@intlayer/core 9.4.4 → 9.5.0
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 +0 -2
- package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs.map +1 -1
- package/dist/cjs/index.cjs +5 -8
- package/dist/cjs/interpreter/getPlural.cjs.map +1 -1
- package/dist/cjs/markdown/compiler.cjs +437 -209
- package/dist/cjs/markdown/compiler.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs +32 -50
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/markdown/elementScanner.cjs +191 -0
- package/dist/cjs/markdown/elementScanner.cjs.map +1 -0
- package/dist/cjs/markdown/index.cjs +5 -8
- package/dist/cjs/markdown/parser.cjs +90 -48
- package/dist/cjs/markdown/parser.cjs.map +1 -1
- package/dist/cjs/markdown/renderer.cjs +14 -11
- package/dist/cjs/markdown/renderer.cjs.map +1 -1
- package/dist/cjs/markdown/utils.cjs +123 -34
- package/dist/cjs/markdown/utils.cjs.map +1 -1
- package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs.map +1 -1
- package/dist/esm/index.mjs +3 -3
- package/dist/esm/interpreter/getPlural.mjs.map +1 -1
- package/dist/esm/markdown/compiler.mjs +438 -211
- package/dist/esm/markdown/compiler.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +29 -43
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/markdown/elementScanner.mjs +183 -0
- package/dist/esm/markdown/elementScanner.mjs.map +1 -0
- package/dist/esm/markdown/index.mjs +3 -3
- package/dist/esm/markdown/parser.mjs +90 -48
- package/dist/esm/markdown/parser.mjs.map +1 -1
- package/dist/esm/markdown/renderer.mjs +14 -11
- package/dist/esm/markdown/renderer.mjs.map +1 -1
- package/dist/esm/markdown/utils.mjs +124 -35
- package/dist/esm/markdown/utils.mjs.map +1 -1
- package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts +3 -3
- package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/interpreter/getPlural.d.ts +3 -3
- package/dist/types/interpreter/getPlural.d.ts.map +1 -1
- package/dist/types/markdown/compiler.d.ts +43 -0
- package/dist/types/markdown/compiler.d.ts.map +1 -1
- package/dist/types/markdown/constants.d.ts +26 -17
- package/dist/types/markdown/constants.d.ts.map +1 -1
- package/dist/types/markdown/elementScanner.d.ts +14 -0
- package/dist/types/markdown/elementScanner.d.ts.map +1 -0
- package/dist/types/markdown/index.d.ts +4 -4
- package/dist/types/markdown/parser.d.ts +0 -5
- package/dist/types/markdown/parser.d.ts.map +1 -1
- package/dist/types/markdown/renderer.d.ts +0 -4
- package/dist/types/markdown/renderer.d.ts.map +1 -1
- package/dist/types/markdown/types.d.ts +13 -0
- package/dist/types/markdown/types.d.ts.map +1 -1
- package/dist/types/markdown/utils.d.ts +7 -2
- package/dist/types/markdown/utils.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getDictionaryAsync.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getEnumeration.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getGender.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getInsertion.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getPlural.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getSelect.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/index.d.ts +0 -7
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/interpolableNode.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/transpiler/index.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/transpiler/nesting/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/transpiler/nesting/nesting.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getDictionaryAsync.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getEnumeration.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getGender.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getInsertion.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getPlural.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/getSelect.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/index.d.ts +0 -7
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/interpreter/interpolableNode.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/intlayer/dist/types/index.d.ts +0 -6
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/transpiler/index.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/transpiler/nesting/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/@intlayer/core/dist/types/transpiler/nesting/nesting.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/dictionaryManipulator/plainDynamicLoader.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/formatters/compact.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/currency.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/date.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/index.d.ts +0 -9
- package/dist/types/@intlayer/core/dist/types/formatters/list.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/number.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/percentage.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/relativeTime.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/formatters/units.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/interpreter/dictionaryTransformCache.d.ts +0 -4
- package/dist/types/@intlayer/core/dist/types/interpreter/getCondition.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/interpreter/getContent/deepTransform.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/interpreter/getContent/getContent.d.ts +0 -3
- package/dist/types/@intlayer/core/dist/types/interpreter/getContent/index.d.ts +0 -3
- package/dist/types/@intlayer/core/dist/types/interpreter/getContent/plugins.d.ts +0 -7
- package/dist/types/@intlayer/core/dist/types/interpreter/getDictionary.d.ts +0 -4
- package/dist/types/@intlayer/core/dist/types/interpreter/getDictionaryAsync.d.ts +0 -6
- package/dist/types/@intlayer/core/dist/types/interpreter/getEnumeration.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/interpreter/getGender.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/interpreter/getInsertion.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/interpreter/getIntlayer.d.ts +0 -4
- package/dist/types/@intlayer/core/dist/types/interpreter/getIntlayerAsync.d.ts +0 -4
- package/dist/types/@intlayer/core/dist/types/interpreter/getNesting.d.ts +0 -6
- package/dist/types/@intlayer/core/dist/types/interpreter/getPlural.d.ts +0 -3
- package/dist/types/@intlayer/core/dist/types/interpreter/getSelect.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/interpreter/getTranslation.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/interpreter/index.d.ts +0 -18
- package/dist/types/@intlayer/core/dist/types/interpreter/interpolableNode.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/intlayer/dist/types/index.d.ts +0 -6
- package/dist/types/@intlayer/core/dist/types/localization/comparePaths.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/domainUtils.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/generateSitemap.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/getBrowserLocale.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/getCanonicalPath.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/getHTMLTextDir.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/getLocale.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/getLocaleFromPath.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/getLocaleLang.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/getLocaleName.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/getLocalizedPath.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/getLocalizedUrl.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/getMultilingualUrls.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/getPathWithoutLocale.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/getPrefix.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/index.d.ts +0 -22
- package/dist/types/@intlayer/core/dist/types/localization/localeDetector.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/localeMapper.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/localeResolver.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/resolveBrowserLocale.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/rewriteMatch.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/localization/rewriteUtils.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/localization/validatePrefix.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/markdown/index.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/transpiler/condition/condition.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/condition/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/enumeration/enumeration.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/enumeration/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/file/file.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/file/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/gender/gender.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/gender/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/html/html.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/html/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/index.d.ts +0 -22
- package/dist/types/@intlayer/core/dist/types/transpiler/insertion/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/insertion/insertion.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/markdown/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/markdown/markdown.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/nesting/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/nesting/nesting.d.ts +0 -4
- package/dist/types/@intlayer/core/dist/types/transpiler/plural/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/plural/plural.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/select/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/select/select.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/translation/index.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/transpiler/translation/translation.d.ts +0 -2
- package/dist/types/@intlayer/core/dist/types/utils/index.d.ts +0 -3
- package/dist/types/@intlayer/core/dist/types/utils/intl.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/utils/isSameKeyPath.d.ts +0 -1
- package/dist/types/@intlayer/core/dist/types/utils/localeStorage.d.ts +0 -2
- package/dist/types/intlayer/dist/types/index.d.ts +0 -14
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { 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, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, CONSECUTIVE_NEWLINE_R,
|
|
1
|
+
import { 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, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, CONSECUTIVE_NEWLINE_R, DO_NOT_PROCESS_HTML_ELEMENTS, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_LEFT_TRIM_AMOUNT_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, Priority, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleType, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNORDERED, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R } from "./constants.mjs";
|
|
2
|
+
import { matchCustomComponent, matchHtmlBlockElement, matchSelfClosingElement, startsWithCustomComponent, startsWithElement, startsWithHtmlBlockElement, startsWithSelfClosingElement } from "./elementScanner.mjs";
|
|
2
3
|
import { allowInline, anyScopeRegex, attributeValueToNodePropValue, blockRegex, captureNothing, cx, get, inlineRegex, normalizeAttributeKey, parseBlock, parseCaptureInline, parseInline, parseSimpleInline, parseTableAlign, parseTableCells, parseTableRow, renderNothing, sanitizer, simpleInlineRegex, slugify, some, startsWith, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, unquote } from "./utils.mjs";
|
|
3
4
|
import { parserFor } from "./parser.mjs";
|
|
4
5
|
import { createRenderer, renderFor } from "./renderer.mjs";
|
|
@@ -13,14 +14,6 @@ const LINK_R = new RegExp(`^\\[((?:\\[[^\\[\\]]*(?:\\[[^\\[\\]]*\\][^\\[\\]]*)*\
|
|
|
13
14
|
* lowercase the whole remaining document to look its closing tag up — copying
|
|
14
15
|
* the rest of the file on each probe.
|
|
15
16
|
*/
|
|
16
|
-
const closingTagRegexCache = /* @__PURE__ */ new Map();
|
|
17
|
-
const getClosingTagRegex = (tag) => {
|
|
18
|
-
const cached = closingTagRegexCache.get(tag);
|
|
19
|
-
if (cached) return cached;
|
|
20
|
-
const regex = new RegExp(`</${tag}>`, "i");
|
|
21
|
-
closingTagRegexCache.set(tag, regex);
|
|
22
|
-
return regex;
|
|
23
|
-
};
|
|
24
17
|
/**
|
|
25
18
|
* Builds a tag -> component resolver for one set of overrides.
|
|
26
19
|
*
|
|
@@ -29,10 +22,17 @@ const getClosingTagRegex = (tag) => {
|
|
|
29
22
|
*/
|
|
30
23
|
const createTagResolver = (components) => {
|
|
31
24
|
let lowercaseKeys = null;
|
|
25
|
+
if (Object.keys(components).length === 0) return (tag) => tag;
|
|
26
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
32
27
|
return (tag) => {
|
|
33
28
|
if (typeof tag !== "string") return tag;
|
|
29
|
+
const memoized = resolved.get(tag);
|
|
30
|
+
if (memoized !== void 0) return memoized;
|
|
34
31
|
const override = get(components, tag);
|
|
35
|
-
if (override)
|
|
32
|
+
if (override) {
|
|
33
|
+
resolved.set(tag, override);
|
|
34
|
+
return override;
|
|
35
|
+
}
|
|
36
36
|
if (!lowercaseKeys) {
|
|
37
37
|
lowercaseKeys = /* @__PURE__ */ new Map();
|
|
38
38
|
for (const key of Object.keys(components)) {
|
|
@@ -41,7 +41,9 @@ const createTagResolver = (components) => {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
const key = lowercaseKeys.get(tag.toLowerCase());
|
|
44
|
-
|
|
44
|
+
const result = (key ? get(components, key) : void 0) || tag;
|
|
45
|
+
resolved.set(tag, result);
|
|
46
|
+
return result;
|
|
45
47
|
};
|
|
46
48
|
};
|
|
47
49
|
/** Resolves the slugifier for a context, falling back to the built-in one. */
|
|
@@ -49,7 +51,7 @@ const createSlugger = (ctx) => (input) => ctx.slugify ? ctx.slugify(input, slugi
|
|
|
49
51
|
const createElementFactory = (ctx, options) => {
|
|
50
52
|
const { runtime, components = {} } = ctx;
|
|
51
53
|
const resolveTag = createTagResolver(components);
|
|
52
|
-
const filteredTags = options.tagfilter ? [
|
|
54
|
+
const filteredTags = options.tagfilter ? /* @__PURE__ */ new Set([
|
|
53
55
|
"title",
|
|
54
56
|
"textarea",
|
|
55
57
|
"style",
|
|
@@ -59,59 +61,211 @@ const createElementFactory = (ctx, options) => {
|
|
|
59
61
|
"noframes",
|
|
60
62
|
"script",
|
|
61
63
|
"plaintext"
|
|
62
|
-
] :
|
|
64
|
+
]) : null;
|
|
65
|
+
/**
|
|
66
|
+
* True when `props` can be handed to the runtime untouched: no `class`
|
|
67
|
+
* alias to fold into `className`, and no empty value to drop. Rules build a
|
|
68
|
+
* fresh literal for every element, so reusing it is safe, and it saves an
|
|
69
|
+
* object per element — the single largest allocation in the render phase.
|
|
70
|
+
*/
|
|
71
|
+
const needsPropsRewrite = (props) => {
|
|
72
|
+
if ("class" in props) return true;
|
|
73
|
+
for (const key in props) {
|
|
74
|
+
const value = props[key];
|
|
75
|
+
if (value === void 0 || value === null) return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
};
|
|
63
79
|
return (tag, props, ...children) => {
|
|
64
|
-
if (typeof tag === "string" && filteredTags.includes(tag.toLowerCase())) return null;
|
|
65
80
|
const isStringTag = typeof tag === "string";
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (props)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
if (filteredTags && isStringTag && (filteredTags.has(tag) || filteredTags.has(tag.toLowerCase()))) return null;
|
|
82
|
+
let finalProps;
|
|
83
|
+
if (!props) finalProps = {};
|
|
84
|
+
else if (!needsPropsRewrite(props)) finalProps = props;
|
|
85
|
+
else {
|
|
86
|
+
const className = cx(props.className, props.class);
|
|
87
|
+
const mergedProps = {};
|
|
88
|
+
let classNameHandled = false;
|
|
89
|
+
for (const key in props) {
|
|
90
|
+
const value = props[key];
|
|
91
|
+
if (value === void 0 || value === null) continue;
|
|
92
|
+
if (key === "className" || key === "class") {
|
|
93
|
+
if (!classNameHandled) {
|
|
94
|
+
if (className) mergedProps.className = className;
|
|
95
|
+
classNameHandled = true;
|
|
96
|
+
}
|
|
97
|
+
} else mergedProps[key] = value;
|
|
98
|
+
}
|
|
99
|
+
if (!classNameHandled && className) mergedProps.className = className;
|
|
100
|
+
finalProps = mergedProps;
|
|
78
101
|
}
|
|
79
|
-
if (
|
|
80
|
-
let finalProps = mergedProps;
|
|
81
|
-
if (runtime.normalizeProps && isStringTag) finalProps = runtime.normalizeProps(tag, mergedProps);
|
|
102
|
+
if (runtime.normalizeProps && isStringTag) finalProps = runtime.normalizeProps(tag, finalProps);
|
|
82
103
|
const component = resolveTag(tag);
|
|
83
|
-
return runtime.createElement(component, finalProps, ...children
|
|
104
|
+
return runtime.createElement(component, finalProps, ...children);
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
const createDocumentScope = () => ({
|
|
108
|
+
footnotes: [],
|
|
109
|
+
references: {}
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* Small enough to scan linearly, large enough that an app mixing a few option
|
|
113
|
+
* sets — say prose and a dictionary rendered with different components — keeps
|
|
114
|
+
* hitting it.
|
|
115
|
+
*/
|
|
116
|
+
const RULE_SET_CACHE_LIMIT = 8;
|
|
117
|
+
const ruleSetCache = [];
|
|
118
|
+
/**
|
|
119
|
+
* Every input that changes how rules are built. Compared directly rather than
|
|
120
|
+
* through a signature array, which would allocate on every compile.
|
|
121
|
+
*/
|
|
122
|
+
const builtFromSame = (entry, ctx, options, parseOnly) => entry.parseOnly === parseOnly && entry.ctx.runtime === ctx.runtime && entry.ctx.components === ctx.components && entry.ctx.namedCodesToUnicode === ctx.namedCodesToUnicode && entry.ctx.sanitizer === ctx.sanitizer && entry.ctx.slugify === ctx.slugify && entry.options.disableAutoLink === options.disableAutoLink && entry.options.disableParsingRawHTML === options.disableParsingRawHTML && entry.options.enforceAtxHeadings === options.enforceAtxHeadings && entry.options.tagfilter === options.tagfilter && entry.options.renderRule === options.renderRule;
|
|
123
|
+
/**
|
|
124
|
+
* Returns the rule set for these options, building it only when no cached set
|
|
125
|
+
* was made from the same inputs.
|
|
126
|
+
*/
|
|
127
|
+
const getRuleSet = (ctx, options, parseOnly) => {
|
|
128
|
+
for (let index = 0; index < ruleSetCache.length; index++) {
|
|
129
|
+
const entry = ruleSetCache[index];
|
|
130
|
+
if (!builtFromSame(entry, ctx, options, parseOnly)) continue;
|
|
131
|
+
if (index > 0) {
|
|
132
|
+
ruleSetCache.splice(index, 1);
|
|
133
|
+
ruleSetCache.unshift(entry);
|
|
134
|
+
}
|
|
135
|
+
return entry;
|
|
136
|
+
}
|
|
137
|
+
const scope = { current: createDocumentScope() };
|
|
138
|
+
const createElement = parseOnly ? noopCreateElement : createElementFactory(ctx, options);
|
|
139
|
+
const rules = createDocumentRules(createElement, ctx, options, scope);
|
|
140
|
+
const entry = {
|
|
141
|
+
ctx,
|
|
142
|
+
options,
|
|
143
|
+
parseOnly,
|
|
144
|
+
createElement,
|
|
145
|
+
scope,
|
|
146
|
+
parse: parserFor(rules),
|
|
147
|
+
emit: renderFor(createRenderer(rules, options.renderRule))
|
|
84
148
|
};
|
|
149
|
+
ruleSetCache.unshift(entry);
|
|
150
|
+
if (ruleSetCache.length > RULE_SET_CACHE_LIMIT) ruleSetCache.pop();
|
|
151
|
+
return entry;
|
|
85
152
|
};
|
|
86
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Runs `operation` with `scope` installed as the current document, restoring
|
|
155
|
+
* whatever was there before. The save/restore keeps a nested compile — a custom
|
|
156
|
+
* component that renders markdown of its own — from clobbering its caller.
|
|
157
|
+
*/
|
|
158
|
+
const withDocumentScope = (ref, scope, operation) => {
|
|
159
|
+
const previous = ref.current;
|
|
160
|
+
ref.current = scope;
|
|
161
|
+
try {
|
|
162
|
+
return operation();
|
|
163
|
+
} finally {
|
|
164
|
+
ref.current = previous;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const createRules = (createElement, ctx, options, scope, attrStringToMap, containsBlockSyntax, nonParagraphBlockSyntaxes) => {
|
|
87
168
|
const slug = createSlugger(ctx);
|
|
88
169
|
const sanitize = ctx.sanitizer ?? sanitizer;
|
|
89
170
|
const namedCodesToUnicode = ctx.namedCodesToUnicode ? {
|
|
90
171
|
...NAMED_CODES_TO_UNICODE,
|
|
91
172
|
...ctx.namedCodesToUnicode
|
|
92
173
|
} : NAMED_CODES_TO_UNICODE;
|
|
174
|
+
/**
|
|
175
|
+
* Raw HTML blocks and custom components differ only in how their tag is
|
|
176
|
+
* spelled: both trim the captured content, decide block or inline parsing
|
|
177
|
+
* from it, and render the tag with its attributes. `rawHtml` adds the two
|
|
178
|
+
* things only real HTML needs — the never-parse element list, and tracking
|
|
179
|
+
* whether we are inside an anchor.
|
|
180
|
+
*/
|
|
181
|
+
const pairedElementRule = (match, order, rawHtml, scope = SCOPE_BOTH) => ({
|
|
182
|
+
_scope: scope,
|
|
183
|
+
_qualify: ["<"],
|
|
184
|
+
_match: anyScopeRegex(match),
|
|
185
|
+
_order: order,
|
|
186
|
+
_parse(capture, parse, state) {
|
|
187
|
+
const content = capture[3] ?? "";
|
|
188
|
+
const whitespace = content.match(HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
|
|
189
|
+
const trimmed = trimLeadingWhitespaceOutsideFences(content, whitespace);
|
|
190
|
+
const parseFunc = containsBlockSyntax(trimmed) ? parseBlock : parseInline;
|
|
191
|
+
const tagName = (capture[1] ?? "").trim();
|
|
192
|
+
const lowercased = tagName.toLowerCase();
|
|
193
|
+
const noInnerParse = rawHtml && DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(lowercased) !== -1;
|
|
194
|
+
const tag = noInnerParse ? lowercased : tagName;
|
|
195
|
+
const ast = {
|
|
196
|
+
attrs: attrStringToMap(tag, capture[2] ?? ""),
|
|
197
|
+
noInnerParse,
|
|
198
|
+
tag
|
|
199
|
+
};
|
|
200
|
+
if (rawHtml) state.inAnchor = state.inAnchor || lowercased === "a";
|
|
201
|
+
if (noInnerParse) ast.text = content;
|
|
202
|
+
else {
|
|
203
|
+
const prevInHTML = state.inHTML;
|
|
204
|
+
state.inHTML = true;
|
|
205
|
+
ast.children = parseFunc(parse, trimmed, state);
|
|
206
|
+
state.inHTML = prevInHTML;
|
|
207
|
+
}
|
|
208
|
+
if (rawHtml) state.inAnchor = false;
|
|
209
|
+
return ast;
|
|
210
|
+
},
|
|
211
|
+
_render(node, output, state = {}) {
|
|
212
|
+
return createElement(node.tag, {
|
|
213
|
+
key: state.key,
|
|
214
|
+
...node.attrs ?? {}
|
|
215
|
+
}, node.text ?? (node.children ? output(node.children, state) : ""));
|
|
216
|
+
}
|
|
217
|
+
});
|
|
93
218
|
const generateListRule = (type) => {
|
|
94
219
|
const ordered = type === 1;
|
|
95
220
|
const LIST_R = ordered ? ORDERED_LIST_R : UNORDERED_LIST_R;
|
|
96
221
|
const LIST_ITEM_R = ordered ? ORDERED_LIST_ITEM_R : UNORDERED_LIST_ITEM_R;
|
|
97
222
|
const LIST_ITEM_PREFIX_R = ordered ? ORDERED_LIST_ITEM_PREFIX_R : UNORDERED_LIST_ITEM_PREFIX_R;
|
|
98
223
|
return {
|
|
99
|
-
|
|
224
|
+
_scope: SCOPE_BOTH,
|
|
225
|
+
_firstChars: ordered ? [
|
|
226
|
+
32,
|
|
227
|
+
9,
|
|
228
|
+
48,
|
|
229
|
+
49,
|
|
230
|
+
50,
|
|
231
|
+
51,
|
|
232
|
+
52,
|
|
233
|
+
53,
|
|
234
|
+
54,
|
|
235
|
+
55,
|
|
236
|
+
56,
|
|
237
|
+
57
|
|
238
|
+
] : [
|
|
239
|
+
32,
|
|
240
|
+
9,
|
|
241
|
+
42,
|
|
242
|
+
43,
|
|
243
|
+
45
|
|
244
|
+
],
|
|
245
|
+
_qualify: (source, state) => state.prevCaptureIndent !== void 0 && Boolean(state.list ?? (!state.inline && !state.simple)) && LIST_ITEM_PREFIX_R.test(source),
|
|
100
246
|
_match: allowInline((source, state) => {
|
|
101
247
|
const lineIndent = state.prevCaptureIndent;
|
|
102
248
|
const isStartOfLine = lineIndent !== void 0;
|
|
103
249
|
const isListAllowed = state.list ?? (!state.inline && !state.simple);
|
|
104
250
|
if (isStartOfLine && isListAllowed) {
|
|
105
251
|
const matchSource = lineIndent ? lineIndent + source : source;
|
|
106
|
-
|
|
252
|
+
const match = LIST_R.exec(matchSource);
|
|
253
|
+
if (!match) return null;
|
|
254
|
+
if (lineIndent && match[0].startsWith(lineIndent)) {
|
|
255
|
+
const adjusted = [...match];
|
|
256
|
+
adjusted[0] = match[0].slice(lineIndent.length);
|
|
257
|
+
adjusted.fullMatch = match[0];
|
|
258
|
+
return adjusted;
|
|
259
|
+
}
|
|
260
|
+
return match;
|
|
107
261
|
}
|
|
108
262
|
return null;
|
|
109
263
|
}),
|
|
110
264
|
_order: Priority.HIGH,
|
|
111
265
|
_parse(capture, parse, state) {
|
|
112
|
-
const bullet = capture[2];
|
|
266
|
+
const bullet = capture[2] ?? "";
|
|
113
267
|
const startValue = ordered ? +bullet.slice(0, -1) : void 0;
|
|
114
|
-
const items = capture[0].replace(BLOCK_END_R, "\n").match(LIST_ITEM_R);
|
|
268
|
+
const items = (capture.fullMatch ?? capture[0] ?? "").replace(BLOCK_END_R, "\n").match(LIST_ITEM_R);
|
|
115
269
|
if (!items) return {
|
|
116
270
|
items: [],
|
|
117
271
|
ordered,
|
|
@@ -122,8 +276,8 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
122
276
|
items: items.map((item, i) => {
|
|
123
277
|
const prefixCapture = LIST_ITEM_PREFIX_R.exec(item);
|
|
124
278
|
const space = prefixCapture ? prefixCapture[0].length : 0;
|
|
125
|
-
const spaceRegex = new RegExp(`^ {1,${space}}`, "gm");
|
|
126
|
-
const content = item.
|
|
279
|
+
const spaceRegex = space <= 8 ? STRIP_INDENT_REGEXES[space] : new RegExp(`^ {1,${space}}`, "gm");
|
|
280
|
+
const content = item.slice(space).replace(spaceRegex, "");
|
|
127
281
|
const isLastItem = i === items.length - 1;
|
|
128
282
|
const thisItemIsAParagraph = content.indexOf("\n\n") !== -1 || isLastItem && lastItemWasAParagraph;
|
|
129
283
|
lastItemWasAParagraph = thisItemIsAParagraph;
|
|
@@ -148,21 +302,33 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
148
302
|
};
|
|
149
303
|
},
|
|
150
304
|
_render(node, output, state = {}) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
305
|
+
return createElement(ordered ? "ol" : "ul", {
|
|
306
|
+
key: state.key,
|
|
307
|
+
start: node.start
|
|
308
|
+
}, ...node.items.map((item, i) => createElement("li", { key: i }, output(item, state))));
|
|
155
309
|
}
|
|
156
310
|
};
|
|
157
311
|
};
|
|
158
312
|
const matchParagraph = (source, state) => {
|
|
159
313
|
if (state.inline || state.simple || state.inHTML && source.indexOf("\n\n") === -1 && !state.prevCaptureHasBlankLine) return null;
|
|
160
314
|
let start = 0;
|
|
161
|
-
|
|
315
|
+
const srcLen = source.length;
|
|
316
|
+
while (start < srcLen) {
|
|
162
317
|
const newlineIndex = source.indexOf("\n", start);
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
318
|
+
const lineEnd = newlineIndex === -1 ? srcLen : newlineIndex;
|
|
319
|
+
let p = start;
|
|
320
|
+
while (p < lineEnd && (source.charCodeAt(p) === 32 || source.charCodeAt(p) === 9)) p++;
|
|
321
|
+
if (p >= lineEnd) break;
|
|
322
|
+
if (p - start >= 4 || source.charCodeAt(start) === 9) break;
|
|
323
|
+
const ch = source.charCodeAt(p);
|
|
324
|
+
if (ch === 62 || ch === 96 || ch === 126 || ch === 35 || ch === 124 || ch === 42 || ch === 43 || ch === 45 || ch === 61 || ch === 60 || ch >= 48 && ch <= 57) {
|
|
325
|
+
const line = source.slice(start, newlineIndex === -1 ? void 0 : newlineIndex + 1);
|
|
326
|
+
if (some(nonParagraphBlockSyntaxes, line)) break;
|
|
327
|
+
}
|
|
328
|
+
if (newlineIndex === -1) {
|
|
329
|
+
start = srcLen;
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
166
332
|
start = newlineIndex + 1;
|
|
167
333
|
}
|
|
168
334
|
const match = source.slice(0, start);
|
|
@@ -177,11 +343,12 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
177
343
|
};
|
|
178
344
|
return {
|
|
179
345
|
[RuleType.blockQuote]: {
|
|
346
|
+
_scope: SCOPE_BLOCK,
|
|
180
347
|
_qualify: [">"],
|
|
181
348
|
_match: blockRegex(BLOCKQUOTE_R),
|
|
182
349
|
_order: Priority.HIGH,
|
|
183
350
|
_parse(capture, parse, state) {
|
|
184
|
-
const matchAlert = capture[0].replace(BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, "").match(BLOCKQUOTE_ALERT_R);
|
|
351
|
+
const matchAlert = (capture[0] ?? "").replace(BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, "").match(BLOCKQUOTE_ALERT_R);
|
|
185
352
|
const alert = matchAlert?.[1];
|
|
186
353
|
const content = matchAlert?.[2] ?? "";
|
|
187
354
|
return {
|
|
@@ -208,6 +375,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
208
375
|
}
|
|
209
376
|
},
|
|
210
377
|
[RuleType.breakLine]: {
|
|
378
|
+
_scope: SCOPE_BOTH,
|
|
211
379
|
_qualify: [" "],
|
|
212
380
|
_match: anyScopeRegex(BREAK_LINE_R),
|
|
213
381
|
_order: Priority.HIGH,
|
|
@@ -217,6 +385,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
217
385
|
}
|
|
218
386
|
},
|
|
219
387
|
[RuleType.breakThematic]: {
|
|
388
|
+
_scope: SCOPE_BLOCK,
|
|
220
389
|
_qualify: [
|
|
221
390
|
"--",
|
|
222
391
|
"__",
|
|
@@ -233,6 +402,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
233
402
|
}
|
|
234
403
|
},
|
|
235
404
|
[RuleType.codeBlock]: {
|
|
405
|
+
_scope: SCOPE_BLOCK,
|
|
236
406
|
_qualify: [" "],
|
|
237
407
|
_match: blockRegex(CODE_BLOCK_R),
|
|
238
408
|
_order: Priority.MAX,
|
|
@@ -240,7 +410,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
240
410
|
return {
|
|
241
411
|
type: RuleType.codeBlock,
|
|
242
412
|
lang: void 0,
|
|
243
|
-
text: unescapeString(trimEnd(capture[0].replace(/^ {4}/gm, "")))
|
|
413
|
+
text: unescapeString(trimEnd((capture[0] ?? "").replace(/^ {4}/gm, "")))
|
|
244
414
|
};
|
|
245
415
|
},
|
|
246
416
|
_render(node, _, state = {}) {
|
|
@@ -251,6 +421,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
251
421
|
}
|
|
252
422
|
},
|
|
253
423
|
[RuleType.codeFenced]: {
|
|
424
|
+
_scope: SCOPE_BLOCK,
|
|
254
425
|
_qualify: ["```", "~~~"],
|
|
255
426
|
_match: blockRegex(CODE_BLOCK_FENCED_R),
|
|
256
427
|
_order: Priority.MAX,
|
|
@@ -258,43 +429,48 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
258
429
|
return {
|
|
259
430
|
attrs: attrStringToMap("code", capture[3] ?? ""),
|
|
260
431
|
lang: capture[2] || void 0,
|
|
261
|
-
text: capture[4],
|
|
432
|
+
text: capture[4] ?? "",
|
|
262
433
|
type: RuleType.codeBlock
|
|
263
434
|
};
|
|
264
435
|
}
|
|
265
436
|
},
|
|
266
437
|
[RuleType.codeInline]: {
|
|
267
|
-
|
|
438
|
+
_scope: SCOPE_INLINE,
|
|
439
|
+
_firstChars: [96],
|
|
440
|
+
_qualify: (source) => source.charCodeAt(0) === 96 && source.indexOf("`", 1) !== -1,
|
|
268
441
|
_match: simpleInlineRegex(CODE_INLINE_R),
|
|
269
442
|
_order: Priority.LOW,
|
|
270
443
|
_parse(capture) {
|
|
271
|
-
return { text: unescapeString(capture[2]) };
|
|
444
|
+
return { text: unescapeString(capture[2] ?? "") };
|
|
272
445
|
},
|
|
273
446
|
_render(node, _, state = {}) {
|
|
274
447
|
return createElement("code", { key: state.key }, node.text);
|
|
275
448
|
}
|
|
276
449
|
},
|
|
277
450
|
[RuleType.footnote]: {
|
|
451
|
+
_scope: SCOPE_INLINE,
|
|
278
452
|
_qualify: ["[^"],
|
|
279
453
|
_match: blockRegex(FOOTNOTE_R),
|
|
280
454
|
_order: Priority.MAX,
|
|
281
455
|
_parse(capture) {
|
|
282
|
-
footnotes.push({
|
|
283
|
-
footnote: capture[2],
|
|
284
|
-
identifier: capture[1]
|
|
456
|
+
scope.current.footnotes.push({
|
|
457
|
+
footnote: capture[2] ?? "",
|
|
458
|
+
identifier: capture[1] ?? ""
|
|
285
459
|
});
|
|
286
460
|
return {};
|
|
287
461
|
},
|
|
288
462
|
_render: renderNothing
|
|
289
463
|
},
|
|
290
464
|
[RuleType.footnoteReference]: {
|
|
465
|
+
_scope: SCOPE_INLINE,
|
|
291
466
|
_qualify: ["[^"],
|
|
292
467
|
_match: inlineRegex(FOOTNOTE_REFERENCE_R),
|
|
293
468
|
_order: Priority.HIGH,
|
|
294
469
|
_parse(capture) {
|
|
470
|
+
const text = capture[1] ?? "";
|
|
295
471
|
return {
|
|
296
|
-
target: `#${slug(
|
|
297
|
-
text
|
|
472
|
+
target: `#${slug(text)}`,
|
|
473
|
+
text
|
|
298
474
|
};
|
|
299
475
|
},
|
|
300
476
|
_render(node, _, state = {}) {
|
|
@@ -305,11 +481,12 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
305
481
|
}
|
|
306
482
|
},
|
|
307
483
|
[RuleType.gfmTask]: {
|
|
484
|
+
_scope: SCOPE_INLINE,
|
|
308
485
|
_qualify: ["[ ]", "[x]"],
|
|
309
486
|
_match: inlineRegex(GFM_TASK_R),
|
|
310
487
|
_order: Priority.HIGH,
|
|
311
488
|
_parse(capture) {
|
|
312
|
-
return { completed: capture[1].toLowerCase() === "x" };
|
|
489
|
+
return { completed: (capture[1] ?? "").toLowerCase() === "x" };
|
|
313
490
|
},
|
|
314
491
|
_render(node, _, state = {}) {
|
|
315
492
|
return createElement("input", {
|
|
@@ -321,14 +498,16 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
321
498
|
}
|
|
322
499
|
},
|
|
323
500
|
[RuleType.heading]: {
|
|
501
|
+
_scope: SCOPE_BLOCK,
|
|
324
502
|
_qualify: ["#"],
|
|
325
503
|
_match: blockRegex(options.enforceAtxHeadings ? HEADING_ATX_COMPLIANT_R : HEADING_R),
|
|
326
504
|
_order: Priority.HIGH,
|
|
327
505
|
_parse(capture, parse, state) {
|
|
506
|
+
const text = capture[2] ?? "";
|
|
328
507
|
return {
|
|
329
|
-
children: parseInline(parse,
|
|
330
|
-
id: slug(
|
|
331
|
-
level: capture[1]
|
|
508
|
+
children: parseInline(parse, text, state),
|
|
509
|
+
id: slug(text),
|
|
510
|
+
level: capture[1]?.length ?? 1
|
|
332
511
|
};
|
|
333
512
|
},
|
|
334
513
|
_render(node, output, state = {}) {
|
|
@@ -339,7 +518,9 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
339
518
|
}
|
|
340
519
|
},
|
|
341
520
|
[RuleType.headingSetext]: {
|
|
342
|
-
|
|
521
|
+
_scope: SCOPE_BLOCK,
|
|
522
|
+
_qualify: (source, state) => {
|
|
523
|
+
if (state.prevCaptureIndent === void 0 || state.inline || state.simple) return false;
|
|
343
524
|
const nlIndex = source.indexOf("\n");
|
|
344
525
|
return nlIndex > 0 && nlIndex < source.length - 1 && (source[nlIndex + 1] === "=" || source[nlIndex + 1] === "-");
|
|
345
526
|
},
|
|
@@ -347,52 +528,15 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
347
528
|
_order: Priority.MAX,
|
|
348
529
|
_parse(capture, parse, state) {
|
|
349
530
|
return {
|
|
350
|
-
children: parseInline(parse, capture[1], state),
|
|
531
|
+
children: parseInline(parse, capture[1] ?? "", state),
|
|
351
532
|
level: capture[2] === "=" ? 1 : 2,
|
|
352
533
|
type: RuleType.heading
|
|
353
534
|
};
|
|
354
535
|
}
|
|
355
536
|
},
|
|
356
|
-
[RuleType.htmlBlock]:
|
|
357
|
-
_qualify: (source) => {
|
|
358
|
-
if (options.disableParsingRawHTML) return false;
|
|
359
|
-
const match = HTML_BLOCK_OPENING_TAG_R.exec(source);
|
|
360
|
-
if (!match) return false;
|
|
361
|
-
return getClosingTagRegex(match[1]).test(source);
|
|
362
|
-
},
|
|
363
|
-
_match: anyScopeRegex(HTML_BLOCK_ELEMENT_R),
|
|
364
|
-
_order: Priority.HIGH,
|
|
365
|
-
_parse(capture, parse, state) {
|
|
366
|
-
const whitespace = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
|
|
367
|
-
const trimmed = trimLeadingWhitespaceOutsideFences(capture[3], whitespace);
|
|
368
|
-
const parseFunc = containsBlockSyntax(trimmed) ? parseBlock : parseInline;
|
|
369
|
-
const tagName = capture[1].trim();
|
|
370
|
-
const noInnerParse = DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName.toLowerCase()) !== -1;
|
|
371
|
-
const tag = noInnerParse ? tagName.toLowerCase() : tagName;
|
|
372
|
-
const ast = {
|
|
373
|
-
attrs: attrStringToMap(tag, capture[2] ?? ""),
|
|
374
|
-
noInnerParse,
|
|
375
|
-
tag
|
|
376
|
-
};
|
|
377
|
-
state.inAnchor = state.inAnchor || tagName.toLowerCase() === "a";
|
|
378
|
-
if (noInnerParse) ast.text = capture[3];
|
|
379
|
-
else {
|
|
380
|
-
const prevInHTML = state.inHTML;
|
|
381
|
-
state.inHTML = true;
|
|
382
|
-
ast.children = parseFunc(parse, trimmed, state);
|
|
383
|
-
state.inHTML = prevInHTML;
|
|
384
|
-
}
|
|
385
|
-
state.inAnchor = false;
|
|
386
|
-
return ast;
|
|
387
|
-
},
|
|
388
|
-
_render(node, output, state = {}) {
|
|
389
|
-
return createElement(node.tag, {
|
|
390
|
-
key: state.key,
|
|
391
|
-
...node.attrs ?? {}
|
|
392
|
-
}, node.text ?? (node.children ? output(node.children, state) : ""));
|
|
393
|
-
}
|
|
394
|
-
},
|
|
537
|
+
[RuleType.htmlBlock]: pairedElementRule(matchHtmlBlockElement, Priority.HIGH, true, SCOPE_BOTH),
|
|
395
538
|
[RuleType.htmlComment]: {
|
|
539
|
+
_scope: SCOPE_BOTH,
|
|
396
540
|
_qualify: ["<!"],
|
|
397
541
|
_match: anyScopeRegex(HTML_COMMENT_R),
|
|
398
542
|
_order: Priority.HIGH,
|
|
@@ -400,14 +544,12 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
400
544
|
_render: renderNothing
|
|
401
545
|
},
|
|
402
546
|
[RuleType.htmlSelfClosing]: {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
},
|
|
407
|
-
_match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
|
|
547
|
+
_scope: SCOPE_BOTH,
|
|
548
|
+
_qualify: ["<"],
|
|
549
|
+
_match: anyScopeRegex(matchSelfClosingElement),
|
|
408
550
|
_order: Priority.HIGH,
|
|
409
551
|
_parse(capture) {
|
|
410
|
-
const tag = capture[1].trim();
|
|
552
|
+
const tag = (capture[1] ?? "").trim();
|
|
411
553
|
return {
|
|
412
554
|
attrs: attrStringToMap(tag, capture[2] || ""),
|
|
413
555
|
tag
|
|
@@ -420,34 +562,10 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
420
562
|
});
|
|
421
563
|
}
|
|
422
564
|
},
|
|
423
|
-
[RuleType.customComponent]:
|
|
424
|
-
_qualify: (source) => CUSTOM_COMPONENT_OPENING_TAG_R.test(source),
|
|
425
|
-
_match: anyScopeRegex(CUSTOM_COMPONENT_R),
|
|
426
|
-
_order: Priority.MAX,
|
|
427
|
-
_parse(capture, parse, state) {
|
|
428
|
-
const whitespace = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
|
|
429
|
-
const trimmed = trimLeadingWhitespaceOutsideFences(capture[3], whitespace);
|
|
430
|
-
const parseFunc = containsBlockSyntax(trimmed) ? parseBlock : parseInline;
|
|
431
|
-
const tag = capture[1].trim();
|
|
432
|
-
const ast = {
|
|
433
|
-
attrs: attrStringToMap(tag, capture[2] ?? ""),
|
|
434
|
-
noInnerParse: false,
|
|
435
|
-
tag
|
|
436
|
-
};
|
|
437
|
-
const prevInHTML = state.inHTML;
|
|
438
|
-
state.inHTML = true;
|
|
439
|
-
ast.children = parseFunc(parse, trimmed, state);
|
|
440
|
-
state.inHTML = prevInHTML;
|
|
441
|
-
return ast;
|
|
442
|
-
},
|
|
443
|
-
_render(node, output, state = {}) {
|
|
444
|
-
return createElement(node.tag, {
|
|
445
|
-
key: state.key,
|
|
446
|
-
...node.attrs ?? {}
|
|
447
|
-
}, node.text ?? (node.children ? output(node.children, state) : ""));
|
|
448
|
-
}
|
|
449
|
-
},
|
|
565
|
+
[RuleType.customComponent]: pairedElementRule(matchCustomComponent, Priority.MAX, false, SCOPE_BOTH),
|
|
450
566
|
[RuleType.paragraph]: {
|
|
567
|
+
_scope: SCOPE_BLOCK,
|
|
568
|
+
_qualify: (_source, state) => !state.inline && !state.simple,
|
|
451
569
|
_match: matchParagraph,
|
|
452
570
|
_order: Priority.LOW,
|
|
453
571
|
_parse: parseCaptureInline,
|
|
@@ -456,14 +574,16 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
456
574
|
}
|
|
457
575
|
},
|
|
458
576
|
[RuleType.image]: {
|
|
459
|
-
|
|
577
|
+
_scope: SCOPE_INLINE,
|
|
578
|
+
_firstChars: [33],
|
|
579
|
+
_qualify: (source) => source.startsWith(" !== -1,
|
|
460
580
|
_match: simpleInlineRegex(IMAGE_R),
|
|
461
581
|
_order: Priority.HIGH,
|
|
462
582
|
_parse(capture) {
|
|
463
583
|
return {
|
|
464
|
-
alt: unescapeString(capture[1]),
|
|
465
|
-
target: unescapeString(capture[2]),
|
|
466
|
-
title: unescapeString(capture[3])
|
|
584
|
+
alt: unescapeString(capture[1] ?? ""),
|
|
585
|
+
target: unescapeString(capture[2] ?? ""),
|
|
586
|
+
title: capture[3] ? unescapeString(capture[3]) : void 0
|
|
467
587
|
};
|
|
468
588
|
},
|
|
469
589
|
_render(node, _, state = {}) {
|
|
@@ -476,14 +596,16 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
476
596
|
}
|
|
477
597
|
},
|
|
478
598
|
[RuleType.link]: {
|
|
479
|
-
|
|
599
|
+
_scope: SCOPE_INLINE,
|
|
600
|
+
_firstChars: [91],
|
|
601
|
+
_qualify: (source) => source.charCodeAt(0) === 91 && source.indexOf("](") !== -1,
|
|
480
602
|
_match: inlineRegex(LINK_R),
|
|
481
603
|
_order: Priority.LOW,
|
|
482
604
|
_parse(capture, parse, state) {
|
|
483
605
|
return {
|
|
484
|
-
children: parseSimpleInline(parse, capture[1], state),
|
|
485
|
-
target: unescapeString(capture[2]),
|
|
486
|
-
title: unescapeString(capture[3])
|
|
606
|
+
children: parseSimpleInline(parse, capture[1] ?? "", state),
|
|
607
|
+
target: unescapeString(capture[2] ?? ""),
|
|
608
|
+
title: capture[3] ? unescapeString(capture[3]) : void 0
|
|
487
609
|
};
|
|
488
610
|
},
|
|
489
611
|
_render(node, output, state = {}) {
|
|
@@ -496,11 +618,12 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
496
618
|
}
|
|
497
619
|
},
|
|
498
620
|
[RuleType.linkAngleBraceStyleDetector]: {
|
|
621
|
+
_scope: SCOPE_INLINE,
|
|
499
622
|
_qualify: ["<"],
|
|
500
623
|
_match: inlineRegex(LINK_AUTOLINK_R),
|
|
501
624
|
_order: Priority.MAX,
|
|
502
625
|
_parse(capture) {
|
|
503
|
-
let target = capture[1];
|
|
626
|
+
let target = capture[1] ?? "";
|
|
504
627
|
let isEmail = false;
|
|
505
628
|
if (target.indexOf("@") !== -1 && target.indexOf("//") === -1) {
|
|
506
629
|
isEmail = true;
|
|
@@ -517,21 +640,26 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
517
640
|
}
|
|
518
641
|
},
|
|
519
642
|
[RuleType.linkBareUrlDetector]: {
|
|
520
|
-
|
|
643
|
+
_scope: SCOPE_INLINE,
|
|
644
|
+
_firstChars: [104],
|
|
645
|
+
_qualify: (source, state) => Boolean(state.inline && !state.inAnchor && !options.disableAutoLink && (startsWith(source, "http://") || startsWith(source, "https://"))),
|
|
521
646
|
_match: inlineRegex(LINK_AUTOLINK_BARE_URL_R),
|
|
522
647
|
_order: Priority.MAX,
|
|
523
648
|
_parse(capture) {
|
|
649
|
+
const url = capture[1] ?? "";
|
|
524
650
|
return {
|
|
525
651
|
children: [{
|
|
526
|
-
text:
|
|
652
|
+
text: url,
|
|
527
653
|
type: RuleType.text
|
|
528
654
|
}],
|
|
529
|
-
target:
|
|
655
|
+
target: url,
|
|
530
656
|
type: RuleType.link
|
|
531
657
|
};
|
|
532
658
|
}
|
|
533
659
|
},
|
|
534
660
|
[RuleType.newlineCoalescer]: {
|
|
661
|
+
_scope: SCOPE_BOTH,
|
|
662
|
+
_qualify: ["\n"],
|
|
535
663
|
_match: blockRegex(CONSECUTIVE_NEWLINE_R),
|
|
536
664
|
_order: Priority.LOW,
|
|
537
665
|
_parse: captureNothing,
|
|
@@ -542,12 +670,14 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
542
670
|
[RuleType.orderedList]: generateListRule(1),
|
|
543
671
|
[RuleType.unorderedList]: generateListRule(2),
|
|
544
672
|
[RuleType.ref]: {
|
|
673
|
+
_scope: SCOPE_BOTH,
|
|
545
674
|
_qualify: ["["],
|
|
546
675
|
_match: anyScopeRegex(REFERENCE_IMAGE_OR_LINK),
|
|
547
676
|
_order: Priority.MAX,
|
|
548
677
|
_parse(capture) {
|
|
549
|
-
|
|
550
|
-
|
|
678
|
+
const identifier = capture[1];
|
|
679
|
+
if (identifier !== void 0) scope.current.references[identifier] = {
|
|
680
|
+
target: capture[2] ?? "",
|
|
551
681
|
title: capture[4]
|
|
552
682
|
};
|
|
553
683
|
return {};
|
|
@@ -555,17 +685,19 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
555
685
|
_render: renderNothing
|
|
556
686
|
},
|
|
557
687
|
[RuleType.refImage]: {
|
|
558
|
-
|
|
688
|
+
_scope: SCOPE_INLINE,
|
|
689
|
+
_firstChars: [33],
|
|
690
|
+
_qualify: (source) => source.startsWith(" === -1,
|
|
559
691
|
_match: simpleInlineRegex(REFERENCE_IMAGE_R),
|
|
560
692
|
_order: Priority.MAX,
|
|
561
693
|
_parse(capture) {
|
|
562
694
|
return {
|
|
563
695
|
alt: capture[1] ? unescapeString(capture[1]) : void 0,
|
|
564
|
-
ref: capture[2]
|
|
696
|
+
ref: capture[2] ?? ""
|
|
565
697
|
};
|
|
566
698
|
},
|
|
567
699
|
_render(node, _, state = {}) {
|
|
568
|
-
const ref =
|
|
700
|
+
const ref = scope.current.references[node.ref];
|
|
569
701
|
if (!ref) return null;
|
|
570
702
|
return createElement("img", {
|
|
571
703
|
key: state.key,
|
|
@@ -576,18 +708,20 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
576
708
|
}
|
|
577
709
|
},
|
|
578
710
|
[RuleType.refLink]: {
|
|
579
|
-
|
|
711
|
+
_scope: SCOPE_INLINE,
|
|
712
|
+
_firstChars: [91],
|
|
713
|
+
_qualify: (source) => source.indexOf("](") === -1,
|
|
580
714
|
_match: inlineRegex(REFERENCE_LINK_R),
|
|
581
715
|
_order: Priority.MAX,
|
|
582
716
|
_parse(capture, parse, state) {
|
|
583
717
|
return {
|
|
584
|
-
children: parseSimpleInline(parse, capture[1], state),
|
|
585
|
-
fallbackChildren: capture[0],
|
|
586
|
-
ref: capture[2]
|
|
718
|
+
children: parseSimpleInline(parse, capture[1] ?? "", state),
|
|
719
|
+
fallbackChildren: capture[0] ?? "",
|
|
720
|
+
ref: capture[2] ?? ""
|
|
587
721
|
};
|
|
588
722
|
},
|
|
589
723
|
_render(node, output, state = {}) {
|
|
590
|
-
const ref =
|
|
724
|
+
const ref = scope.current.references[node.ref];
|
|
591
725
|
if (!ref) return createElement("span", { key: state.key }, node.fallbackChildren);
|
|
592
726
|
return createElement("a", {
|
|
593
727
|
key: state.key,
|
|
@@ -597,6 +731,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
597
731
|
}
|
|
598
732
|
},
|
|
599
733
|
[RuleType.table]: {
|
|
734
|
+
_scope: SCOPE_BLOCK,
|
|
600
735
|
_qualify: ["|"],
|
|
601
736
|
_match: blockRegex(NP_TABLE_R),
|
|
602
737
|
_order: Priority.HIGH,
|
|
@@ -604,7 +739,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
604
739
|
state.inline = true;
|
|
605
740
|
const align = capture[2] ? parseTableAlign(capture[2]) : [];
|
|
606
741
|
const cells = capture[3] ? parseTableCells(capture[3], parse, state) : [];
|
|
607
|
-
const header = parseTableRow(capture[1], parse, state, !!cells.length);
|
|
742
|
+
const header = parseTableRow(capture[1] ?? "", parse, state, !!cells.length);
|
|
608
743
|
state.inline = false;
|
|
609
744
|
return cells.length ? {
|
|
610
745
|
align,
|
|
@@ -619,17 +754,19 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
619
754
|
_render(node, output, state = {}) {
|
|
620
755
|
const table = node;
|
|
621
756
|
const getStyle = (i) => table.align[i] && table.align[i] !== "left" ? { textAlign: table.align[i] } : {};
|
|
622
|
-
return createElement("table", { key: state.key }, createElement("thead",
|
|
757
|
+
return createElement("table", { key: state.key }, createElement("thead", { key: "thead" }, createElement("tr", null, ...table.header.map((c, i) => createElement("th", {
|
|
623
758
|
key: i,
|
|
624
759
|
style: getStyle(i)
|
|
625
|
-
}, output(c, state))))), createElement("tbody",
|
|
760
|
+
}, output(c, state))))), createElement("tbody", { key: "tbody" }, ...table.cells.map((row, i) => createElement("tr", { key: i }, ...row.map((c, j) => createElement("td", {
|
|
626
761
|
key: j,
|
|
627
762
|
style: getStyle(j)
|
|
628
763
|
}, output(c, state)))))));
|
|
629
764
|
}
|
|
630
765
|
},
|
|
631
766
|
[RuleType.tableSeparator]: {
|
|
632
|
-
|
|
767
|
+
_scope: SCOPE_INLINE,
|
|
768
|
+
_qualify: ["|"],
|
|
769
|
+
_match: (source, state) => state.inTable ? /^\|/.exec(source) : null,
|
|
633
770
|
_order: Priority.HIGH,
|
|
634
771
|
_parse() {
|
|
635
772
|
return { type: RuleType.tableSeparator };
|
|
@@ -639,90 +776,180 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
|
|
|
639
776
|
}
|
|
640
777
|
},
|
|
641
778
|
[RuleType.text]: {
|
|
779
|
+
_scope: SCOPE_INLINE,
|
|
642
780
|
_match: allowInline((source, _state) => {
|
|
643
|
-
const
|
|
644
|
-
if (
|
|
645
|
-
|
|
781
|
+
const len = source.length;
|
|
782
|
+
if (source.charCodeAt(0) === 10) {
|
|
783
|
+
let j = 1;
|
|
784
|
+
while (j < len && source.charCodeAt(j) === 32) j++;
|
|
785
|
+
if (j < len && (source.charCodeAt(j) === 42 || source.charCodeAt(j) === 43 || source.charCodeAt(j) === 45 || source.charCodeAt(j) >= 48 && source.charCodeAt(j) <= 57)) return [source.slice(0, j)];
|
|
786
|
+
return ["\n"];
|
|
787
|
+
}
|
|
788
|
+
if (source.charCodeAt(0) === 58) {
|
|
789
|
+
const shortMatch = SHORTCODE_R.exec(source);
|
|
790
|
+
if (shortMatch) return shortMatch;
|
|
791
|
+
}
|
|
792
|
+
TEXT_RUN_R.lastIndex = 1;
|
|
793
|
+
TEXT_RUN_R.test(source);
|
|
794
|
+
TEXT_CAPTURE[0] = source.slice(0, trimHardBreak(source, TEXT_RUN_R.lastIndex));
|
|
795
|
+
return TEXT_CAPTURE;
|
|
646
796
|
}),
|
|
647
797
|
_order: Priority.MIN,
|
|
648
798
|
_parse(capture) {
|
|
649
|
-
const text = capture[0];
|
|
650
|
-
return {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
799
|
+
const text = capture[0] ?? "";
|
|
800
|
+
return {
|
|
801
|
+
type: RuleType.text,
|
|
802
|
+
text: text.charCodeAt(0) !== 38 ? text : text.replace(HTML_CHAR_CODE_R, (f, i) => {
|
|
803
|
+
if (i.startsWith("#x")) return String.fromCharCode(parseInt(i.slice(2), 16));
|
|
804
|
+
if (i.startsWith("#")) return String.fromCharCode(parseInt(i.slice(1), 10));
|
|
805
|
+
return namedCodesToUnicode[i] || f;
|
|
806
|
+
})
|
|
807
|
+
};
|
|
655
808
|
},
|
|
656
809
|
_render(node) {
|
|
657
810
|
return node.text;
|
|
658
811
|
}
|
|
659
812
|
},
|
|
660
813
|
[RuleType.textBolded]: {
|
|
661
|
-
|
|
814
|
+
_scope: SCOPE_INLINE,
|
|
815
|
+
_firstChars: [42, 95],
|
|
816
|
+
_qualify: (source) => {
|
|
817
|
+
const c = source.charCodeAt(0);
|
|
818
|
+
if (c === 42) {
|
|
819
|
+
const next = source.charCodeAt(2);
|
|
820
|
+
if (next === 32 || next === 10 || next === 9) return false;
|
|
821
|
+
return source.charCodeAt(1) === 42 && source.indexOf("**", 2) !== -1;
|
|
822
|
+
}
|
|
823
|
+
if (c === 95) {
|
|
824
|
+
const next = source.charCodeAt(2);
|
|
825
|
+
if (next === 32 || next === 10 || next === 9) return false;
|
|
826
|
+
return source.charCodeAt(1) === 95 && source.indexOf("__", 2) !== -1;
|
|
827
|
+
}
|
|
828
|
+
return false;
|
|
829
|
+
},
|
|
662
830
|
_match: simpleInlineRegex(TEXT_BOLD_R),
|
|
663
831
|
_order: Priority.MED,
|
|
664
832
|
_parse(capture, parse, state) {
|
|
665
|
-
return { children: parse(capture[2], state) };
|
|
833
|
+
return { children: parse(capture[2] ?? "", state) };
|
|
666
834
|
},
|
|
667
835
|
_render(node, output, state = {}) {
|
|
668
836
|
return createElement("strong", { key: state.key }, output(node.children, state));
|
|
669
837
|
}
|
|
670
838
|
},
|
|
671
839
|
[RuleType.textEmphasized]: {
|
|
672
|
-
|
|
840
|
+
_scope: SCOPE_INLINE,
|
|
841
|
+
_firstChars: [42, 95],
|
|
842
|
+
_qualify: (source) => {
|
|
843
|
+
const c = source.charCodeAt(0);
|
|
844
|
+
const next = source.charCodeAt(1);
|
|
845
|
+
if (next === 32 || next === 10 || next === 9) return false;
|
|
846
|
+
return c === 42 && source.indexOf("*", 1) !== -1 || c === 95 && source.indexOf("_", 1) !== -1;
|
|
847
|
+
},
|
|
673
848
|
_match: simpleInlineRegex(TEXT_EMPHASIZED_R),
|
|
674
849
|
_order: Priority.LOW,
|
|
675
850
|
_parse(capture, parse, state) {
|
|
676
|
-
return { children: parse(capture[2], state) };
|
|
851
|
+
return { children: parse(capture[2] ?? "", state) };
|
|
677
852
|
},
|
|
678
853
|
_render(node, output, state = {}) {
|
|
679
854
|
return createElement("em", { key: state.key }, output(node.children, state));
|
|
680
855
|
}
|
|
681
856
|
},
|
|
682
857
|
[RuleType.textEscaped]: {
|
|
858
|
+
_scope: SCOPE_INLINE,
|
|
683
859
|
_qualify: ["\\"],
|
|
684
860
|
_match: simpleInlineRegex(TEXT_ESCAPED_R),
|
|
685
861
|
_order: Priority.HIGH,
|
|
686
862
|
_parse(capture) {
|
|
687
863
|
return {
|
|
688
|
-
text: capture[1],
|
|
864
|
+
text: capture[1] ?? "",
|
|
689
865
|
type: RuleType.text
|
|
690
866
|
};
|
|
691
867
|
}
|
|
692
868
|
},
|
|
693
869
|
[RuleType.textMarked]: {
|
|
694
|
-
|
|
870
|
+
_scope: SCOPE_INLINE,
|
|
871
|
+
_firstChars: [61],
|
|
872
|
+
_qualify: (source) => {
|
|
873
|
+
const next = source.charCodeAt(2);
|
|
874
|
+
if (next === 32 || next === 10 || next === 9) return false;
|
|
875
|
+
return source.charCodeAt(1) === 61 && source.indexOf("==", 2) !== -1;
|
|
876
|
+
},
|
|
695
877
|
_match: simpleInlineRegex(TEXT_MARKED_R),
|
|
696
878
|
_order: Priority.LOW,
|
|
697
|
-
_parse
|
|
879
|
+
_parse(capture, parse, state) {
|
|
880
|
+
return { children: parseCaptureInline(capture, parse, state).children };
|
|
881
|
+
},
|
|
698
882
|
_render(node, output, state = {}) {
|
|
699
883
|
return createElement("mark", { key: state.key }, output(node.children, state));
|
|
700
884
|
}
|
|
701
885
|
},
|
|
702
886
|
[RuleType.textStrikethroughed]: {
|
|
703
|
-
|
|
887
|
+
_scope: SCOPE_INLINE,
|
|
888
|
+
_firstChars: [126],
|
|
889
|
+
_qualify: (source) => {
|
|
890
|
+
const next = source.charCodeAt(2);
|
|
891
|
+
if (next === 32 || next === 10 || next === 9) return false;
|
|
892
|
+
return source.charCodeAt(1) === 126 && source.indexOf("~~", 2) !== -1;
|
|
893
|
+
},
|
|
704
894
|
_match: simpleInlineRegex(TEXT_STRIKETHROUGHED_R),
|
|
705
895
|
_order: Priority.LOW,
|
|
706
|
-
_parse
|
|
896
|
+
_parse(capture, parse, state) {
|
|
897
|
+
return { children: parseCaptureInline(capture, parse, state).children };
|
|
898
|
+
},
|
|
707
899
|
_render(node, output, state = {}) {
|
|
708
900
|
return createElement("del", { key: state.key }, output(node.children, state));
|
|
709
901
|
}
|
|
710
902
|
}
|
|
711
903
|
};
|
|
712
904
|
};
|
|
905
|
+
const STRIP_INDENT_REGEXES = [
|
|
906
|
+
null,
|
|
907
|
+
/^ {1,1}/gm,
|
|
908
|
+
/^ {1,2}/gm,
|
|
909
|
+
/^ {1,3}/gm,
|
|
910
|
+
/^ {1,4}/gm,
|
|
911
|
+
/^ {1,5}/gm,
|
|
912
|
+
/^ {1,6}/gm,
|
|
913
|
+
/^ {1,7}/gm,
|
|
914
|
+
/^ {1,8}/gm
|
|
915
|
+
];
|
|
916
|
+
/** Scratch capture reused by the text rule; see its `_match`. */
|
|
917
|
+
const TEXT_CAPTURE = [""];
|
|
713
918
|
/**
|
|
714
|
-
*
|
|
715
|
-
*
|
|
919
|
+
* Consumes a run of plain text, stopping before the next character that could
|
|
920
|
+
* open another inline rule or a bare URL. Anchored so `test` leaves the stop
|
|
921
|
+
* offset in `lastIndex` without allocating a match array, and so the scan
|
|
922
|
+
* itself runs in the regex engine.
|
|
923
|
+
*
|
|
924
|
+
* The bare-URL guard is an alternation branch rather than a per-character
|
|
925
|
+
* lookahead, because a lookahead is re-evaluated at every offset while this
|
|
926
|
+
* branch is only reached on an `h`. `&` stops a run purely so that an HTML
|
|
927
|
+
* entity can only ever sit at offset 0 of a text node; adjacent text nodes are
|
|
928
|
+
* merged by the parser, so the tree is unchanged.
|
|
716
929
|
*/
|
|
717
|
-
const
|
|
930
|
+
const TEXT_RUN_R = /(?:[^\n&h!*:<=[\\_`~]+|h(?!ttp))*/y;
|
|
931
|
+
/**
|
|
932
|
+
* Pull a run's stop offset back before a hard line break it just swallowed.
|
|
933
|
+
*
|
|
934
|
+
* A run never contains a newline, so ` \n` can only sit immediately before the
|
|
935
|
+
* stop offset — which makes this O(1) check equivalent to the per-character
|
|
936
|
+
* `(?! {2}\n)` lookahead the run scanner used to carry.
|
|
937
|
+
*/
|
|
938
|
+
const trimHardBreak = (source, end) => end >= 3 && source.charCodeAt(end) === 10 && source.charCodeAt(end - 1) === 32 && source.charCodeAt(end - 2) === 32 ? end - 2 : end;
|
|
939
|
+
const noopCreateElement = (type, props, ...children) => ({
|
|
940
|
+
children,
|
|
941
|
+
props,
|
|
942
|
+
type
|
|
943
|
+
});
|
|
718
944
|
/**
|
|
719
945
|
* Builds the rule set backing one document.
|
|
720
946
|
*
|
|
721
|
-
* Rules
|
|
722
|
-
*
|
|
723
|
-
*
|
|
947
|
+
* Rules read the document's footnote and reference tables through `scope`
|
|
948
|
+
* rather than closing over them, so one set serves every document sharing the
|
|
949
|
+
* same options. Building this graph dominated the cost of compiling the many
|
|
950
|
+
* short strings a dictionary holds; `getRuleSet` caches it.
|
|
724
951
|
*/
|
|
725
|
-
const createDocumentRules = (createElement, ctx, options,
|
|
952
|
+
const createDocumentRules = (createElement, ctx, options, scope) => {
|
|
726
953
|
const attrStringToMap = (tag, str) => {
|
|
727
954
|
if (!str?.trim()) return null;
|
|
728
955
|
const attributes = str.match(ATTR_EXTRACTOR_R);
|
|
@@ -735,7 +962,7 @@ const createDocumentRules = (createElement, ctx, options, footnotes, refs) => {
|
|
|
735
962
|
const mappedKey = ATTRIBUTE_TO_NODE_PROP_MAP[key] ?? key;
|
|
736
963
|
if (mappedKey === "ref") return map;
|
|
737
964
|
map[mappedKey] = attributeValueToNodePropValue(tag, key, value, ctx.sanitizer ?? sanitizer);
|
|
738
|
-
if (typeof map[mappedKey] === "string" && (
|
|
965
|
+
if (typeof map[mappedKey] === "string" && startsWithElement(map[mappedKey])) map[mappedKey] = parseMarkdown(map[mappedKey].trim(), ctx, options).ast;
|
|
739
966
|
} else if (raw !== "style") map[ATTRIBUTE_TO_NODE_PROP_MAP[raw] ?? raw] = true;
|
|
740
967
|
return map;
|
|
741
968
|
}, {});
|
|
@@ -745,19 +972,18 @@ const createDocumentRules = (createElement, ctx, options, footnotes, refs) => {
|
|
|
745
972
|
CODE_BLOCK_FENCED_R,
|
|
746
973
|
CODE_BLOCK_R,
|
|
747
974
|
options.enforceAtxHeadings ? HEADING_ATX_COMPLIANT_R : HEADING_R,
|
|
748
|
-
HEADING_SETEXT_R,
|
|
749
975
|
NP_TABLE_R,
|
|
750
976
|
ORDERED_LIST_R,
|
|
751
977
|
UNORDERED_LIST_R,
|
|
752
|
-
|
|
978
|
+
startsWithCustomComponent
|
|
753
979
|
];
|
|
754
980
|
const blockSyntaxes = options.disableParsingRawHTML ? nonParagraphBlockSyntaxes : [
|
|
755
981
|
...nonParagraphBlockSyntaxes,
|
|
756
982
|
PARAGRAPH_R,
|
|
757
|
-
|
|
983
|
+
startsWithHtmlBlockElement,
|
|
758
984
|
HTML_COMMENT_R,
|
|
759
|
-
|
|
760
|
-
|
|
985
|
+
startsWithSelfClosingElement,
|
|
986
|
+
startsWithCustomComponent
|
|
761
987
|
];
|
|
762
988
|
const containsBlockSyntax = (input) => {
|
|
763
989
|
const cleaned = input.replace(TRIM_STARTING_NEWLINES, "");
|
|
@@ -765,17 +991,16 @@ const createDocumentRules = (createElement, ctx, options, footnotes, refs) => {
|
|
|
765
991
|
if (slice.indexOf("\n\n") !== -1) return true;
|
|
766
992
|
return some(blockSyntaxes, slice);
|
|
767
993
|
};
|
|
768
|
-
const baseRules = createRules(createElement, ctx, options,
|
|
994
|
+
const baseRules = createRules(createElement, ctx, options, scope, attrStringToMap, containsBlockSyntax, nonParagraphBlockSyntaxes);
|
|
769
995
|
return options.disableParsingRawHTML ? Object.keys(baseRules).reduce((acc, key) => {
|
|
770
996
|
if (key !== RuleType.htmlBlock && key !== RuleType.htmlSelfClosing) acc[key] = baseRules[key];
|
|
771
997
|
return acc;
|
|
772
998
|
}, {}) : baseRules;
|
|
773
999
|
};
|
|
774
1000
|
/** Runs the parse phase against an already-built rule set. */
|
|
775
|
-
const parseWithRules = (markdown, options,
|
|
776
|
-
const
|
|
777
|
-
const
|
|
778
|
-
const trimmedStart = result.replace(TRIM_STARTING_NEWLINES, "");
|
|
1001
|
+
const parseWithRules = (markdown, options, parser, footnotes, refs) => {
|
|
1002
|
+
const result = !options.preserveFrontmatter && markdown.charCodeAt(0) === 45 ? markdown.replace(FRONT_MATTER_R, "") : markdown;
|
|
1003
|
+
const trimmedStart = result.charCodeAt(0) === 10 ? result.replace(TRIM_STARTING_NEWLINES, "") : result;
|
|
779
1004
|
const inline = options.forceInline || !options.forceBlock && SHOULD_RENDER_AS_BLOCK_R.test(trimmedStart) === false;
|
|
780
1005
|
const ast = parser(inline ? result : `${trimEnd(trimmedStart)}\n\n`, { inline });
|
|
781
1006
|
if (footnotes.length > 0) for (const def of footnotes) def.parsedAst = parser(def.footnote, { inline: true });
|
|
@@ -787,11 +1012,10 @@ const parseWithRules = (markdown, options, rules, footnotes, refs) => {
|
|
|
787
1012
|
};
|
|
788
1013
|
};
|
|
789
1014
|
/** Runs the render phase against an already-built rule set. */
|
|
790
|
-
const renderWithRules = (parsed, ctx, options,
|
|
1015
|
+
const renderWithRules = (parsed, ctx, options, emitter, createElement) => {
|
|
791
1016
|
const components = ctx.components ?? {};
|
|
792
1017
|
const slug = createSlugger(ctx);
|
|
793
1018
|
const footnotes = parsed.footnotes || [];
|
|
794
|
-
const emitter = renderFor(createRenderer(rules, options.renderRule));
|
|
795
1019
|
const inline = parsed.inline;
|
|
796
1020
|
const arr = emitter(parsed.ast, { inline });
|
|
797
1021
|
while (typeof arr[arr.length - 1] === "string" && !arr[arr.length - 1].trim()) arr.pop();
|
|
@@ -801,6 +1025,7 @@ const renderWithRules = (parsed, ctx, options, rules, createElement) => {
|
|
|
801
1025
|
if (arr.length > 1 || options.forceWrapper) return createElement(wrapper, { key: "outer" }, arr);
|
|
802
1026
|
if (arr.length === 1) {
|
|
803
1027
|
const node = arr[0];
|
|
1028
|
+
if (Array.isArray(node)) return createElement(wrapper, { key: "outer" }, node);
|
|
804
1029
|
if (typeof node === "string") {
|
|
805
1030
|
const spanProps = { key: "outer" };
|
|
806
1031
|
if (!inline && components) {
|
|
@@ -826,27 +1051,29 @@ const renderWithRules = (parsed, ctx, options, rules, createElement) => {
|
|
|
826
1051
|
}, def.identifier, emitter(def.parsedAst || def.footnote, { inline: true }))))) : node;
|
|
827
1052
|
};
|
|
828
1053
|
const parseMarkdown = (markdown = "", ctx, options = {}) => {
|
|
829
|
-
const
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
return parseWithRules(markdown, options, rules, footnotes, refs);
|
|
1054
|
+
const { parse, scope } = getRuleSet(ctx, options, true);
|
|
1055
|
+
const documentScope = createDocumentScope();
|
|
1056
|
+
return withDocumentScope(scope, documentScope, () => parseWithRules(markdown, options, parse, documentScope.footnotes, documentScope.references));
|
|
833
1057
|
};
|
|
834
1058
|
const renderMarkdownAst = (parsed, ctx, options = {}) => {
|
|
835
|
-
const createElement =
|
|
836
|
-
const
|
|
837
|
-
|
|
1059
|
+
const { emit, createElement, scope } = getRuleSet(ctx, options, false);
|
|
1060
|
+
const documentScope = {
|
|
1061
|
+
footnotes: parsed.footnotes ?? [],
|
|
1062
|
+
references: parsed.references ?? {}
|
|
1063
|
+
};
|
|
1064
|
+
return withDocumentScope(scope, documentScope, () => renderWithRules(parsed, ctx, options, emit, createElement));
|
|
838
1065
|
};
|
|
839
1066
|
const compile = (markdown = "", ctx, options = {}) => {
|
|
840
1067
|
if (typeof markdown !== "string") {
|
|
841
1068
|
console.error("intlayer: the first argument must be a string. Received", typeof markdown);
|
|
842
1069
|
throw new Error("intlayer: the first argument must be a string");
|
|
843
1070
|
}
|
|
844
|
-
const
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1071
|
+
const { parse, emit, createElement, scope } = getRuleSet(ctx, options, false);
|
|
1072
|
+
const documentScope = createDocumentScope();
|
|
1073
|
+
return withDocumentScope(scope, documentScope, () => {
|
|
1074
|
+
const parsed = parseWithRules(markdown, options, parse, documentScope.footnotes, documentScope.references);
|
|
1075
|
+
return renderWithRules(parsed, ctx, options, emit, createElement);
|
|
1076
|
+
});
|
|
850
1077
|
};
|
|
851
1078
|
const createCompiler = (ctx) => (markdown, options) => compile(markdown, ctx, options);
|
|
852
1079
|
const compileWithOptions = (markdown, runtime, options = {}) => {
|
|
@@ -861,5 +1088,5 @@ const compileWithOptions = (markdown, runtime, options = {}) => {
|
|
|
861
1088
|
};
|
|
862
1089
|
|
|
863
1090
|
//#endregion
|
|
864
|
-
export { compile, compileWithOptions, createCompiler, parseMarkdown, renderMarkdownAst };
|
|
1091
|
+
export { compile, compileWithOptions, createCompiler, getRuleSet, parseMarkdown, renderMarkdownAst };
|
|
865
1092
|
//# sourceMappingURL=compiler.mjs.map
|