Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(frontend): replace markdown with html when update ES (#179)
- Loading branch information
Showing
6 changed files
with
456 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
const conventionMatchers = [ | ||
"convention collective", | ||
"conventions collectives", | ||
"accords de branches", | ||
"accord de branche", | ||
"disposition conventionnelle", | ||
"dispositions conventionnelles", | ||
]; | ||
|
||
// we cannot use \b word boundary since \w does not match diacritics | ||
// So we do a kind of \b equivalent. | ||
// the main différence is that matched pattern can include a whitespace as first char | ||
const frDiacritics = "àâäçéèêëïîôöùûüÿœæÀÂÄÇÉÈÊËÎÏÔÖÙÛÜŸŒÆ"; | ||
const wordBoundaryStart = `(?:^|[^_/\\w${frDiacritics}-])`; | ||
const wordBoundaryEnd = `(?![\\w${frDiacritics}])`; | ||
|
||
const startTag = `(?<=>[^><]*)`; | ||
const endTag = `(?=[^<]*</)`; | ||
|
||
export function addGlossary(entries, htmlContent) { | ||
if (!htmlContent) return ""; | ||
|
||
let idHtmlContent = htmlContent; | ||
|
||
let glossary = []; | ||
entries.forEach(({ abbrs, definition, title, variants }) => { | ||
glossary = glossary.concat( | ||
[title, ...variants].map((term) => ({ | ||
definition, | ||
pattern: new RegExp( | ||
`${startTag}${wordBoundaryStart}(${term})${wordBoundaryEnd}${endTag}`, | ||
"gi" | ||
), | ||
term, | ||
})) | ||
); | ||
if (abbrs) { | ||
glossary.push({ | ||
definition, | ||
pattern: new RegExp(`${startTag}\\b(${abbrs})\\b${endTag}`, "g"), | ||
term: abbrs, | ||
}); | ||
} | ||
}); | ||
|
||
// we make sure that bigger terms are replaced first | ||
glossary.sort((previous, next) => { | ||
return next.term.length - previous.term.length; | ||
}); | ||
|
||
// we also sure that cc matchers are replaced first | ||
conventionMatchers.forEach((matcher) => { | ||
glossary.unshift({ | ||
definition: false, | ||
pattern: new RegExp(`${startTag}(${matcher})${endTag}`, "gi"), | ||
term: matcher, | ||
}); | ||
}); | ||
|
||
const idToWebComponent = new Map(); | ||
|
||
glossary.forEach(({ definition, pattern, term }, index) => { | ||
// while we loop, we replace the matches with an id to prevent nested matches | ||
idHtmlContent = idHtmlContent.replace(pattern, function ( | ||
match // contains the matching term with the word boundaries | ||
) { | ||
const id = "__tt__" + index; | ||
const webComponent = definition | ||
? `<webcomponent-tooltip content="${encodeURIComponent( | ||
definition.replace(/'/g, "’").replace("<p>", "").replace("</p>", "") | ||
)}">${term}</webcomponent-tooltip>` | ||
: `<webcomponent-tooltip-cc>${term}</webcomponent-tooltip-cc>`; | ||
idToWebComponent.set(id, webComponent); | ||
return match.replace(new RegExp(term), id); | ||
}); | ||
}); | ||
|
||
// In the end, we replace the id with its related component | ||
let finalContent = idHtmlContent; | ||
idToWebComponent.forEach((webComponent, id) => { | ||
// make sure we don't match larger numbers | ||
finalContent = finalContent.replace( | ||
new RegExp(`${id}([^1-9])`, "g"), | ||
`${webComponent}$1` | ||
); | ||
}); | ||
|
||
return finalContent; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import htmlAstToAnotherHtmlAst from "rehype-raw"; | ||
import htmlAstStringify from "rehype-stringify"; | ||
import markdownToMardownAst from "remark-parse"; | ||
import markdownAstToHtmlAst from "remark-rehype"; | ||
import markdownAstStringify from "remark-stringify"; | ||
import markdownAstStrip from "strip-markdown"; | ||
import unified from "unified"; | ||
|
||
import { addGlossary } from "./glossary"; | ||
|
||
const textProcessor = unified() | ||
.use(markdownToMardownAst) | ||
.use(markdownAstStrip) | ||
.use(markdownAstStringify); | ||
|
||
const htmlProcessor = unified() | ||
.use(markdownToMardownAst) | ||
.use(markdownAstToHtmlAst, { allowDangerousHtml: true }) | ||
.use(htmlAstToAnotherHtmlAst) | ||
.use(htmlAstStringify); | ||
|
||
export function markdownTransform(glossary, document) { | ||
document.intro = addGlossary( | ||
glossary, | ||
htmlProcessor.processSync(document.intro).contents | ||
); | ||
|
||
document.contents.forEach((content) => { | ||
content.html = addGlossary( | ||
glossary, | ||
htmlProcessor.processSync(content.markdown).contents | ||
); | ||
delete content.markdown; | ||
}); | ||
|
||
document.text = | ||
textProcessor.processSync(document.intro) + | ||
document.contents | ||
.map(({ markdown }) => | ||
textProcessor.processSync(markdown).contents.replace(/\s\s+/g, " ") | ||
) | ||
.join(""); | ||
|
||
return document; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.