discourse/app/assets/javascripts/pretty-text/engines/discourse-markdown/custom-typographer-replacem...

104 lines
2.5 KiB
JavaScript

// Simple typographic replacements
//
// (tm) (TM) → ™
// +- → ±
// ... → … (also ?.... → ?.., !.... → !..)
// ???????? → ???, !!!!! → !!!, `,,` → `,`
// -- → –, --- → —
// --> <-- -> <- to → ← → ←
// (pa) (PA) → ¶
//
// Disabled replacements:
//
// (c) (C) → ©
// (r) (R) → ®
// (p) (P) -> §
let RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--|-->|<--|->|<-/;
let SCOPED_ABBR_RE = /\((tm|pa)\)/gi;
let SCOPED_ABBR = {
pa: "¶",
tm: "™",
};
function replaceFn(match, name) {
return SCOPED_ABBR[name.toLowerCase()];
}
function replaceScoped(inlineTokens) {
let i, token;
for (i = inlineTokens.length - 1; i >= 0; i--) {
token = inlineTokens[i];
if (token.type === "text") {
token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn);
}
}
}
function replaceRare(inlineTokens) {
let i,
token,
inside_autolink = 0;
for (i = inlineTokens.length - 1; i >= 0; i--) {
token = inlineTokens[i];
if (token.type === "text" && !inside_autolink) {
if (RARE_RE.test(token.content)) {
token.content = token.content
.replace(/\+-/g, "±")
// Custom arrows
.replace(/(^|\s)-{1,2}>(\s|$)/gm, "\u0020\u2192\u0020")
.replace(/(^|\s)<-{1,2}(\s|$)/gm, "\u0020\u2190\u0020")
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
.replace(/\.{2,}/g, "…")
.replace(/([?!])…/g, "$1..")
.replace(/([?!]){4,}/g, "$1$1$1")
.replace(/,{2,}/g, ",")
// em-dash
.replace(/(^|[^-])---(?=[^-]|$)/gm, "$1\u2014")
// en-dash
.replace(/(^|\s)--(?=\s|$)/gm, "$1\u2013")
.replace(/(^|[^-\s])--(?=[^-\s]|$)/gm, "$1\u2013");
}
}
if (token.type === "link_open" && token.info === "auto") {
inside_autolink--;
}
if (token.type === "link_close" && token.info === "auto") {
inside_autolink++;
}
}
}
function replace(state) {
let blkIdx;
for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
if (state.tokens[blkIdx].type !== "inline") {
continue;
}
if (SCOPED_ABBR_RE.test(state.tokens[blkIdx].content)) {
replaceScoped(state.tokens[blkIdx].children);
}
if (RARE_RE.test(state.tokens[blkIdx].content)) {
replaceRare(state.tokens[blkIdx].children);
}
}
}
export function setup(helper) {
helper.registerPlugin((md) => {
if (md.options.typographer) {
md.core.ruler.at("replacements", replace);
}
});
}