@intlayer/core 9.4.1 → 9.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/index.cjs +8 -4
- package/dist/cjs/localization/getCanonicalPath.cjs +52 -0
- package/dist/cjs/localization/getCanonicalPath.cjs.map +1 -0
- package/dist/cjs/localization/getCanonicalPath.test-d.cjs +12 -0
- package/dist/cjs/localization/getCanonicalPath.test-d.cjs.map +1 -0
- package/dist/cjs/localization/getLocalizedPath.cjs +4 -2
- package/dist/cjs/localization/getLocalizedPath.cjs.map +1 -1
- package/dist/cjs/localization/index.cjs +4 -2
- package/dist/cjs/localization/rewriteMatch.cjs +52 -0
- package/dist/cjs/localization/rewriteMatch.cjs.map +1 -0
- package/dist/cjs/localization/rewriteUtils.cjs +6 -68
- package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
- package/dist/cjs/localization/rewriteUtils.test-d.cjs +0 -5
- package/dist/cjs/localization/rewriteUtils.test-d.cjs.map +1 -1
- package/dist/cjs/markdown/compiler.cjs +100 -75
- package/dist/cjs/markdown/compiler.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs +14 -5
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/markdown/index.cjs +4 -2
- package/dist/cjs/markdown/parser.cjs +70 -44
- package/dist/cjs/markdown/parser.cjs.map +1 -1
- package/dist/cjs/markdown/renderer.cjs +7 -19
- package/dist/cjs/markdown/renderer.cjs.map +1 -1
- package/dist/cjs/markdown/utils.cjs +33 -37
- package/dist/cjs/markdown/utils.cjs.map +1 -1
- package/dist/esm/index.mjs +5 -3
- package/dist/esm/localization/getCanonicalPath.mjs +51 -0
- package/dist/esm/localization/getCanonicalPath.mjs.map +1 -0
- package/dist/esm/localization/getCanonicalPath.test-d.mjs +12 -0
- package/dist/esm/localization/getCanonicalPath.test-d.mjs.map +1 -0
- package/dist/esm/localization/getLocalizedPath.mjs +3 -1
- package/dist/esm/localization/getLocalizedPath.mjs.map +1 -1
- package/dist/esm/localization/index.mjs +3 -1
- package/dist/esm/localization/rewriteMatch.mjs +49 -0
- package/dist/esm/localization/rewriteMatch.mjs.map +1 -0
- package/dist/esm/localization/rewriteUtils.mjs +3 -63
- package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
- package/dist/esm/localization/rewriteUtils.test-d.mjs +1 -6
- package/dist/esm/localization/rewriteUtils.test-d.mjs.map +1 -1
- package/dist/esm/markdown/compiler.mjs +101 -55
- package/dist/esm/markdown/compiler.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +11 -4
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/markdown/index.mjs +2 -2
- package/dist/esm/markdown/parser.mjs +70 -44
- package/dist/esm/markdown/parser.mjs.map +1 -1
- package/dist/esm/markdown/renderer.mjs +7 -19
- package/dist/esm/markdown/renderer.mjs.map +1 -1
- package/dist/esm/markdown/utils.mjs +34 -38
- package/dist/esm/markdown/utils.mjs.map +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/localization/getCanonicalPath.d.ts +19 -0
- package/dist/types/localization/getCanonicalPath.d.ts.map +1 -0
- package/dist/types/localization/getCanonicalPath.test-d.d.ts +1 -0
- package/dist/types/localization/getLocalizedPath.d.ts.map +1 -1
- package/dist/types/localization/index.d.ts +3 -1
- package/dist/types/localization/rewriteMatch.d.ts +20 -0
- package/dist/types/localization/rewriteMatch.d.ts.map +1 -0
- package/dist/types/localization/rewriteUtils.d.ts +2 -14
- package/dist/types/localization/rewriteUtils.d.ts.map +1 -1
- package/dist/types/markdown/compiler.d.ts.map +1 -1
- package/dist/types/markdown/constants.d.ts +11 -4
- package/dist/types/markdown/constants.d.ts.map +1 -1
- package/dist/types/markdown/index.d.ts +2 -2
- package/dist/types/markdown/parser.d.ts.map +1 -1
- package/dist/types/markdown/renderer.d.ts.map +1 -1
- package/dist/types/markdown/types.d.ts +8 -2
- package/dist/types/markdown/types.d.ts.map +1 -1
- package/dist/types/markdown/utils.d.ts +0 -4
- package/dist/types/markdown/utils.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.mjs","names":[],"sources":["../../../src/markdown/parser.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"parser.mjs","names":[],"sources":["../../../src/markdown/parser.ts"],"sourcesContent":["import type {\n NestedParser,\n ParserResult,\n ParseState,\n Rule,\n Rules,\n} from './types';\nimport { normalizeWhitespace, qualifies } from './utils';\n\n/**\n * Cached rule precedence, grouped by rule count.\n *\n * A rule's `_order` never varies, so the precedence a rule set sorts into is a\n * pure function of which rules it holds. Rules themselves are rebuilt per\n * document, so the cache is keyed by rule names rather than by object identity,\n * and grouped by count to keep the comparison short.\n */\ntype RuleOrderEntry = { names: string[]; order: string[] };\n\nconst ruleOrderCache = new Map<number, RuleOrderEntry[]>();\n\nconst sameNames = (a: string[], b: string[]): boolean => {\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n\n return true;\n};\n\n/**\n * Resolves `Object.keys(rules)` into precedence order, sorting only the first\n * time a given rule set is seen.\n */\nconst orderRules = (names: string[], rules: Rules): string[] => {\n const candidates = ruleOrderCache.get(names.length);\n\n if (candidates) {\n for (let i = 0; i < candidates.length; i++) {\n if (sameNames(names, candidates[i]!.names)) return candidates[i]!.order;\n }\n }\n\n // Sorts rules in order of increasing order, then\n // ascending rule name (numeric) in case of ties.\n // RuleType keys are string numbers — use numeric comparison to preserve\n // intended ordering (e.g. codeFenced '4' must precede headingSetext '10').\n const order = names\n .slice()\n .sort((a, b) => rules[a]!._order - rules[b]!._order || +a - +b);\n\n const entry: RuleOrderEntry = { names: names.slice(), order };\n\n if (candidates) candidates.push(entry);\n else ruleOrderCache.set(names.length, [entry]);\n\n return order;\n};\n\n/**\n * Advance the incremental lookbehind carried on the parse state.\n *\n * Rules only ever ask two questions about the source already consumed: how far\n * the current line is indented (`prevCaptureIndent`) and whether a blank line\n * has been seen (`prevCaptureHasBlankLine`). Both are maintained in time\n * proportional to the capture rather than by concatenating — and later\n * rescanning — the whole document, which made parsing quadratic.\n */\nconst advanceLookbehind = (state: ParseState, capture: string): void => {\n const newlineIndex = capture.lastIndexOf('\\n');\n // `undefined` marks a lookbehind nothing has been appended to yet, which is\n // the only way to tell an empty lookbehind from one ending on a line break.\n const hasPrevCapture = state.prevCaptureHasBlankLine !== undefined;\n\n if (state.prevCaptureHasBlankLine !== true) {\n state.prevCaptureHasBlankLine =\n capture.indexOf('\\n\\n') !== -1 ||\n // A capture opening on a line break closes a blank line when the\n // lookbehind already ended on one.\n (hasPrevCapture &&\n capture.charCodeAt(0) === 10 /* \\n */ &&\n state.prevCaptureIndent === '');\n }\n\n // Everything after the final newline forms the current line. With no newline\n // in the capture, the current line simply grew by `capture`.\n const tail =\n newlineIndex === -1\n ? state.prevCaptureIndent === undefined\n ? undefined\n : state.prevCaptureIndent + capture\n : capture.slice(newlineIndex + 1);\n\n if (tail === undefined || tail === '') {\n state.prevCaptureIndent = tail;\n return;\n }\n\n for (let i = 0; i < tail.length; i++) {\n if (tail.charCodeAt(i) !== 32 /* space */) {\n state.prevCaptureIndent = undefined;\n return;\n }\n }\n\n state.prevCaptureIndent = tail;\n};\n\n/**\n * Creates a parser for a given set of rules, with the precedence\n * specified as a list of rules.\n *\n * @param rules - An object containing rule type -> {match, order, parse} objects\n * (lower order is higher precedence)\n *\n * @returns The resulting parse function\n */\nexport const parserFor = (\n rules: Rules\n): ((source: string, state: ParseState) => ParserResult[]) => {\n const ruleList = Object.keys(rules);\n\n if (process.env.NODE_ENV !== 'production') {\n ruleList.forEach((type) => {\n const order = rules[type]?._order;\n if (typeof order !== 'number' || !Number.isFinite(order)) {\n console.warn(`intlayer: Invalid order for rule \\`${type}\\`: ${order}`);\n }\n });\n }\n\n const order = orderRules(ruleList, rules);\n const ruleCount = order.length;\n\n // Rule objects have heterogeneous shapes (`_qualify` and `_render` are both\n // optional), so their members are hoisted into parallel arrays: the hot loop\n // then reads monomorphic slots instead of polymorphic properties, and the\n // whole set costs three allocations rather than one wrapper per rule.\n const qualifiers: (Rule<any>['_qualify'] | undefined)[] = new Array(\n ruleCount\n );\n const matchers: Rule<any>['_match'][] = new Array(ruleCount);\n const parsers: Rule<any>['_parse'][] = new Array(ruleCount);\n\n for (let i = 0; i < ruleCount; i++) {\n const rule = rules[order[i]!]!;\n\n qualifiers[i] = rule._qualify;\n matchers[i] = rule._match;\n parsers[i] = rule._parse;\n }\n\n const nestedParse: NestedParser = (\n source: string,\n state: ParseState = {}\n ): ParserResult[] => {\n const result: ParserResult[] = [];\n\n if (state.prevCaptureHasBlankLine === undefined) {\n // Nothing consumed yet: an empty lookbehind sits at the start of a line.\n state.prevCaptureIndent = '';\n }\n\n if (source.trim()) {\n while (source) {\n for (let i = 0; i < ruleCount; i++) {\n const qualify = qualifiers[i];\n\n if (qualify && !qualifies(source, state, qualify)) continue;\n\n const capture = matchers[i]!(source, state);\n\n if (capture?.[0]) {\n source = source.substring(capture[0].length);\n\n const parsed: any = parsers[i]!(capture, nestedParse, state);\n\n advanceLookbehind(state, capture[0]);\n\n if (!parsed.type) {\n parsed.type = order[i];\n }\n\n result.push(parsed as ParserResult);\n break;\n }\n }\n }\n }\n\n return result;\n };\n\n return (source: string, state: ParseState) =>\n nestedParse(normalizeWhitespace(source), state);\n};\n"],"mappings":"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"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { DURATION_DELAY_TRIGGER } from "./constants.mjs";
|
|
2
|
-
|
|
3
1
|
//#region src/markdown/renderer.ts
|
|
4
2
|
/**
|
|
5
3
|
* Creates a renderer for AST nodes.
|
|
@@ -8,16 +6,15 @@ import { DURATION_DELAY_TRIGGER } from "./constants.mjs";
|
|
|
8
6
|
* @param render - The render function to call for each node
|
|
9
7
|
* @returns A function that renders AST to output
|
|
10
8
|
*/
|
|
11
|
-
const renderFor = (render) =>
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
if (Array.isArray(ast)) {
|
|
9
|
+
const renderFor = (render) => {
|
|
10
|
+
const emit = (ast, state = {}) => {
|
|
11
|
+
if (!Array.isArray(ast)) return render(ast, emit, state);
|
|
15
12
|
const oldKey = state.key;
|
|
16
13
|
const result = [];
|
|
17
14
|
let lastWasString = false;
|
|
18
15
|
let renderedIndex = 0;
|
|
19
16
|
for (let i = 0; i < ast.length; i++) {
|
|
20
|
-
const nodeOut =
|
|
17
|
+
const nodeOut = emit(ast[i], {
|
|
21
18
|
...state,
|
|
22
19
|
key: renderedIndex
|
|
23
20
|
});
|
|
@@ -30,14 +27,9 @@ const renderFor = (render) => (ast, state = {}) => {
|
|
|
30
27
|
lastWasString = isString;
|
|
31
28
|
}
|
|
32
29
|
state.key = oldKey;
|
|
33
|
-
const duration = performance.now() - start;
|
|
34
|
-
if (duration > 20) console.log(`renderFor (array): ${duration.toFixed(3)}ms, ast length: ${ast.length}`);
|
|
35
30
|
return result;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const duration = performance.now() - start;
|
|
39
|
-
if (duration > 20) console.log(`renderFor (single): ${duration.toFixed(3)}ms, ast type: ${ast.type}`);
|
|
40
|
-
return result;
|
|
31
|
+
};
|
|
32
|
+
return emit;
|
|
41
33
|
};
|
|
42
34
|
/**
|
|
43
35
|
* Creates a renderer from rules with optional custom render hook.
|
|
@@ -47,12 +39,8 @@ const renderFor = (render) => (ast, state = {}) => {
|
|
|
47
39
|
* @returns A render function for AST nodes
|
|
48
40
|
*/
|
|
49
41
|
const createRenderer = (rules, userRender) => (ast, render, state) => {
|
|
50
|
-
const start = performance.now();
|
|
51
42
|
const renderer = rules[ast.type]?._render;
|
|
52
|
-
|
|
53
|
-
const duration = performance.now() - start;
|
|
54
|
-
if (duration > 20) console.log(`createRenderer: ${duration.toFixed(3)}ms, ast type: ${ast.type}, hasUserRender: ${!!userRender}`);
|
|
55
|
-
return result;
|
|
43
|
+
return userRender ? userRender(() => renderer?.(ast, render, state), ast, render, state) : renderer?.(ast, render, state);
|
|
56
44
|
};
|
|
57
45
|
|
|
58
46
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.mjs","names":[],"sources":["../../../src/markdown/renderer.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"renderer.mjs","names":[],"sources":["../../../src/markdown/renderer.ts"],"sourcesContent":["import type {\n ParserResult,\n ParseState,\n RenderRuleHook,\n RuleOutput,\n Rules,\n} from './types';\n\n/**\n * Creates a renderer for AST nodes.\n * Renamed from `reactFor` to be framework-agnostic.\n *\n * @param render - The render function to call for each node\n * @returns A function that renders AST to output\n */\nexport const renderFor = (\n render: (ast: ParserResult, render: RuleOutput, state: ParseState) => unknown\n) => {\n // Bound once instead of per node: rebuilding the recursive renderer on every\n // visit allocated a closure pair for each AST node.\n const emit = (\n ast: ParserResult | ParserResult[],\n state: ParseState = {}\n ): any => {\n if (!Array.isArray(ast)) {\n return render(ast, emit as RuleOutput, state);\n }\n\n const oldKey = state.key;\n const result: any[] = [];\n\n // map nestedOutput over the ast, except group any text\n // nodes together into a single string output.\n let lastWasString = false;\n let renderedIndex = 0;\n\n for (let i = 0; i < ast.length; i++) {\n // We clone the state to avoid side effects on other nodes in the same level\n // while ensuring each non-null rendered node gets a unique, sequential key.\n const nodeOut = emit(ast[i], { ...state, key: renderedIndex });\n const isString = typeof nodeOut === 'string';\n\n if (isString && lastWasString) {\n result[result.length - 1] =\n (result[result.length - 1] as string) + nodeOut;\n } else if (nodeOut !== null) {\n result.push(nodeOut);\n renderedIndex++;\n }\n\n lastWasString = isString;\n }\n\n state.key = oldKey;\n\n return result;\n };\n\n return emit;\n};\n\n/**\n * Creates a renderer from rules with optional custom render hook.\n *\n * @param rules - The rules object containing _render functions\n * @param userRender - Optional custom render hook for full control\n * @returns A render function for AST nodes\n */\nexport const createRenderer =\n (rules: Rules, userRender?: RenderRuleHook) =>\n (ast: ParserResult, render: RuleOutput, state: ParseState): unknown => {\n const renderer = rules[ast.type]?._render;\n\n return userRender\n ? userRender(() => renderer?.(ast, render, state), ast, render, state)\n : renderer?.(ast, render, state);\n };\n"],"mappings":";;;;;;;;AAeA,MAAa,aACX,WACG;CAGH,MAAM,QACJ,KACA,QAAoB,CAAC,MACb;EACR,IAAI,CAAC,MAAM,QAAQ,GAAG,GACpB,OAAO,OAAO,KAAK,MAAoB,KAAK;EAG9C,MAAM,SAAS,MAAM;EACrB,MAAM,SAAgB,CAAC;EAIvB,IAAI,gBAAgB;EACpB,IAAI,gBAAgB;EAEpB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;GAGnC,MAAM,UAAU,KAAK,IAAI,IAAI;IAAE,GAAG;IAAO,KAAK;GAAc,CAAC;GAC7D,MAAM,WAAW,OAAO,YAAY;GAEpC,IAAI,YAAY,eACd,OAAO,OAAO,SAAS,KACpB,OAAO,OAAO,SAAS,KAAgB;QACrC,IAAI,YAAY,MAAM;IAC3B,OAAO,KAAK,OAAO;IACnB;GACF;GAEA,gBAAgB;EAClB;EAEA,MAAM,MAAM;EAEZ,OAAO;CACT;CAEA,OAAO;AACT;;;;;;;;AASA,MAAa,kBACV,OAAc,gBACd,KAAmB,QAAoB,UAA+B;CACrE,MAAM,WAAW,MAAM,IAAI,KAAK,EAAE;CAElC,OAAO,aACH,iBAAiB,WAAW,KAAK,QAAQ,KAAK,GAAG,KAAK,QAAQ,KAAK,IACnE,WAAW,KAAK,QAAQ,KAAK;AACnC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ATTRIBUTES_TO_SANITIZE, CAPTURE_LETTER_AFTER_HYPHEN,
|
|
1
|
+
import { ATTRIBUTES_TO_SANITIZE, CAPTURE_LETTER_AFTER_HYPHEN, FENCE_DELIMITER_R, HTML_CUSTOM_ATTR_R, INTERPOLATION_R, NORMALIZE_WHITESPACE_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, UNESCAPE_R } from "./constants.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/markdown/utils.ts
|
|
4
4
|
/**
|
|
@@ -48,15 +48,37 @@ const get = (src, path, fb) => {
|
|
|
48
48
|
* Convert a string to a URL-safe slug.
|
|
49
49
|
* Based on https://stackoverflow.com/a/18123682/1141611
|
|
50
50
|
*/
|
|
51
|
-
const
|
|
51
|
+
const SLUGIFY_REPLACEMENTS = [
|
|
52
|
+
[/[ÀÁÂÃÄÅàáâãä忯]/g, "a"],
|
|
53
|
+
[/[çÇ]/g, "c"],
|
|
54
|
+
[/[ðÐ]/g, "d"],
|
|
55
|
+
[/[ÈÉÊËéèêë]/g, "e"],
|
|
56
|
+
[/[ÏïÎîÍíÌì]/g, "i"],
|
|
57
|
+
[/[Ññ]/g, "n"],
|
|
58
|
+
[/[øØœŒÕõÔôÓóÒò]/g, "o"],
|
|
59
|
+
[/[ÜüÛûÚúÙù]/g, "u"],
|
|
60
|
+
[/[ŸÿÝý]/g, "y"],
|
|
61
|
+
[/[^a-z0-9- ]/gi, ""],
|
|
62
|
+
[/ /gi, "-"]
|
|
63
|
+
];
|
|
64
|
+
const slugify = (str) => {
|
|
65
|
+
let result = str;
|
|
66
|
+
for (let i = 0; i < SLUGIFY_REPLACEMENTS.length; i++) {
|
|
67
|
+
const [pattern, replacement] = SLUGIFY_REPLACEMENTS[i];
|
|
68
|
+
result = result.replace(pattern, replacement);
|
|
69
|
+
}
|
|
70
|
+
return result.toLowerCase();
|
|
71
|
+
};
|
|
52
72
|
const SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;
|
|
73
|
+
const SANITIZE_STRIP_R = /[^A-Za-z0-9/:]/g;
|
|
53
74
|
/**
|
|
54
75
|
* Sanitize URLs to prevent XSS attacks.
|
|
55
76
|
* Returns null if the URL is unsafe.
|
|
56
77
|
*/
|
|
57
78
|
const sanitizer = (input) => {
|
|
79
|
+
if (input.indexOf(":") === -1 && input.indexOf("%") === -1) return input;
|
|
58
80
|
try {
|
|
59
|
-
const decoded = decodeURIComponent(input).replace(
|
|
81
|
+
const decoded = decodeURIComponent(input).replace(SANITIZE_STRIP_R, "");
|
|
60
82
|
if (SANITIZE_R.test(decoded)) {
|
|
61
83
|
console.warn("Input contains an unsafe JavaScript/VBScript/data expression, it will not be rendered.", decoded);
|
|
62
84
|
return null;
|
|
@@ -70,13 +92,11 @@ const sanitizer = (input) => {
|
|
|
70
92
|
/**
|
|
71
93
|
* Normalize whitespace in source string.
|
|
72
94
|
*/
|
|
73
|
-
const normalizeWhitespace = (source) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return result;
|
|
79
|
-
};
|
|
95
|
+
const normalizeWhitespace = (source) => source.replace(NORMALIZE_WHITESPACE_R, (match) => {
|
|
96
|
+
if (match === " ") return " ";
|
|
97
|
+
if (match === "\f") return "";
|
|
98
|
+
return "\n";
|
|
99
|
+
});
|
|
80
100
|
/**
|
|
81
101
|
* Safely remove a uniform leading indentation from lines, but do NOT touch
|
|
82
102
|
* the content inside fenced code blocks (``` or ~~~).
|
|
@@ -88,13 +108,12 @@ const normalizeWhitespace = (source) => {
|
|
|
88
108
|
* verbatim, instead of losing the first level of indentation.
|
|
89
109
|
*/
|
|
90
110
|
const trimLeadingWhitespaceOutsideFences = (text, whitespace) => {
|
|
91
|
-
const start = performance.now();
|
|
92
111
|
if (!whitespace) return text;
|
|
93
112
|
const lines = text.split("\n");
|
|
94
113
|
/** Indentation and marker of the fence currently open, if any. */
|
|
95
114
|
let openFence = null;
|
|
96
115
|
const removePrefix = (line, prefix) => prefix && line.startsWith(prefix) ? line.slice(prefix.length) : line;
|
|
97
|
-
|
|
116
|
+
return lines.map((line) => {
|
|
98
117
|
const fenceMatch = line.match(FENCE_DELIMITER_R);
|
|
99
118
|
if (!openFence) {
|
|
100
119
|
if (fenceMatch) openFence = {
|
|
@@ -103,14 +122,11 @@ const trimLeadingWhitespaceOutsideFences = (text, whitespace) => {
|
|
|
103
122
|
};
|
|
104
123
|
return removePrefix(line, whitespace);
|
|
105
124
|
}
|
|
106
|
-
const isClosingFence = fenceMatch?.[2]
|
|
125
|
+
const isClosingFence = fenceMatch?.[2]?.startsWith(openFence.marker);
|
|
107
126
|
const { indentation } = openFence;
|
|
108
127
|
if (isClosingFence) openFence = null;
|
|
109
128
|
return removePrefix(line, indentation);
|
|
110
129
|
}).join("\n");
|
|
111
|
-
const duration = performance.now() - start;
|
|
112
|
-
if (duration > 20) console.log(`trimLeadingWhitespaceOutsideFences: ${duration.toFixed(3)}ms, text length: ${text.length}, lines count: ${lines.length}`);
|
|
113
|
-
return result;
|
|
114
130
|
};
|
|
115
131
|
/**
|
|
116
132
|
* Normalize HTML attribute key to JSX prop name.
|
|
@@ -125,7 +141,6 @@ const normalizeAttributeKey = (key) => {
|
|
|
125
141
|
* Parse a CSS style string into an array of [key, value] tuples.
|
|
126
142
|
*/
|
|
127
143
|
const parseStyleAttribute = (styleString) => {
|
|
128
|
-
const start = performance.now();
|
|
129
144
|
const styles = [];
|
|
130
145
|
let buffer = "";
|
|
131
146
|
let inUrl = false;
|
|
@@ -167,8 +182,6 @@ const parseStyleAttribute = (styleString) => {
|
|
|
167
182
|
styles.push([key, value]);
|
|
168
183
|
}
|
|
169
184
|
}
|
|
170
|
-
const duration = performance.now() - start;
|
|
171
|
-
if (duration > 20) console.log(`parseStyleAttribute: ${duration.toFixed(3)}ms, styleString length: ${styleString.length}, styles count: ${styles.length}`);
|
|
172
185
|
return styles;
|
|
173
186
|
};
|
|
174
187
|
/**
|
|
@@ -205,7 +218,6 @@ const parseTableAlign = (source) => {
|
|
|
205
218
|
* Parse a single table row.
|
|
206
219
|
*/
|
|
207
220
|
const parseTableRow = (source, parse, state, tableOutput) => {
|
|
208
|
-
const start = performance.now();
|
|
209
221
|
const prevInTable = state.inTable;
|
|
210
222
|
state.inTable = true;
|
|
211
223
|
const cells = [[]];
|
|
@@ -228,20 +240,13 @@ const parseTableRow = (source, parse, state, tableOutput) => {
|
|
|
228
240
|
});
|
|
229
241
|
flush();
|
|
230
242
|
state.inTable = prevInTable;
|
|
231
|
-
const duration = performance.now() - start;
|
|
232
|
-
if (duration > 20) console.log(`parseTableRow: ${duration.toFixed(3)}ms, source length: ${source.length}, cells count: ${cells.length}`);
|
|
233
243
|
return cells;
|
|
234
244
|
};
|
|
235
245
|
/**
|
|
236
246
|
* Parse table cells (multiple rows).
|
|
237
247
|
*/
|
|
238
248
|
const parseTableCells = (source, parse, state) => {
|
|
239
|
-
|
|
240
|
-
const rowsText = source.trim().split("\n");
|
|
241
|
-
const result = rowsText.map((rowText) => parseTableRow(rowText, parse, state, true));
|
|
242
|
-
const duration = performance.now() - start;
|
|
243
|
-
if (duration > 20) console.log(`parseTableCells: ${duration.toFixed(3)}ms, source length: ${source.length}, rows count: ${rowsText.length}`);
|
|
244
|
-
return result;
|
|
249
|
+
return source.trim().split("\n").map((rowText) => parseTableRow(rowText, parse, state, true));
|
|
245
250
|
};
|
|
246
251
|
/**
|
|
247
252
|
* Check if a rule qualifies for the current source and state.
|
|
@@ -292,7 +297,6 @@ const anyScopeRegex = (fn) => allowInline((source, state) => {
|
|
|
292
297
|
* Parse inline content (including links).
|
|
293
298
|
*/
|
|
294
299
|
const parseInline = (parse, children, state) => {
|
|
295
|
-
const start = performance.now();
|
|
296
300
|
const isCurrentlyInline = state.inline ?? false;
|
|
297
301
|
const isCurrentlySimple = state.simple ?? false;
|
|
298
302
|
state.inline = true;
|
|
@@ -300,15 +304,12 @@ const parseInline = (parse, children, state) => {
|
|
|
300
304
|
const result = parse(children, state);
|
|
301
305
|
state.inline = isCurrentlyInline;
|
|
302
306
|
state.simple = isCurrentlySimple;
|
|
303
|
-
const duration = performance.now() - start;
|
|
304
|
-
if (duration > 20) console.log(`parseInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`);
|
|
305
307
|
return result;
|
|
306
308
|
};
|
|
307
309
|
/**
|
|
308
310
|
* Parse simple inline content (no links).
|
|
309
311
|
*/
|
|
310
312
|
const parseSimpleInline = (parse, children, state) => {
|
|
311
|
-
const start = performance.now();
|
|
312
313
|
const isCurrentlyInline = state.inline ?? false;
|
|
313
314
|
const isCurrentlySimple = state.simple ?? false;
|
|
314
315
|
state.inline = false;
|
|
@@ -316,29 +317,24 @@ const parseSimpleInline = (parse, children, state) => {
|
|
|
316
317
|
const result = parse(children, state);
|
|
317
318
|
state.inline = isCurrentlyInline;
|
|
318
319
|
state.simple = isCurrentlySimple;
|
|
319
|
-
const duration = performance.now() - start;
|
|
320
|
-
if (duration > 20) console.log(`parseSimpleInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`);
|
|
321
320
|
return result;
|
|
322
321
|
};
|
|
323
322
|
/**
|
|
324
323
|
* Parse block content.
|
|
325
324
|
*/
|
|
326
325
|
const parseBlock = (parse, children, state = {}) => {
|
|
327
|
-
const start = performance.now();
|
|
328
326
|
const isCurrentlyInline = state.inline || false;
|
|
329
327
|
state.inline = false;
|
|
330
328
|
const normalizedChildren = trimEnd(children);
|
|
331
329
|
const result = parse(/\n\n$/.test(normalizedChildren) === false ? normalizedChildren.endsWith("\n") ? `${normalizedChildren}\n` : `${normalizedChildren}\n\n` : normalizedChildren, state);
|
|
332
330
|
state.inline = isCurrentlyInline;
|
|
333
|
-
const duration = performance.now() - start;
|
|
334
|
-
if (duration > 20) console.log(`parseBlock: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`);
|
|
335
331
|
return result;
|
|
336
332
|
};
|
|
337
333
|
/**
|
|
338
334
|
* Helper to parse capture group 2 as inline content.
|
|
339
335
|
*/
|
|
340
336
|
const parseCaptureInline = (capture, parse, state) => {
|
|
341
|
-
return { children: parseInline(parse, capture[2], state) };
|
|
337
|
+
return { children: parseInline(parse, capture[2] ?? "", state) };
|
|
342
338
|
};
|
|
343
339
|
/**
|
|
344
340
|
* Helper that captures nothing (empty object).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/markdown/utils.ts"],"sourcesContent":["import {\n ATTRIBUTES_TO_SANITIZE,\n CAPTURE_LETTER_AFTER_HYPHEN,\n CR_NEWLINE_R,\n DURATION_DELAY_TRIGGER,\n FENCE_DELIMITER_R,\n FORMFEED_R,\n HTML_CUSTOM_ATTR_R,\n INTERPOLATION_R,\n TAB_R,\n TABLE_CENTER_ALIGN,\n TABLE_LEFT_ALIGN,\n TABLE_RIGHT_ALIGN,\n TABLE_TRIM_PIPES,\n UNESCAPE_R,\n} from './constants';\nimport type { NestedParser, ParserResult, ParseState, Rule } from './types';\n\n// ============================================================================\n// STRING UTILITIES\n// ============================================================================\n\n/**\n * Trim trailing whitespace from a string.\n */\nexport const trimEnd = (str: string): string => {\n let end = str.length;\n\n while (end > 0 && str[end - 1] <= ' ') end--;\n\n return str.slice(0, end);\n};\n\n/**\n * Check if string starts with prefix.\n */\nexport const startsWith = (str: string, prefix: string): boolean => {\n return str.startsWith(prefix);\n};\n\n/**\n * Remove symmetrical leading and trailing quotes.\n */\nexport const unquote = (str: string): string => {\n const first = str[0];\n\n if (\n (first === '\"' || first === \"'\") &&\n str.length >= 2 &&\n str[str.length - 1] === first\n ) {\n return str.slice(1, -1);\n }\n\n return str;\n};\n\n/**\n * Unescape backslash-escaped characters.\n */\nexport const unescapeString = (rawString: string): string =>\n rawString ? rawString.replace(UNESCAPE_R, '$1') : rawString;\n\n/**\n * Join class names, filtering out falsy values.\n */\nexport const cx = (...args: any[]): string => args.filter(Boolean).join(' ');\n\n/**\n * Get a nested property from an object using dot notation.\n */\nexport const get = (src: any, path: string, fb?: any): any => {\n let ptr = src;\n const frags = path.split('.');\n\n while (frags.length) {\n ptr = ptr[frags[0]];\n\n if (ptr === undefined) break;\n else frags.shift();\n }\n\n return ptr ?? fb;\n};\n\n// ============================================================================\n// SLUGIFY\n// ============================================================================\n\n/**\n * Convert a string to a URL-safe slug.\n * Based on https://stackoverflow.com/a/18123682/1141611\n */\nexport const slugify = (str: string): string =>\n str\n .replace(/[ÀÁÂÃÄÅàáâãä忯]/g, 'a')\n .replace(/[çÇ]/g, 'c')\n .replace(/[ðÐ]/g, 'd')\n .replace(/[ÈÉÊËéèêë]/g, 'e')\n .replace(/[ÏïÎîÍíÌì]/g, 'i')\n .replace(/[Ññ]/g, 'n')\n .replace(/[øØœŒÕõÔôÓóÒò]/g, 'o')\n .replace(/[ÜüÛûÚúÙù]/g, 'u')\n .replace(/[ŸÿÝý]/g, 'y')\n .replace(/[^a-z0-9- ]/gi, '')\n .replace(/ /gi, '-')\n .toLowerCase();\n\n// ============================================================================\n// SANITIZER\n// ============================================================================\n\nconst SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;\n\n/**\n * Sanitize URLs to prevent XSS attacks.\n * Returns null if the URL is unsafe.\n */\nexport const sanitizer = (input: string): string | null => {\n try {\n const decoded = decodeURIComponent(input).replace(/[^A-Za-z0-9/:]/g, '');\n\n if (SANITIZE_R.test(decoded)) {\n console.warn(\n 'Input contains an unsafe JavaScript/VBScript/data expression, it will not be rendered.',\n decoded\n );\n\n return null;\n }\n } catch (_e) {\n console.warn(\n 'Input could not be decoded due to malformed syntax or characters, it will not be rendered.',\n input\n );\n\n // decodeURIComponent sometimes throws a URIError\n return null;\n }\n\n return input;\n};\n\n// ============================================================================\n// WHITESPACE NORMALIZATION\n// ============================================================================\n\n/**\n * Normalize whitespace in source string.\n */\nexport const normalizeWhitespace = (source: string): string => {\n const start = performance.now();\n const result = source\n .replace(CR_NEWLINE_R, '\\n')\n .replace(FORMFEED_R, '')\n .replace(TAB_R, ' ');\n\n const duration = performance.now() - start;\n\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `normalizeWhitespace: ${duration.toFixed(3)}ms, source length: ${source.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Safely remove a uniform leading indentation from lines, but do NOT touch\n * the content inside fenced code blocks (``` or ~~~).\n *\n * Inside a fenced block the structural indentation is irrelevant: what matters\n * is the indentation of the opening fence itself, which is the only amount\n * CommonMark strips from the code lines. A block nested in an indented HTML\n * element but written with its fence at column 0 therefore keeps its code\n * verbatim, instead of losing the first level of indentation.\n */\nexport const trimLeadingWhitespaceOutsideFences = (\n text: string,\n whitespace: string\n): string => {\n const start = performance.now();\n if (!whitespace) return text;\n\n const lines = text.split('\\n');\n\n /** Indentation and marker of the fence currently open, if any. */\n let openFence: { indentation: string; marker: string } | null = null;\n\n const removePrefix = (line: string, prefix: string): string =>\n prefix && line.startsWith(prefix) ? line.slice(prefix.length) : line;\n\n // Outside fences, strip the base structural indentation from every line.\n // Lines that don't start with the whitespace prefix are left as-is.\n const result = lines\n .map((line) => {\n const fenceMatch = line.match(FENCE_DELIMITER_R);\n\n if (!openFence) {\n if (fenceMatch)\n openFence = { indentation: fenceMatch[1], marker: fenceMatch[2] };\n return removePrefix(line, whitespace);\n }\n\n const isClosingFence = fenceMatch?.[2].startsWith(openFence.marker);\n const { indentation } = openFence;\n\n if (isClosingFence) openFence = null;\n\n return removePrefix(line, indentation);\n })\n .join('\\n');\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `trimLeadingWhitespaceOutsideFences: ${duration.toFixed(3)}ms, text length: ${text.length}, lines count: ${lines.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Normalize HTML attribute key to JSX prop name.\n */\nexport const normalizeAttributeKey = (key: string): string => {\n const hyphenIndex = key.indexOf('-');\n\n if (hyphenIndex !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) {\n key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, (_, letter) => {\n return letter.toUpperCase();\n });\n }\n\n return key;\n};\n\ntype StyleTuple = [key: string, value: string];\n\n/**\n * Parse a CSS style string into an array of [key, value] tuples.\n */\nexport const parseStyleAttribute = (styleString: string): StyleTuple[] => {\n const start = performance.now();\n const styles: StyleTuple[] = [];\n let buffer = '';\n let inUrl = false;\n let inQuotes = false;\n let quoteChar: '\"' | \"'\" | '' = '';\n\n if (!styleString) return styles;\n\n for (let i = 0; i < styleString.length; i++) {\n const char = styleString[i];\n\n if ((char === '\"' || char === \"'\") && !inUrl) {\n if (!inQuotes) {\n inQuotes = true;\n quoteChar = char;\n } else if (char === quoteChar) {\n inQuotes = false;\n quoteChar = '';\n }\n }\n\n if (char === '(' && buffer.endsWith('url')) {\n inUrl = true;\n } else if (char === ')' && inUrl) {\n inUrl = false;\n }\n\n if (char === ';' && !inQuotes && !inUrl) {\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n buffer = '';\n } else {\n buffer += char;\n }\n }\n\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n\n const duration = performance.now() - start;\n\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseStyleAttribute: ${duration.toFixed(3)}ms, styleString length: ${styleString.length}, styles count: ${styles.length}`\n );\n }\n\n return styles;\n};\n\n/**\n * Convert an attribute value to a Node prop value.\n */\nexport const attributeValueToNodePropValue = (\n tag: string,\n key: string,\n value: string,\n sanitizeUrlFn: (\n value: string,\n tag: string,\n attribute: string\n ) => string | null\n): any => {\n if (key === 'style') {\n return parseStyleAttribute(value).reduce(\n (styles, [styleKey, styleValue]) => {\n const camelCasedKey = styleKey.replace(/(-[a-z])/g, (substr) =>\n substr[1].toUpperCase()\n );\n\n (styles as Record<string, any>)[camelCasedKey] = sanitizeUrlFn(\n styleValue,\n tag,\n styleKey\n );\n\n return styles;\n },\n {} as Record<string, any>\n );\n } else if (ATTRIBUTES_TO_SANITIZE.indexOf(key) !== -1) {\n return sanitizeUrlFn(unescapeString(value), tag, key);\n } else if (value.match(INTERPOLATION_R)) {\n value = unescapeString(value.slice(1, value.length - 1));\n }\n\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n }\n\n return value;\n};\n\n// ============================================================================\n// TABLE PARSING\n// ============================================================================\n\n/**\n * Parse table alignment from a separator row.\n */\nexport const parseTableAlignCapture = (\n alignCapture: string\n): 'left' | 'right' | 'center' => {\n if (TABLE_RIGHT_ALIGN.test(alignCapture)) {\n return 'right';\n } else if (TABLE_CENTER_ALIGN.test(alignCapture)) {\n return 'center';\n } else if (TABLE_LEFT_ALIGN.test(alignCapture)) {\n return 'left';\n }\n\n return 'left';\n};\n\n/**\n * Parse table alignment row.\n */\nexport const parseTableAlign = (\n source: string\n): ('left' | 'right' | 'center')[] => {\n const alignText = source.replace(TABLE_TRIM_PIPES, '').split('|');\n return alignText.map(parseTableAlignCapture);\n};\n\n/**\n * Parse a single table row.\n */\nexport const parseTableRow = (\n source: string,\n parse: NestedParser,\n state: ParseState,\n tableOutput: boolean\n): ParserResult[][] => {\n const start = performance.now();\n const prevInTable = state.inTable;\n\n state.inTable = true;\n\n const cells: ParserResult[][] = [[]];\n let acc = '';\n\n const flush = (): void => {\n if (!acc) return;\n\n const cell = cells[cells.length - 1];\n cell.push.apply(cell, parse(acc, state));\n acc = '';\n };\n\n source\n .trim()\n .split(/(`[^`]*`|\\\\\\||\\|)/)\n .filter(Boolean)\n .forEach((fragment, i, arr) => {\n if (fragment.trim() === '|') {\n flush();\n\n if (tableOutput) {\n if (i !== 0 && i !== arr.length - 1) {\n cells.push([]);\n }\n\n return;\n }\n }\n\n acc += fragment;\n });\n\n flush();\n\n state.inTable = prevInTable;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseTableRow: ${duration.toFixed(3)}ms, source length: ${source.length}, cells count: ${cells.length}`\n );\n }\n\n return cells;\n};\n\n/**\n * Parse table cells (multiple rows).\n */\nexport const parseTableCells = (\n source: string,\n parse: NestedParser,\n state: ParseState\n): ParserResult[][][] => {\n const start = performance.now();\n const rowsText = source.trim().split('\\n');\n\n const result = rowsText.map((rowText) =>\n parseTableRow(rowText, parse, state, true)\n );\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseTableCells: ${duration.toFixed(3)}ms, source length: ${source.length}, rows count: ${rowsText.length}`\n );\n }\n\n return result;\n};\n\n// ============================================================================\n// PARSING HELPERS\n// ============================================================================\n\n/**\n * Check if a rule qualifies for the current source and state.\n */\nexport const qualifies = (\n source: string,\n state: ParseState,\n qualify: NonNullable<Rule<any>['_qualify']>\n): boolean => {\n if (Array.isArray(qualify)) {\n for (let i = 0; i < qualify.length; i++) {\n if (startsWith(source, qualify[i])) return true;\n }\n\n return false;\n }\n\n return (qualify as (source: string, state: ParseState) => boolean)(\n source,\n state\n );\n};\n\n/**\n * Marks a matcher function as eligible for being run inside an inline context.\n */\nexport const allowInline = <T extends (...args: any[]) => any>(\n fn: T\n): T & { inline: 1 } => {\n (fn as any).inline = 1;\n return fn as T & { inline: 1 };\n};\n\n/**\n * Creates a match function for an inline scoped element from a regex.\n */\nexport const inlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for inline elements except links.\n */\nexport const simpleInlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for a block scoped element from a regex.\n */\nexport const blockRegex =\n (regex: RegExp) =>\n (source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return null;\n } else {\n return regex.exec(source);\n }\n };\n\n/**\n * Creates a match function from a regex, ignoring block/inline scope.\n */\nexport const anyScopeRegex = (\n fn: RegExp | ((source: string, state: ParseState) => RegExpMatchArray | null)\n) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (typeof fn === 'function') {\n return fn(source, state);\n }\n return fn.exec(source);\n });\n\n/**\n * Parse inline content (including links).\n */\nexport const parseInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n state.inline = true;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Parse simple inline content (no links).\n */\nexport const parseSimpleInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n\n state.inline = false;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseSimpleInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Parse block content.\n */\nexport const parseBlock = (\n parse: NestedParser,\n children: string,\n state: ParseState = {}\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline || false;\n state.inline = false;\n const normalizedChildren = trimEnd(children);\n const needsTerminator = /\\n\\n$/.test(normalizedChildren) === false;\n const blockInput = needsTerminator\n ? normalizedChildren.endsWith('\\n')\n ? `${normalizedChildren}\\n`\n : `${normalizedChildren}\\n\\n`\n : normalizedChildren;\n\n const result = parse(blockInput, state);\n state.inline = isCurrentlyInline;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseBlock: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Helper to parse capture group 2 as inline content.\n */\nexport const parseCaptureInline = (\n capture: RegExpMatchArray,\n parse: NestedParser,\n state: ParseState\n): { children: ParserResult[] } => {\n return {\n children: parseInline(parse, capture[2], state),\n };\n};\n\n/**\n * Helper that captures nothing (empty object).\n */\nexport const captureNothing = (): Record<string, never> => ({});\n\n/**\n * Helper that renders nothing (null).\n */\nexport const renderNothing = (): null => null;\n\n/**\n * Check if any regex in a list matches the input.\n */\nexport const some = (regexes: RegExp[], input: string): boolean => {\n for (let i = 0; i < regexes.length; i++) {\n if (regexes[i].test(input)) {\n return true;\n }\n }\n return false;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/markdown/utils.ts"],"sourcesContent":["import {\n ATTRIBUTES_TO_SANITIZE,\n CAPTURE_LETTER_AFTER_HYPHEN,\n FENCE_DELIMITER_R,\n HTML_CUSTOM_ATTR_R,\n INTERPOLATION_R,\n NORMALIZE_WHITESPACE_R,\n TABLE_CENTER_ALIGN,\n TABLE_LEFT_ALIGN,\n TABLE_RIGHT_ALIGN,\n TABLE_TRIM_PIPES,\n UNESCAPE_R,\n} from './constants';\nimport type { NestedParser, ParserResult, ParseState, Rule } from './types';\n\n// ============================================================================\n// STRING UTILITIES\n// ============================================================================\n\n/**\n * Trim trailing whitespace from a string.\n */\nexport const trimEnd = (str: string): string => {\n let end = str.length;\n\n while (end > 0 && str[end - 1]! <= ' ') end--;\n\n return str.slice(0, end);\n};\n\n/**\n * Check if string starts with prefix.\n */\nexport const startsWith = (str: string, prefix: string): boolean => {\n return str.startsWith(prefix);\n};\n\n/**\n * Remove symmetrical leading and trailing quotes.\n */\nexport const unquote = (str: string): string => {\n const first = str[0];\n\n if (\n (first === '\"' || first === \"'\") &&\n str.length >= 2 &&\n str[str.length - 1] === first\n ) {\n return str.slice(1, -1);\n }\n\n return str;\n};\n\n/**\n * Unescape backslash-escaped characters.\n */\nexport const unescapeString = (rawString: string): string =>\n rawString ? rawString.replace(UNESCAPE_R, '$1') : rawString;\n\n/**\n * Join class names, filtering out falsy values.\n */\nexport const cx = (...args: any[]): string => args.filter(Boolean).join(' ');\n\n/**\n * Get a nested property from an object using dot notation.\n */\nexport const get = (src: any, path: string, fb?: any): any => {\n let ptr = src;\n const frags = path.split('.');\n\n while (frags.length) {\n ptr = ptr[frags[0]!];\n\n if (ptr === undefined) break;\n else frags.shift();\n }\n\n return ptr ?? fb;\n};\n\n// ============================================================================\n// SLUGIFY\n// ============================================================================\n\n/**\n * Convert a string to a URL-safe slug.\n * Based on https://stackoverflow.com/a/18123682/1141611\n */\nconst SLUGIFY_REPLACEMENTS: [pattern: RegExp, replacement: string][] = [\n [/[ÀÁÂÃÄÅàáâãä忯]/g, 'a'],\n [/[çÇ]/g, 'c'],\n [/[ðÐ]/g, 'd'],\n [/[ÈÉÊËéèêë]/g, 'e'],\n [/[ÏïÎîÍíÌì]/g, 'i'],\n [/[Ññ]/g, 'n'],\n [/[øØœŒÕõÔôÓóÒò]/g, 'o'],\n [/[ÜüÛûÚúÙù]/g, 'u'],\n [/[ŸÿÝý]/g, 'y'],\n [/[^a-z0-9- ]/gi, ''],\n [/ /gi, '-'],\n];\n\nexport const slugify = (str: string): string => {\n let result = str;\n\n for (let i = 0; i < SLUGIFY_REPLACEMENTS.length; i++) {\n const [pattern, replacement] = SLUGIFY_REPLACEMENTS[i]!;\n result = result.replace(pattern, replacement);\n }\n\n return result.toLowerCase();\n};\n\n// ============================================================================\n// SANITIZER\n// ============================================================================\n\nconst SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;\nconst SANITIZE_STRIP_R = /[^A-Za-z0-9/:]/g;\n\n/**\n * Sanitize URLs to prevent XSS attacks.\n * Returns null if the URL is unsafe.\n */\nexport const sanitizer = (input: string): string | null => {\n // `SANITIZE_R` only ever matches on a colon, and decoding can introduce one\n // solely through a percent escape — so a value with neither is safe as-is,\n // and skipping the decode avoids the bulk of the work on ordinary links.\n if (input.indexOf(':') === -1 && input.indexOf('%') === -1) return input;\n\n try {\n const decoded = decodeURIComponent(input).replace(SANITIZE_STRIP_R, '');\n\n if (SANITIZE_R.test(decoded)) {\n console.warn(\n 'Input contains an unsafe JavaScript/VBScript/data expression, it will not be rendered.',\n decoded\n );\n\n return null;\n }\n } catch (_e) {\n console.warn(\n 'Input could not be decoded due to malformed syntax or characters, it will not be rendered.',\n input\n );\n\n // decodeURIComponent sometimes throws a URIError\n return null;\n }\n\n return input;\n};\n\n// ============================================================================\n// WHITESPACE NORMALIZATION\n// ============================================================================\n\n/**\n * Normalize whitespace in source string.\n */\nexport const normalizeWhitespace = (source: string): string =>\n // `\\r`, `\\f` and `\\t` are disjoint, so one pass over the source replaces\n // what used to take three full scans.\n source.replace(NORMALIZE_WHITESPACE_R, (match) => {\n if (match === '\\t') return ' ';\n if (match === '\\f') return '';\n\n return '\\n';\n });\n\n/**\n * Safely remove a uniform leading indentation from lines, but do NOT touch\n * the content inside fenced code blocks (``` or ~~~).\n *\n * Inside a fenced block the structural indentation is irrelevant: what matters\n * is the indentation of the opening fence itself, which is the only amount\n * CommonMark strips from the code lines. A block nested in an indented HTML\n * element but written with its fence at column 0 therefore keeps its code\n * verbatim, instead of losing the first level of indentation.\n */\nexport const trimLeadingWhitespaceOutsideFences = (\n text: string,\n whitespace: string\n): string => {\n if (!whitespace) return text;\n\n const lines = text.split('\\n');\n\n /** Indentation and marker of the fence currently open, if any. */\n let openFence: { indentation: string; marker: string } | null = null;\n\n const removePrefix = (line: string, prefix: string): string =>\n prefix && line.startsWith(prefix) ? line.slice(prefix.length) : line;\n\n // Outside fences, strip the base structural indentation from every line.\n // Lines that don't start with the whitespace prefix are left as-is.\n const result = lines\n .map((line) => {\n const fenceMatch = line.match(FENCE_DELIMITER_R);\n\n if (!openFence) {\n if (fenceMatch)\n openFence = { indentation: fenceMatch[1]!, marker: fenceMatch[2]! };\n return removePrefix(line, whitespace);\n }\n\n const isClosingFence = fenceMatch?.[2]?.startsWith(openFence.marker);\n const { indentation } = openFence;\n\n if (isClosingFence) openFence = null;\n\n return removePrefix(line, indentation);\n })\n .join('\\n');\n\n return result;\n};\n\n/**\n * Normalize HTML attribute key to JSX prop name.\n */\nexport const normalizeAttributeKey = (key: string): string => {\n const hyphenIndex = key.indexOf('-');\n\n if (hyphenIndex !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) {\n key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, (_, letter) => {\n return letter.toUpperCase();\n });\n }\n\n return key;\n};\n\ntype StyleTuple = [key: string, value: string];\n\n/**\n * Parse a CSS style string into an array of [key, value] tuples.\n */\nexport const parseStyleAttribute = (styleString: string): StyleTuple[] => {\n const styles: StyleTuple[] = [];\n let buffer = '';\n let inUrl = false;\n let inQuotes = false;\n let quoteChar: '\"' | \"'\" | '' = '';\n\n if (!styleString) return styles;\n\n for (let i = 0; i < styleString.length; i++) {\n const char = styleString[i];\n\n if ((char === '\"' || char === \"'\") && !inUrl) {\n if (!inQuotes) {\n inQuotes = true;\n quoteChar = char;\n } else if (char === quoteChar) {\n inQuotes = false;\n quoteChar = '';\n }\n }\n\n if (char === '(' && buffer.endsWith('url')) {\n inUrl = true;\n } else if (char === ')' && inUrl) {\n inUrl = false;\n }\n\n if (char === ';' && !inQuotes && !inUrl) {\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n buffer = '';\n } else {\n buffer += char;\n }\n }\n\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n\n return styles;\n};\n\n/**\n * Convert an attribute value to a Node prop value.\n */\nexport const attributeValueToNodePropValue = (\n tag: string,\n key: string,\n value: string,\n sanitizeUrlFn: (\n value: string,\n tag: string,\n attribute: string\n ) => string | null\n): any => {\n if (key === 'style') {\n return parseStyleAttribute(value).reduce(\n (styles, [styleKey, styleValue]) => {\n const camelCasedKey = styleKey.replace(/(-[a-z])/g, (substr) =>\n substr[1]!.toUpperCase()\n );\n\n (styles as Record<string, any>)[camelCasedKey] = sanitizeUrlFn(\n styleValue,\n tag,\n styleKey\n );\n\n return styles;\n },\n {} as Record<string, any>\n );\n } else if (ATTRIBUTES_TO_SANITIZE.indexOf(key) !== -1) {\n return sanitizeUrlFn(unescapeString(value), tag, key);\n } else if (value.match(INTERPOLATION_R)) {\n value = unescapeString(value.slice(1, value.length - 1));\n }\n\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n }\n\n return value;\n};\n\n// ============================================================================\n// TABLE PARSING\n// ============================================================================\n\n/**\n * Parse table alignment from a separator row.\n */\nexport const parseTableAlignCapture = (\n alignCapture: string\n): 'left' | 'right' | 'center' => {\n if (TABLE_RIGHT_ALIGN.test(alignCapture)) {\n return 'right';\n } else if (TABLE_CENTER_ALIGN.test(alignCapture)) {\n return 'center';\n } else if (TABLE_LEFT_ALIGN.test(alignCapture)) {\n return 'left';\n }\n\n return 'left';\n};\n\n/**\n * Parse table alignment row.\n */\nexport const parseTableAlign = (\n source: string\n): ('left' | 'right' | 'center')[] => {\n const alignText = source.replace(TABLE_TRIM_PIPES, '').split('|');\n return alignText.map(parseTableAlignCapture);\n};\n\n/**\n * Parse a single table row.\n */\nexport const parseTableRow = (\n source: string,\n parse: NestedParser,\n state: ParseState,\n tableOutput: boolean\n): ParserResult[][] => {\n const prevInTable = state.inTable;\n\n state.inTable = true;\n\n const cells: ParserResult[][] = [[]];\n let acc = '';\n\n const flush = (): void => {\n if (!acc) return;\n\n const cell = cells[cells.length - 1]!;\n cell.push.apply(cell, parse(acc, state));\n acc = '';\n };\n\n source\n .trim()\n .split(/(`[^`]*`|\\\\\\||\\|)/)\n .filter(Boolean)\n .forEach((fragment, i, arr) => {\n if (fragment.trim() === '|') {\n flush();\n\n if (tableOutput) {\n if (i !== 0 && i !== arr.length - 1) {\n cells.push([]);\n }\n\n return;\n }\n }\n\n acc += fragment;\n });\n\n flush();\n\n state.inTable = prevInTable;\n\n return cells;\n};\n\n/**\n * Parse table cells (multiple rows).\n */\nexport const parseTableCells = (\n source: string,\n parse: NestedParser,\n state: ParseState\n): ParserResult[][][] => {\n const rowsText = source.trim().split('\\n');\n\n const result = rowsText.map((rowText) =>\n parseTableRow(rowText, parse, state, true)\n );\n\n return result;\n};\n\n// ============================================================================\n// PARSING HELPERS\n// ============================================================================\n\n/**\n * Check if a rule qualifies for the current source and state.\n */\nexport const qualifies = (\n source: string,\n state: ParseState,\n qualify: NonNullable<Rule<any>['_qualify']>\n): boolean => {\n if (Array.isArray(qualify)) {\n for (let i = 0; i < qualify.length; i++) {\n if (startsWith(source, qualify[i]!)) return true;\n }\n\n return false;\n }\n\n return (qualify as (source: string, state: ParseState) => boolean)(\n source,\n state\n );\n};\n\n/**\n * Marks a matcher function as eligible for being run inside an inline context.\n */\nexport const allowInline = <T extends (...args: any[]) => any>(\n fn: T\n): T & { inline: 1 } => {\n (fn as any).inline = 1;\n return fn as T & { inline: 1 };\n};\n\n/**\n * Creates a match function for an inline scoped element from a regex.\n */\nexport const inlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for inline elements except links.\n */\nexport const simpleInlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for a block scoped element from a regex.\n */\nexport const blockRegex =\n (regex: RegExp) =>\n (source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return null;\n } else {\n return regex.exec(source);\n }\n };\n\n/**\n * Creates a match function from a regex, ignoring block/inline scope.\n */\nexport const anyScopeRegex = (\n fn: RegExp | ((source: string, state: ParseState) => RegExpMatchArray | null)\n) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (typeof fn === 'function') {\n return fn(source, state);\n }\n return fn.exec(source);\n });\n\n/**\n * Parse inline content (including links).\n */\nexport const parseInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n state.inline = true;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n return result;\n};\n\n/**\n * Parse simple inline content (no links).\n */\nexport const parseSimpleInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n\n state.inline = false;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n return result;\n};\n\n/**\n * Parse block content.\n */\nexport const parseBlock = (\n parse: NestedParser,\n children: string,\n state: ParseState = {}\n): ParserResult[] => {\n const isCurrentlyInline = state.inline || false;\n state.inline = false;\n const normalizedChildren = trimEnd(children);\n const needsTerminator = /\\n\\n$/.test(normalizedChildren) === false;\n const blockInput = needsTerminator\n ? normalizedChildren.endsWith('\\n')\n ? `${normalizedChildren}\\n`\n : `${normalizedChildren}\\n\\n`\n : normalizedChildren;\n\n const result = parse(blockInput, state);\n state.inline = isCurrentlyInline;\n\n return result;\n};\n\n/**\n * Helper to parse capture group 2 as inline content.\n */\nexport const parseCaptureInline = (\n capture: RegExpMatchArray,\n parse: NestedParser,\n state: ParseState\n): { children: ParserResult[] } => {\n return {\n children: parseInline(parse, capture[2] ?? '', state),\n };\n};\n\n/**\n * Helper that captures nothing (empty object).\n */\nexport const captureNothing = (): Record<string, never> => ({});\n\n/**\n * Helper that renders nothing (null).\n */\nexport const renderNothing = (): null => null;\n\n/**\n * Check if any regex in a list matches the input.\n */\nexport const some = (regexes: RegExp[], input: string): boolean => {\n for (let i = 0; i < regexes.length; i++) {\n if (regexes[i]!.test(input)) {\n return true;\n }\n }\n return false;\n};\n"],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -81,6 +81,7 @@ import { comparePaths, normalizePath } from "./localization/comparePaths.js";
|
|
|
81
81
|
import { LocaleDomainMap, getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain } from "./localization/domainUtils.js";
|
|
82
82
|
import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./localization/generateSitemap.js";
|
|
83
83
|
import { getBrowserLocale } from "./localization/getBrowserLocale.js";
|
|
84
|
+
import { getCanonicalPath } from "./localization/getCanonicalPath.js";
|
|
84
85
|
import { getHTMLTextDir } from "./localization/getHTMLTextDir.js";
|
|
85
86
|
import { getLocale } from "./localization/getLocale.js";
|
|
86
87
|
import { GetPrefixOptions, GetPrefixResult, getPrefix, isDeclaredLocale } from "./localization/getPrefix.js";
|
|
@@ -96,12 +97,13 @@ import { localeFlatMap, localeMap, localeRecord } from "./localization/localeMap
|
|
|
96
97
|
import { localeResolver } from "./localization/localeResolver.js";
|
|
97
98
|
import { ProxyMode, formatProxyEnabledMessage, isProxyStorageLocaleEnabled, resolveProxyMode } from "./localization/proxyMode.js";
|
|
98
99
|
import { getPreloadLocale, resolveBrowserLocale } from "./localization/resolveBrowserLocale.js";
|
|
99
|
-
import {
|
|
100
|
+
import { getRewriteRules } from "./localization/rewriteMatch.js";
|
|
101
|
+
import { LocalizedPathResult, getInternalPath, getRewritePath, resolveLocalizedPath } from "./localization/rewriteUtils.js";
|
|
100
102
|
import { validatePrefix } from "./localization/validatePrefix.js";
|
|
101
103
|
import "./localization/index.js";
|
|
102
104
|
import { BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, CustomComponentNode, ElementType, EscapedTextNode, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, HTMLCommentNode, HTMLNode, HTMLSelfClosingNode, HTMLTag, HeadingNode, HeadingSetextNode, ImageNode, ItalicTextNode, LinkAngleBraceNode, LinkBareURLNode, LinkNode, MarkdownContext, MarkdownOptions, MarkdownRuntime, MarkedTextNode, NestedParser, NewlineNode, OrderedListNode, ParagraphNode, ParseState, Parser, ParserResult, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, Rules, StrikethroughTextNode, TableNode, TableSeparatorNode, TextNode, UnorderedListNode } from "./markdown/types.js";
|
|
103
105
|
import { MarkdownReferences, ParsedMarkdown, compile, compileWithOptions, createCompiler, parseMarkdown, renderMarkdownAst } from "./markdown/compiler.js";
|
|
104
|
-
import { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, DO_NOT_PROCESS_HTML_ELEMENTS,
|
|
106
|
+
import { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_OPENING_TAG_R, CUSTOM_COMPONENT_R, DO_NOT_PROCESS_HTML_ELEMENTS, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_BLOCK_ELEMENT_R, HTML_BLOCK_OPENING_TAG_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_SELF_CLOSING_OPENING_TAG_R, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, ListType, NAMED_CODES_TO_UNICODE, NORMALIZE_WHITESPACE_R, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, Priority, PriorityValue, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleType, RuleTypeValue, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex } from "./markdown/constants.js";
|
|
105
107
|
import { parserFor } from "./markdown/parser.js";
|
|
106
108
|
import { createRenderer, renderFor } from "./markdown/renderer.js";
|
|
107
109
|
import { allowInline, anyScopeRegex, attributeValueToNodePropValue, blockRegex, captureNothing, cx, get, inlineRegex, normalizeAttributeKey, normalizeWhitespace, parseBlock, parseCaptureInline, parseInline, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, qualifies, renderNothing, sanitizer, simpleInlineRegex, slugify, some, startsWith, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, unquote } from "./markdown/utils.js";
|
|
@@ -121,4 +123,4 @@ import { CookieBuildAttributes, LocaleStorage, LocaleStorageClient, LocaleStorag
|
|
|
121
123
|
import { YamlRecord, YamlValue, parseYaml } from "./utils/parseYaml.js";
|
|
122
124
|
import { stringifyYaml } from "./utils/stringifyYaml.js";
|
|
123
125
|
import "./utils/index.js";
|
|
124
|
-
export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, type BlockQuoteNode, type BoldTextNode, type BreakLineNode, type BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, type CodeBlockNode, type CodeFencedNode, type CodeInlineNode, type CompileOptions, type ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, type CustomComponentNode, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS,
|
|
126
|
+
export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, type BlockQuoteNode, type BoldTextNode, type BreakLineNode, type BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_OPENING_TAG_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, type CodeBlockNode, type CodeFencedNode, type CodeInlineNode, type CompileOptions, type ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, type CustomComponentNode, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, type ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, type EscapedTextNode, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, type FileContent, type FileContentConstructor, type FootnoteNode, type FootnoteReferenceNode, type GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, type GenerateSitemapOptions, GetNestingResult, type GetPrefixOptions, type GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, type HTMLCommentNode, HTMLContent, HTMLContentConstructor, type HTMLNode, type HTMLSelfClosingNode, type HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_BLOCK_OPENING_TAG_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_SELF_CLOSING_OPENING_TAG_R, HTML_TAGS, type HeadingNode, type HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, type ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, InterpolableNode, IntlConstructorName, IsAny, type ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, type LinkAngleBraceNode, type LinkBareURLNode, type LinkNode, ListType, type LocaleDomainMap, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, type LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, type MarkdownContext, type MarkdownOptions, MarkdownReferences, type MarkdownRuntime, type HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, type MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NORMALIZE_WHITESPACE_R, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedFieldReferences, type NestedParser, type NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, type OrderedListNode, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, type ParagraphNode, type ParseState, ParsedMarkdown, type Parser, type ParserResult, PlainDynamicLoaderMap, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, PreloadableDynamicLoaderMap, PreloadedDynamicEntry, Priority, PriorityValue, type ProxyMode, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, type ReferenceImageNode, type ReferenceLinkNode, type ReferenceNode, type RenderRuleHook, ResolvedDynamicLoader, type Rule, type RuleOutput, RuleType, RuleTypeValue, type Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SelectCond, SelectContent, SelectContentStates, SelectSelector, type SitemapUrlEntry, type StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, type TableNode, type TableSeparatorNode, TaggedMessageToken, type TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, type UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, type file, type fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LocalesValues } from "@intlayer/types/module_augmentation";
|
|
2
|
+
import { RewriteRules, RoutingConfig } from "@intlayer/types/config";
|
|
3
|
+
//#region src/localization/getCanonicalPath.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Given a localized URL (e.g., "/produits/123"), finds the canonical internal path (e.g., "/products/123").
|
|
6
|
+
* If locale is provided, only check for that locale. Otherwise, check for all locales.
|
|
7
|
+
*
|
|
8
|
+
* The lookup is encoding-insensitive: a percent-encoded path matches a pattern
|
|
9
|
+
* written with literal (non-ASCII) characters.
|
|
10
|
+
*
|
|
11
|
+
* @param localizedPath - The path as seen in the browser, without locale prefix.
|
|
12
|
+
* @param locale - Restricts the lookup to that locale's rules. Defaults to every locale.
|
|
13
|
+
* @param rewriteRules - Raw `routing.rewrite` configuration or already-normalized
|
|
14
|
+
* rules. Defaults to the project configuration's `routing.rewrite`.
|
|
15
|
+
*/
|
|
16
|
+
declare const getCanonicalPath: <const Path extends string, const Locale extends LocalesValues = LocalesValues>(localizedPath: Path, locale?: Locale, rewriteRules?: RoutingConfig['rewrite'] | RewriteRules) => string;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { getCanonicalPath };
|
|
19
|
+
//# sourceMappingURL=getCanonicalPath.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getCanonicalPath.d.ts","names":[],"sources":["../../../src/localization/getCanonicalPath.ts"],"mappings":";;;;;;;;;;;;;;;cAkCa,yBACL,2BACA,eAAe,gBAAgB,eAAa,eAEnC,MAAI,SACV,QAAM,eACA,2BAA2B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedPath.d.ts","names":[],"sources":["../../../src/localization/getLocalizedPath.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"getLocalizedPath.d.ts","names":[],"sources":["../../../src/localization/getLocalizedPath.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4Da,yBACL,oCACA,sBAAsB,gBAAgB,uBAAqB,eAElD,eAAa,SACpB,eAAa,UACZ,mBACR,kBAAkB,eAAe"}
|
|
@@ -2,6 +2,7 @@ import { comparePaths, normalizePath } from "./comparePaths.js";
|
|
|
2
2
|
import { LocaleDomainMap, getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain } from "./domainUtils.js";
|
|
3
3
|
import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./generateSitemap.js";
|
|
4
4
|
import { getBrowserLocale } from "./getBrowserLocale.js";
|
|
5
|
+
import { getCanonicalPath } from "./getCanonicalPath.js";
|
|
5
6
|
import { getHTMLTextDir } from "./getHTMLTextDir.js";
|
|
6
7
|
import { getLocale } from "./getLocale.js";
|
|
7
8
|
import { GetPrefixOptions, GetPrefixResult, getPrefix, isDeclaredLocale } from "./getPrefix.js";
|
|
@@ -17,6 +18,7 @@ import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.js";
|
|
|
17
18
|
import { localeResolver } from "./localeResolver.js";
|
|
18
19
|
import { ProxyMode, formatProxyEnabledMessage, isProxyStorageLocaleEnabled, resolveProxyMode } from "./proxyMode.js";
|
|
19
20
|
import { getPreloadLocale, resolveBrowserLocale } from "./resolveBrowserLocale.js";
|
|
20
|
-
import {
|
|
21
|
+
import { getRewriteRules } from "./rewriteMatch.js";
|
|
22
|
+
import { LocalizedPathResult, getInternalPath, getRewritePath, resolveLocalizedPath } from "./rewriteUtils.js";
|
|
21
23
|
import { validatePrefix } from "./validatePrefix.js";
|
|
22
24
|
export { type GenerateSitemapOptions, type GetPrefixOptions, type GetPrefixResult, type LocaleDomainMap, type LocalizedPathResult, type ProxyMode, type SitemapUrlEntry, comparePaths, formatProxyEnabledMessage, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getDomainHostname, getDomainOrigin, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getPreloadLocale, getRewritePath, getRewriteRules, isDeclaredLocale, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, resolveBrowserLocale, resolveLocalizedPath, resolveProxyMode, validatePrefix };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RewriteObject, RewriteRules, RoutingConfig } from "@intlayer/types/config";
|
|
2
|
+
//#region src/localization/rewriteMatch.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Normalizes legacy Record format or extracts specialized rules from RewriteObject.
|
|
5
|
+
*
|
|
6
|
+
* Idempotent: already-normalized rules are handed back untouched, so a caller
|
|
7
|
+
* holding resolved rules can pass them on without re-normalizing.
|
|
8
|
+
*/
|
|
9
|
+
declare const getRewriteRules: <const Context extends keyof RewriteObject = 'url'>(rewrite: RoutingConfig['rewrite'] | RewriteRules, context?: Context) => RewriteRules | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Replaces route parameters in a path with provided values.
|
|
12
|
+
*/
|
|
13
|
+
declare const fillPath: (pattern: string, params: string[]) => string;
|
|
14
|
+
/**
|
|
15
|
+
* Extract values from a URL based on a pattern.
|
|
16
|
+
*/
|
|
17
|
+
declare const extractParams: (url: string, pattern: string) => string[] | null;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { extractParams, fillPath, getRewriteRules };
|
|
20
|
+
//# sourceMappingURL=rewriteMatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewriteMatch.d.ts","names":[],"sources":["../../../src/localization/rewriteMatch.ts"],"mappings":";;;;;;;;cAYa,wBACL,sBAAsB,uBAAqB,SAExC,2BAA2B,cAAY,UACvC,YACR;;;;cA+DU,WAAQ,iBAAmB;;;;cAa3B,gBAAa,aACb"}
|