62 lines
2.1 KiB
JavaScript
62 lines
2.1 KiB
JavaScript
import { retext } from "retext";
|
|
import { visit } from "unist-util-visit";
|
|
import smartypants from "retext-smartypants";
|
|
const VISITED_NODES = new Set(["text", "inlineCode"]);
|
|
const IGNORED_HTML_ELEMENTS = new Set(["style", "script"]);
|
|
const check = (node, index, parent) => {
|
|
return (parent &&
|
|
(parent.type !== "mdxJsxTextElement" ||
|
|
("name" in parent &&
|
|
typeof parent.name === "string" &&
|
|
!IGNORED_HTML_ELEMENTS.has(parent.name))) &&
|
|
VISITED_NODES.has(node.type) &&
|
|
isLiteral(node));
|
|
};
|
|
/**
|
|
* remark plugin to implement SmartyPants.
|
|
*/
|
|
const remarkSmartypants = (options) => {
|
|
const processor = retext().use(smartypants, {
|
|
...options,
|
|
// Do not replace ellipses, dashes, backticks because they change string
|
|
// length, and we couldn't guarantee right splice of text in second visit of
|
|
// tree
|
|
ellipses: false,
|
|
dashes: false,
|
|
backticks: false,
|
|
});
|
|
const processor2 = retext().use(smartypants, {
|
|
...options,
|
|
// Do not replace quotes because they are already replaced in the first
|
|
// processor
|
|
quotes: false,
|
|
});
|
|
return (tree) => {
|
|
let allText = "";
|
|
let startIndex = 0;
|
|
const nodes = [];
|
|
visit(tree, check, (node) => {
|
|
if (!isLiteral(node))
|
|
return;
|
|
allText +=
|
|
node.type === "text" ? node.value : "A".repeat(node.value.length);
|
|
nodes.push(node);
|
|
});
|
|
// Concat all text into one string, to properly replace quotes around links
|
|
// and bold text
|
|
allText = processor.processSync(allText).toString();
|
|
for (const node of nodes) {
|
|
const endIndex = startIndex + node.value.length;
|
|
if (node.type === "text") {
|
|
const processedText = allText.slice(startIndex, endIndex);
|
|
node.value = processor2.processSync(processedText).toString();
|
|
}
|
|
startIndex = endIndex;
|
|
}
|
|
};
|
|
};
|
|
function isLiteral(node) {
|
|
return "value" in node && typeof node.value === "string";
|
|
}
|
|
export default remarkSmartypants;
|