@readme/markdown 14.11.5 → 14.12.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/components/HTMLBlock/index.tsx +12 -10
- package/dist/main.js +1883 -1748
- package/dist/main.node.js +1882 -1747
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/components/mdx-blocks.d.ts +4 -0
- package/dist/processor/transform/mdxish/components/utils.d.ts +13 -1
- package/dist/processor/transform/mdxish/mdxish-html-blocks.d.ts +7 -6
- package/dist/processor/transform/mdxish/normalize-closing-tag-whitespace.d.ts +13 -0
- package/dist/render-fixture.node.js +1417 -1282
- package/dist/render-fixture.node.js.map +1 -1
- package/package.json +2 -2
package/dist/main.node.js
CHANGED
|
@@ -24839,17 +24839,12 @@ const extractScripts = (html = '') => {
|
|
|
24839
24839
|
return [cleaned, () => scripts.map(js => window.eval(js))];
|
|
24840
24840
|
};
|
|
24841
24841
|
const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeModeRaw = false }) => {
|
|
24842
|
-
// Determine HTML source: MDXish uses html prop (from HAST), MDX uses children
|
|
24843
|
-
|
|
24844
|
-
|
|
24845
|
-
|
|
24846
|
-
|
|
24847
|
-
|
|
24848
|
-
if (typeof children !== 'string') {
|
|
24849
|
-
throw new TypeError('HTMLBlock: children must be a string');
|
|
24850
|
-
}
|
|
24851
|
-
html = children;
|
|
24852
|
-
}
|
|
24842
|
+
// Determine HTML source: MDXish uses html prop (from HAST), MDX uses children.
|
|
24843
|
+
// A non-string child (no html prop) can't be injected as raw HTML — see the
|
|
24844
|
+
// fail-soft fallback below.
|
|
24845
|
+
const htmlSource = htmlProp !== undefined ? htmlProp : children;
|
|
24846
|
+
const nonStringChildren = typeof htmlSource !== 'string';
|
|
24847
|
+
const html = nonStringChildren ? '' : htmlSource;
|
|
24853
24848
|
// eslint-disable-next-line no-param-reassign
|
|
24854
24849
|
runScripts = typeof runScripts !== 'boolean' ? runScripts === 'true' : runScripts;
|
|
24855
24850
|
// In MDX mode, safeMode is passed in as a boolean from JSX parsing
|
|
@@ -24860,6 +24855,11 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
|
|
|
24860
24855
|
if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
|
|
24861
24856
|
exec();
|
|
24862
24857
|
}, [runScripts, exec]);
|
|
24858
|
+
if (nonStringChildren) {
|
|
24859
|
+
// Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
|
|
24860
|
+
// raw string) should never throw, so render the child nodes directly
|
|
24861
|
+
return external_react_default().createElement("div", { className: "rdmd-html" }, children);
|
|
24862
|
+
}
|
|
24863
24863
|
if (safeMode) {
|
|
24864
24864
|
return (external_react_default().createElement("pre", { className: "html-unsafe" },
|
|
24865
24865
|
external_react_default().createElement("code", null, html)));
|
|
@@ -96670,6 +96670,9 @@ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
|
|
|
96670
96670
|
* Uses `walkTags` so `<table>`s inside code spans / fenced blocks (masked away)
|
|
96671
96671
|
* are never matched.
|
|
96672
96672
|
*
|
|
96673
|
+
* `<table>`s inside an `<HTMLBlock>` body are also ignored: that body is opaque
|
|
96674
|
+
* raw HTML, so lifting a table out of it would corrupt the block.
|
|
96675
|
+
*
|
|
96673
96676
|
* Note: An implicitly-closed table (no `</table>`, so htmlparser2 synthesizes the
|
|
96674
96677
|
* close at a later tag) is skipped: splitting there would swallow whatever
|
|
96675
96678
|
* followed the table into the fragment and drop it, so we leave such a node
|
|
@@ -96677,21 +96680,35 @@ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
|
|
|
96677
96680
|
*/
|
|
96678
96681
|
const findTableRanges = (html) => {
|
|
96679
96682
|
const ranges = [];
|
|
96680
|
-
let
|
|
96683
|
+
let tableDepth = 0;
|
|
96684
|
+
let htmlBlockDepth = 0;
|
|
96681
96685
|
let start = 0;
|
|
96682
96686
|
walkTags(html, {
|
|
96683
|
-
onOpen: ({ name, start: openStart, isStrayCloser }) => {
|
|
96684
|
-
if (
|
|
96687
|
+
onOpen: ({ name, start: openStart, isSelfClosing, isStrayCloser }) => {
|
|
96688
|
+
if (isStrayCloser)
|
|
96685
96689
|
return;
|
|
96686
|
-
|
|
96690
|
+
// `<HTMLBlock/>` has no body to protect; only a real open enters one.
|
|
96691
|
+
if (name === 'HTMLBlock') {
|
|
96692
|
+
if (!isSelfClosing)
|
|
96693
|
+
htmlBlockDepth += 1;
|
|
96694
|
+
return;
|
|
96695
|
+
}
|
|
96696
|
+
if (htmlBlockDepth > 0 || name.toLowerCase() !== 'table')
|
|
96697
|
+
return;
|
|
96698
|
+
if (tableDepth === 0)
|
|
96687
96699
|
start = openStart;
|
|
96688
|
-
|
|
96700
|
+
tableDepth += 1;
|
|
96689
96701
|
},
|
|
96690
96702
|
onClose: ({ name, end, implicit }) => {
|
|
96691
|
-
if (
|
|
96703
|
+
if (name === 'HTMLBlock') {
|
|
96704
|
+
if (!implicit && htmlBlockDepth > 0)
|
|
96705
|
+
htmlBlockDepth -= 1;
|
|
96692
96706
|
return;
|
|
96693
|
-
|
|
96694
|
-
if (
|
|
96707
|
+
}
|
|
96708
|
+
if (implicit || htmlBlockDepth > 0 || name.toLowerCase() !== 'table' || tableDepth === 0)
|
|
96709
|
+
return;
|
|
96710
|
+
tableDepth -= 1;
|
|
96711
|
+
if (tableDepth === 0)
|
|
96695
96712
|
ranges.push({ start, end });
|
|
96696
96713
|
},
|
|
96697
96714
|
});
|
|
@@ -96711,7 +96728,9 @@ const splitHtmlWithNestedTables = (node) => {
|
|
|
96711
96728
|
// This is a top-level table, so we don't need to split it
|
|
96712
96729
|
if (TOP_LEVEL_TABLE_TAG_RE.test(value))
|
|
96713
96730
|
return null;
|
|
96714
|
-
// No table text anywhere
|
|
96731
|
+
// No table text anywhere → skip the htmlparser2 walk entirely. (A `<table>` that
|
|
96732
|
+
// only appears inside an `<HTMLBlock>` body still yields no ranges below, so it's
|
|
96733
|
+
// left whole for `mdxishHtmlBlocks` to convert to an html-block next.)
|
|
96715
96734
|
if (!/<\/?table/i.test(value))
|
|
96716
96735
|
return null;
|
|
96717
96736
|
const ranges = findTableRanges(value);
|
|
@@ -119873,6 +119892,55 @@ function emptyTaskListItemFromMarkdown() {
|
|
|
119873
119892
|
};
|
|
119874
119893
|
}
|
|
119875
119894
|
|
|
119895
|
+
;// ./lib/mdast-util/jsx-table/index.ts
|
|
119896
|
+
const jsx_table_contextMap = new WeakMap();
|
|
119897
|
+
function findJsxTableToken() {
|
|
119898
|
+
const events = this.tokenStack;
|
|
119899
|
+
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
119900
|
+
if (events[i][0].type === 'jsxTable')
|
|
119901
|
+
return events[i][0];
|
|
119902
|
+
}
|
|
119903
|
+
return undefined;
|
|
119904
|
+
}
|
|
119905
|
+
function enterJsxTable(token) {
|
|
119906
|
+
jsx_table_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
|
|
119907
|
+
this.enter({ type: 'html', value: '' }, token);
|
|
119908
|
+
}
|
|
119909
|
+
function exitJsxTableData(token) {
|
|
119910
|
+
const tableToken = findJsxTableToken.call(this);
|
|
119911
|
+
if (!tableToken)
|
|
119912
|
+
return;
|
|
119913
|
+
const ctx = jsx_table_contextMap.get(tableToken);
|
|
119914
|
+
if (ctx) {
|
|
119915
|
+
const gap = token.start.line - ctx.lastEndLine;
|
|
119916
|
+
if (ctx.chunks.length > 0 && gap > 0) {
|
|
119917
|
+
ctx.chunks.push('\n'.repeat(gap));
|
|
119918
|
+
}
|
|
119919
|
+
ctx.chunks.push(this.sliceSerialize(token));
|
|
119920
|
+
ctx.lastEndLine = token.end.line;
|
|
119921
|
+
}
|
|
119922
|
+
}
|
|
119923
|
+
function exitJsxTable(token) {
|
|
119924
|
+
const ctx = jsx_table_contextMap.get(token);
|
|
119925
|
+
const node = this.stack[this.stack.length - 1];
|
|
119926
|
+
if (ctx) {
|
|
119927
|
+
node.value = ctx.chunks.join('');
|
|
119928
|
+
jsx_table_contextMap.delete(token);
|
|
119929
|
+
}
|
|
119930
|
+
this.exit(token);
|
|
119931
|
+
}
|
|
119932
|
+
function jsxTableFromMarkdown() {
|
|
119933
|
+
return {
|
|
119934
|
+
enter: {
|
|
119935
|
+
jsxTable: enterJsxTable,
|
|
119936
|
+
},
|
|
119937
|
+
exit: {
|
|
119938
|
+
jsxTableData: exitJsxTableData,
|
|
119939
|
+
jsxTable: exitJsxTable,
|
|
119940
|
+
},
|
|
119941
|
+
};
|
|
119942
|
+
}
|
|
119943
|
+
|
|
119876
119944
|
;// ./lib/mdast-util/magic-block/index.ts
|
|
119877
119945
|
const magic_block_contextMap = new WeakMap();
|
|
119878
119946
|
/**
|
|
@@ -120062,867 +120130,16 @@ function mdxComponentFromMarkdown() {
|
|
|
120062
120130
|
};
|
|
120063
120131
|
}
|
|
120064
120132
|
|
|
120065
|
-
;// ./
|
|
120066
|
-
|
|
120067
|
-
|
|
120068
|
-
/**
|
|
120069
|
-
* Known magic block types that the tokenizer will recognize.
|
|
120070
|
-
* Unknown types will not be tokenized as magic blocks.
|
|
120071
|
-
*/
|
|
120072
|
-
const KNOWN_BLOCK_TYPES = new Set([
|
|
120073
|
-
'code',
|
|
120074
|
-
'api-header',
|
|
120075
|
-
'image',
|
|
120076
|
-
'callout',
|
|
120077
|
-
'parameters',
|
|
120078
|
-
'table',
|
|
120079
|
-
'embed',
|
|
120080
|
-
'html',
|
|
120081
|
-
'recipe',
|
|
120082
|
-
'tutorial-tile',
|
|
120083
|
-
]);
|
|
120084
|
-
/**
|
|
120085
|
-
* Check if a character is valid for a magic block type identifier.
|
|
120086
|
-
* Types can contain alphanumeric characters and hyphens (e.g., "api-header", "tutorial-tile")
|
|
120087
|
-
*/
|
|
120088
|
-
function isTypeChar(code) {
|
|
120089
|
-
return asciiAlphanumeric(code) || code === codes.dash;
|
|
120090
|
-
}
|
|
120091
|
-
/**
|
|
120092
|
-
* Creates the opening marker state machine: [block:
|
|
120093
|
-
* Returns the first state function to start parsing.
|
|
120094
|
-
*/
|
|
120095
|
-
function createOpeningMarkerParser(effects, nok, onComplete) {
|
|
120096
|
-
const expectB = (code) => {
|
|
120097
|
-
if (code !== codes.lowercaseB)
|
|
120098
|
-
return nok(code);
|
|
120099
|
-
effects.consume(code);
|
|
120100
|
-
return expectL;
|
|
120101
|
-
};
|
|
120102
|
-
const expectL = (code) => {
|
|
120103
|
-
if (code !== codes.lowercaseL)
|
|
120104
|
-
return nok(code);
|
|
120105
|
-
effects.consume(code);
|
|
120106
|
-
return expectO;
|
|
120107
|
-
};
|
|
120108
|
-
const expectO = (code) => {
|
|
120109
|
-
if (code !== codes.lowercaseO)
|
|
120110
|
-
return nok(code);
|
|
120111
|
-
effects.consume(code);
|
|
120112
|
-
return expectC;
|
|
120113
|
-
};
|
|
120114
|
-
const expectC = (code) => {
|
|
120115
|
-
if (code !== codes.lowercaseC)
|
|
120116
|
-
return nok(code);
|
|
120117
|
-
effects.consume(code);
|
|
120118
|
-
return expectK;
|
|
120119
|
-
};
|
|
120120
|
-
const expectK = (code) => {
|
|
120121
|
-
if (code !== codes.lowercaseK)
|
|
120122
|
-
return nok(code);
|
|
120123
|
-
effects.consume(code);
|
|
120124
|
-
return expectColon;
|
|
120125
|
-
};
|
|
120126
|
-
const expectColon = (code) => {
|
|
120127
|
-
if (code !== codes.colon)
|
|
120128
|
-
return nok(code);
|
|
120129
|
-
effects.consume(code);
|
|
120130
|
-
effects.exit('magicBlockMarkerStart');
|
|
120131
|
-
effects.enter('magicBlockType');
|
|
120132
|
-
return onComplete;
|
|
120133
|
-
};
|
|
120134
|
-
return expectB;
|
|
120135
|
-
}
|
|
120136
|
-
/**
|
|
120137
|
-
* Creates the type capture state machine.
|
|
120138
|
-
* Captures type characters until ] and validates against known types.
|
|
120139
|
-
*/
|
|
120140
|
-
function createTypeCaptureParser(effects, nok, onComplete, blockTypeRef) {
|
|
120141
|
-
const captureTypeFirst = (code) => {
|
|
120142
|
-
// Reject empty type name [block:]
|
|
120143
|
-
if (code === codes.rightSquareBracket) {
|
|
120144
|
-
return nok(code);
|
|
120145
|
-
}
|
|
120146
|
-
if (isTypeChar(code)) {
|
|
120147
|
-
blockTypeRef.value += String.fromCharCode(code);
|
|
120148
|
-
effects.consume(code);
|
|
120149
|
-
return captureType;
|
|
120150
|
-
}
|
|
120151
|
-
return nok(code);
|
|
120152
|
-
};
|
|
120153
|
-
const captureType = (code) => {
|
|
120154
|
-
if (code === codes.rightSquareBracket) {
|
|
120155
|
-
if (!KNOWN_BLOCK_TYPES.has(blockTypeRef.value)) {
|
|
120156
|
-
return nok(code);
|
|
120157
|
-
}
|
|
120158
|
-
effects.exit('magicBlockType');
|
|
120159
|
-
effects.enter('magicBlockMarkerTypeEnd');
|
|
120160
|
-
effects.consume(code);
|
|
120161
|
-
effects.exit('magicBlockMarkerTypeEnd');
|
|
120162
|
-
return onComplete;
|
|
120163
|
-
}
|
|
120164
|
-
if (isTypeChar(code)) {
|
|
120165
|
-
blockTypeRef.value += String.fromCharCode(code);
|
|
120166
|
-
effects.consume(code);
|
|
120167
|
-
return captureType;
|
|
120168
|
-
}
|
|
120169
|
-
return nok(code);
|
|
120170
|
-
};
|
|
120171
|
-
return { first: captureTypeFirst, remaining: captureType };
|
|
120172
|
-
}
|
|
120173
|
-
/**
|
|
120174
|
-
* Creates the closing marker state machine: /block]
|
|
120175
|
-
* Handles partial matches by calling onMismatch to fall back to data capture.
|
|
120176
|
-
*/
|
|
120177
|
-
function createClosingMarkerParser(effects, onSuccess, onMismatch, onEof, jsonState) {
|
|
120178
|
-
const handleMismatch = (code) => {
|
|
120179
|
-
if (jsonState && code === codes.quotationMark) {
|
|
120180
|
-
jsonState.inString = true;
|
|
120181
|
-
}
|
|
120182
|
-
return onMismatch(code);
|
|
120183
|
-
};
|
|
120184
|
-
const expectSlash = (code) => {
|
|
120185
|
-
if (code === null)
|
|
120186
|
-
return onEof(code);
|
|
120187
|
-
if (code !== codes.slash)
|
|
120188
|
-
return handleMismatch(code);
|
|
120189
|
-
effects.consume(code);
|
|
120190
|
-
return expectB;
|
|
120191
|
-
};
|
|
120192
|
-
const expectB = (code) => {
|
|
120193
|
-
if (code === null)
|
|
120194
|
-
return onEof(code);
|
|
120195
|
-
if (code !== codes.lowercaseB)
|
|
120196
|
-
return handleMismatch(code);
|
|
120197
|
-
effects.consume(code);
|
|
120198
|
-
return expectL;
|
|
120199
|
-
};
|
|
120200
|
-
const expectL = (code) => {
|
|
120201
|
-
if (code === null)
|
|
120202
|
-
return onEof(code);
|
|
120203
|
-
if (code !== codes.lowercaseL)
|
|
120204
|
-
return handleMismatch(code);
|
|
120205
|
-
effects.consume(code);
|
|
120206
|
-
return expectO;
|
|
120207
|
-
};
|
|
120208
|
-
const expectO = (code) => {
|
|
120209
|
-
if (code === null)
|
|
120210
|
-
return onEof(code);
|
|
120211
|
-
if (code !== codes.lowercaseO)
|
|
120212
|
-
return handleMismatch(code);
|
|
120213
|
-
effects.consume(code);
|
|
120214
|
-
return expectC;
|
|
120215
|
-
};
|
|
120216
|
-
const expectC = (code) => {
|
|
120217
|
-
if (code === null)
|
|
120218
|
-
return onEof(code);
|
|
120219
|
-
if (code !== codes.lowercaseC)
|
|
120220
|
-
return handleMismatch(code);
|
|
120221
|
-
effects.consume(code);
|
|
120222
|
-
return expectK;
|
|
120223
|
-
};
|
|
120224
|
-
const expectK = (code) => {
|
|
120225
|
-
if (code === null)
|
|
120226
|
-
return onEof(code);
|
|
120227
|
-
if (code !== codes.lowercaseK)
|
|
120228
|
-
return handleMismatch(code);
|
|
120229
|
-
effects.consume(code);
|
|
120230
|
-
return expectBracket;
|
|
120231
|
-
};
|
|
120232
|
-
const expectBracket = (code) => {
|
|
120233
|
-
if (code === null)
|
|
120234
|
-
return onEof(code);
|
|
120235
|
-
if (code !== codes.rightSquareBracket)
|
|
120236
|
-
return handleMismatch(code);
|
|
120237
|
-
effects.consume(code);
|
|
120238
|
-
return onSuccess;
|
|
120239
|
-
};
|
|
120240
|
-
return { expectSlash };
|
|
120241
|
-
}
|
|
120242
|
-
/**
|
|
120243
|
-
* Partial construct for checking non-lazy continuation.
|
|
120244
|
-
* This is used by the flow tokenizer to check if we can continue
|
|
120245
|
-
* parsing on the next line.
|
|
120246
|
-
*/
|
|
120247
|
-
const syntax_nonLazyContinuation = {
|
|
120248
|
-
partial: true,
|
|
120249
|
-
tokenize: syntax_tokenizeNonLazyContinuation,
|
|
120250
|
-
};
|
|
120251
|
-
/**
|
|
120252
|
-
* Tokenizer for non-lazy continuation checking.
|
|
120253
|
-
* Returns ok if the next line is non-lazy (can continue), nok if lazy.
|
|
120254
|
-
*/
|
|
120255
|
-
function syntax_tokenizeNonLazyContinuation(effects, ok, nok) {
|
|
120256
|
-
const lineStart = (code) => {
|
|
120257
|
-
// `this` here refers to the micromark parser
|
|
120258
|
-
// since we are just passing functions as references and not actually calling them
|
|
120259
|
-
// micromarks's internal parser will call this automatically with appropriate arguments
|
|
120260
|
-
return this.parser.lazy[this.now().line] ? nok(code) : ok(code);
|
|
120261
|
-
};
|
|
120262
|
-
const start = (code) => {
|
|
120263
|
-
if (code === null) {
|
|
120264
|
-
return nok(code);
|
|
120265
|
-
}
|
|
120266
|
-
if (!markdownLineEnding(code)) {
|
|
120267
|
-
return nok(code);
|
|
120268
|
-
}
|
|
120269
|
-
effects.enter('magicBlockLineEnding');
|
|
120270
|
-
effects.consume(code);
|
|
120271
|
-
effects.exit('magicBlockLineEnding');
|
|
120272
|
-
return lineStart;
|
|
120273
|
-
};
|
|
120274
|
-
return start;
|
|
120275
|
-
}
|
|
120133
|
+
;// ./node_modules/micromark-util-symbol/lib/types.js
|
|
120276
120134
|
/**
|
|
120277
|
-
*
|
|
120278
|
-
*
|
|
120279
|
-
* This extension handles both single-line and multiline magic blocks:
|
|
120280
|
-
* - Flow construct (concrete): Handles block-level multiline magic blocks at document level
|
|
120281
|
-
* - Text construct: Handles inline magic blocks in lists, paragraphs, etc.
|
|
120135
|
+
* This module is compiled away!
|
|
120282
120136
|
*
|
|
120283
|
-
*
|
|
120284
|
-
*
|
|
120285
|
-
|
|
120286
|
-
|
|
120287
|
-
|
|
120288
|
-
|
|
120289
|
-
// Marked as concrete to prevent interruption by containers
|
|
120290
|
-
flow: {
|
|
120291
|
-
[codes.leftSquareBracket]: {
|
|
120292
|
-
name: 'magicBlock',
|
|
120293
|
-
concrete: true,
|
|
120294
|
-
tokenize: tokenizeMagicBlockFlow,
|
|
120295
|
-
},
|
|
120296
|
-
},
|
|
120297
|
-
// Text construct - handles magic blocks in inline contexts (lists, paragraphs)
|
|
120298
|
-
text: {
|
|
120299
|
-
[codes.leftSquareBracket]: {
|
|
120300
|
-
name: 'magicBlock',
|
|
120301
|
-
tokenize: tokenizeMagicBlockText,
|
|
120302
|
-
},
|
|
120303
|
-
},
|
|
120304
|
-
};
|
|
120305
|
-
}
|
|
120306
|
-
/**
|
|
120307
|
-
* Flow tokenizer for block-level magic blocks (multiline).
|
|
120308
|
-
* Uses the continuation checking pattern from code fences.
|
|
120309
|
-
*/
|
|
120310
|
-
function tokenizeMagicBlockFlow(effects, ok, nok) {
|
|
120311
|
-
// State for tracking JSON content
|
|
120312
|
-
const jsonState = { escapeNext: false, inString: false };
|
|
120313
|
-
const blockTypeRef = { value: '' };
|
|
120314
|
-
let seenOpenBrace = false;
|
|
120315
|
-
// Create shared parsers for opening marker and type capture
|
|
120316
|
-
const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
|
|
120317
|
-
const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
|
|
120318
|
-
return start;
|
|
120319
|
-
function start(code) {
|
|
120320
|
-
if (code !== codes.leftSquareBracket)
|
|
120321
|
-
return nok(code);
|
|
120322
|
-
effects.enter('magicBlock');
|
|
120323
|
-
effects.enter('magicBlockMarkerStart');
|
|
120324
|
-
effects.consume(code);
|
|
120325
|
-
return openingMarkerParser;
|
|
120326
|
-
}
|
|
120327
|
-
/**
|
|
120328
|
-
* State before data content - handles line endings or starts data capture.
|
|
120329
|
-
*/
|
|
120330
|
-
function beforeData(code) {
|
|
120331
|
-
// EOF - magic block must be closed
|
|
120332
|
-
if (code === null) {
|
|
120333
|
-
effects.exit('magicBlock');
|
|
120334
|
-
return nok(code);
|
|
120335
|
-
}
|
|
120336
|
-
// Line ending before any data - check continuation
|
|
120337
|
-
if (markdownLineEnding(code)) {
|
|
120338
|
-
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
120339
|
-
}
|
|
120340
|
-
// Check for closing marker directly (without entering data)
|
|
120341
|
-
// This handles cases like [block:type]\n{}\n\n[/block] where there are
|
|
120342
|
-
// newlines after the data object
|
|
120343
|
-
if (code === codes.leftSquareBracket) {
|
|
120344
|
-
effects.enter('magicBlockMarkerEnd');
|
|
120345
|
-
effects.consume(code);
|
|
120346
|
-
return expectSlashFromContinuation;
|
|
120347
|
-
}
|
|
120348
|
-
// If we've already seen the opening brace, just continue capturing data
|
|
120349
|
-
if (seenOpenBrace) {
|
|
120350
|
-
effects.enter('magicBlockData');
|
|
120351
|
-
return captureData(code);
|
|
120352
|
-
}
|
|
120353
|
-
// Skip whitespace (spaces/tabs) before the data - stay in beforeData
|
|
120354
|
-
// Don't enter magicBlockData token yet until we confirm there's a '{'
|
|
120355
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120356
|
-
return beforeDataWhitespace(code);
|
|
120357
|
-
}
|
|
120358
|
-
// Data must start with '{' for valid JSON
|
|
120359
|
-
if (code !== codes.leftCurlyBrace) {
|
|
120360
|
-
effects.exit('magicBlock');
|
|
120361
|
-
return nok(code);
|
|
120362
|
-
}
|
|
120363
|
-
// We have '{' - enter data token and start capturing
|
|
120364
|
-
seenOpenBrace = true;
|
|
120365
|
-
effects.enter('magicBlockData');
|
|
120366
|
-
return captureData(code);
|
|
120367
|
-
}
|
|
120368
|
-
/**
|
|
120369
|
-
* Consume whitespace before the data without creating a token.
|
|
120370
|
-
* Uses a temporary token to satisfy micromark's requirement.
|
|
120371
|
-
*/
|
|
120372
|
-
function beforeDataWhitespace(code) {
|
|
120373
|
-
if (code === null) {
|
|
120374
|
-
effects.exit('magicBlock');
|
|
120375
|
-
return nok(code);
|
|
120376
|
-
}
|
|
120377
|
-
if (markdownLineEnding(code)) {
|
|
120378
|
-
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
120379
|
-
}
|
|
120380
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120381
|
-
// We need to consume this but can't without a token - use magicBlockData
|
|
120382
|
-
// and track that we haven't seen '{' yet
|
|
120383
|
-
effects.enter('magicBlockData');
|
|
120384
|
-
effects.consume(code);
|
|
120385
|
-
return beforeDataWhitespaceContinue;
|
|
120386
|
-
}
|
|
120387
|
-
if (code === codes.leftCurlyBrace) {
|
|
120388
|
-
seenOpenBrace = true;
|
|
120389
|
-
effects.enter('magicBlockData');
|
|
120390
|
-
return captureData(code);
|
|
120391
|
-
}
|
|
120392
|
-
effects.exit('magicBlock');
|
|
120393
|
-
return nok(code);
|
|
120394
|
-
}
|
|
120395
|
-
/**
|
|
120396
|
-
* Continue consuming whitespace or validate the opening brace.
|
|
120397
|
-
*/
|
|
120398
|
-
function beforeDataWhitespaceContinue(code) {
|
|
120399
|
-
if (code === null) {
|
|
120400
|
-
effects.exit('magicBlockData');
|
|
120401
|
-
effects.exit('magicBlock');
|
|
120402
|
-
return nok(code);
|
|
120403
|
-
}
|
|
120404
|
-
if (markdownLineEnding(code)) {
|
|
120405
|
-
effects.exit('magicBlockData');
|
|
120406
|
-
return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
|
|
120407
|
-
}
|
|
120408
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120409
|
-
effects.consume(code);
|
|
120410
|
-
return beforeDataWhitespaceContinue;
|
|
120411
|
-
}
|
|
120412
|
-
if (code === codes.leftCurlyBrace) {
|
|
120413
|
-
seenOpenBrace = true;
|
|
120414
|
-
return captureData(code);
|
|
120415
|
-
}
|
|
120416
|
-
effects.exit('magicBlockData');
|
|
120417
|
-
effects.exit('magicBlock');
|
|
120418
|
-
return nok(code);
|
|
120419
|
-
}
|
|
120420
|
-
/**
|
|
120421
|
-
* Continuation OK before we've entered data token.
|
|
120422
|
-
*/
|
|
120423
|
-
function continuationOkBeforeData(code) {
|
|
120424
|
-
effects.enter('magicBlockLineEnding');
|
|
120425
|
-
effects.consume(code);
|
|
120426
|
-
effects.exit('magicBlockLineEnding');
|
|
120427
|
-
return beforeData; // Stay in beforeData state - don't enter magicBlockData yet
|
|
120428
|
-
}
|
|
120429
|
-
function captureData(code) {
|
|
120430
|
-
// EOF - magic block must be closed
|
|
120431
|
-
if (code === null) {
|
|
120432
|
-
effects.exit('magicBlockData');
|
|
120433
|
-
effects.exit('magicBlock');
|
|
120434
|
-
return nok(code);
|
|
120435
|
-
}
|
|
120436
|
-
// At line ending, check if we can continue on the next line
|
|
120437
|
-
if (markdownLineEnding(code)) {
|
|
120438
|
-
effects.exit('magicBlockData');
|
|
120439
|
-
return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
|
|
120440
|
-
}
|
|
120441
|
-
if (jsonState.escapeNext) {
|
|
120442
|
-
jsonState.escapeNext = false;
|
|
120443
|
-
effects.consume(code);
|
|
120444
|
-
return captureData;
|
|
120445
|
-
}
|
|
120446
|
-
if (jsonState.inString) {
|
|
120447
|
-
if (code === codes.backslash) {
|
|
120448
|
-
jsonState.escapeNext = true;
|
|
120449
|
-
effects.consume(code);
|
|
120450
|
-
return captureData;
|
|
120451
|
-
}
|
|
120452
|
-
if (code === codes.quotationMark) {
|
|
120453
|
-
jsonState.inString = false;
|
|
120454
|
-
}
|
|
120455
|
-
effects.consume(code);
|
|
120456
|
-
return captureData;
|
|
120457
|
-
}
|
|
120458
|
-
if (code === codes.quotationMark) {
|
|
120459
|
-
jsonState.inString = true;
|
|
120460
|
-
effects.consume(code);
|
|
120461
|
-
return captureData;
|
|
120462
|
-
}
|
|
120463
|
-
if (code === codes.leftSquareBracket) {
|
|
120464
|
-
effects.exit('magicBlockData');
|
|
120465
|
-
effects.enter('magicBlockMarkerEnd');
|
|
120466
|
-
effects.consume(code);
|
|
120467
|
-
return expectSlash;
|
|
120468
|
-
}
|
|
120469
|
-
effects.consume(code);
|
|
120470
|
-
return captureData;
|
|
120471
|
-
}
|
|
120472
|
-
/**
|
|
120473
|
-
* Called when non-lazy continuation check passes - we can continue parsing.
|
|
120474
|
-
*/
|
|
120475
|
-
function continuationOk(code) {
|
|
120476
|
-
// Consume the line ending
|
|
120477
|
-
effects.enter('magicBlockLineEnding');
|
|
120478
|
-
effects.consume(code);
|
|
120479
|
-
effects.exit('magicBlockLineEnding');
|
|
120480
|
-
return continuationStart;
|
|
120481
|
-
}
|
|
120482
|
-
/**
|
|
120483
|
-
* Start of continuation line - check for more line endings, closing marker, or start capturing data.
|
|
120484
|
-
*/
|
|
120485
|
-
function continuationStart(code) {
|
|
120486
|
-
// Handle consecutive line endings
|
|
120487
|
-
if (code === null) {
|
|
120488
|
-
effects.exit('magicBlock');
|
|
120489
|
-
return nok(code);
|
|
120490
|
-
}
|
|
120491
|
-
if (markdownLineEnding(code)) {
|
|
120492
|
-
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
120493
|
-
}
|
|
120494
|
-
// Check if this is the start of the closing marker [/block]
|
|
120495
|
-
// If so, handle it directly without entering magicBlockData
|
|
120496
|
-
if (code === codes.leftSquareBracket) {
|
|
120497
|
-
effects.enter('magicBlockMarkerEnd');
|
|
120498
|
-
effects.consume(code);
|
|
120499
|
-
return expectSlashFromContinuation;
|
|
120500
|
-
}
|
|
120501
|
-
effects.enter('magicBlockData');
|
|
120502
|
-
return captureData(code);
|
|
120503
|
-
}
|
|
120504
|
-
/**
|
|
120505
|
-
* Check for closing marker slash when coming from continuation.
|
|
120506
|
-
* If not a closing marker, create an empty data token and continue.
|
|
120507
|
-
*/
|
|
120508
|
-
function expectSlashFromContinuation(code) {
|
|
120509
|
-
if (code === null) {
|
|
120510
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120511
|
-
effects.exit('magicBlock');
|
|
120512
|
-
return nok(code);
|
|
120513
|
-
}
|
|
120514
|
-
if (markdownLineEnding(code)) {
|
|
120515
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120516
|
-
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
120517
|
-
}
|
|
120518
|
-
if (code === codes.slash) {
|
|
120519
|
-
effects.consume(code);
|
|
120520
|
-
return expectClosingB;
|
|
120521
|
-
}
|
|
120522
|
-
// Not a closing marker - this is data content
|
|
120523
|
-
// Exit marker and enter data
|
|
120524
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120525
|
-
effects.enter('magicBlockData');
|
|
120526
|
-
// The [ was consumed by the marker, so we need to conceptually "have it" in our data
|
|
120527
|
-
// But since we already consumed it into the marker, we need a different approach
|
|
120528
|
-
// Re-classify: consume this character as data and continue
|
|
120529
|
-
if (code === codes.quotationMark)
|
|
120530
|
-
jsonState.inString = true;
|
|
120531
|
-
effects.consume(code);
|
|
120532
|
-
return captureData;
|
|
120533
|
-
}
|
|
120534
|
-
function expectSlash(code) {
|
|
120535
|
-
if (code === null) {
|
|
120536
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120537
|
-
effects.exit('magicBlock');
|
|
120538
|
-
return nok(code);
|
|
120539
|
-
}
|
|
120540
|
-
// At line ending during marker parsing
|
|
120541
|
-
if (markdownLineEnding(code)) {
|
|
120542
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120543
|
-
return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
|
|
120544
|
-
}
|
|
120545
|
-
if (code !== codes.slash) {
|
|
120546
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120547
|
-
effects.enter('magicBlockData');
|
|
120548
|
-
if (code === codes.quotationMark)
|
|
120549
|
-
jsonState.inString = true;
|
|
120550
|
-
effects.consume(code);
|
|
120551
|
-
return captureData;
|
|
120552
|
-
}
|
|
120553
|
-
effects.consume(code);
|
|
120554
|
-
return expectClosingB;
|
|
120555
|
-
}
|
|
120556
|
-
function expectClosingB(code) {
|
|
120557
|
-
if (code === null) {
|
|
120558
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120559
|
-
effects.exit('magicBlock');
|
|
120560
|
-
return nok(code);
|
|
120561
|
-
}
|
|
120562
|
-
if (code !== codes.lowercaseB) {
|
|
120563
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120564
|
-
effects.enter('magicBlockData');
|
|
120565
|
-
if (code === codes.quotationMark)
|
|
120566
|
-
jsonState.inString = true;
|
|
120567
|
-
effects.consume(code);
|
|
120568
|
-
return captureData;
|
|
120569
|
-
}
|
|
120570
|
-
effects.consume(code);
|
|
120571
|
-
return expectClosingL;
|
|
120572
|
-
}
|
|
120573
|
-
function expectClosingL(code) {
|
|
120574
|
-
if (code === null) {
|
|
120575
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120576
|
-
effects.exit('magicBlock');
|
|
120577
|
-
return nok(code);
|
|
120578
|
-
}
|
|
120579
|
-
if (code !== codes.lowercaseL) {
|
|
120580
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120581
|
-
effects.enter('magicBlockData');
|
|
120582
|
-
if (code === codes.quotationMark)
|
|
120583
|
-
jsonState.inString = true;
|
|
120584
|
-
effects.consume(code);
|
|
120585
|
-
return captureData;
|
|
120586
|
-
}
|
|
120587
|
-
effects.consume(code);
|
|
120588
|
-
return expectClosingO;
|
|
120589
|
-
}
|
|
120590
|
-
function expectClosingO(code) {
|
|
120591
|
-
if (code === null) {
|
|
120592
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120593
|
-
effects.exit('magicBlock');
|
|
120594
|
-
return nok(code);
|
|
120595
|
-
}
|
|
120596
|
-
if (code !== codes.lowercaseO) {
|
|
120597
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120598
|
-
effects.enter('magicBlockData');
|
|
120599
|
-
if (code === codes.quotationMark)
|
|
120600
|
-
jsonState.inString = true;
|
|
120601
|
-
effects.consume(code);
|
|
120602
|
-
return captureData;
|
|
120603
|
-
}
|
|
120604
|
-
effects.consume(code);
|
|
120605
|
-
return expectClosingC;
|
|
120606
|
-
}
|
|
120607
|
-
function expectClosingC(code) {
|
|
120608
|
-
if (code === null) {
|
|
120609
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120610
|
-
effects.exit('magicBlock');
|
|
120611
|
-
return nok(code);
|
|
120612
|
-
}
|
|
120613
|
-
if (code !== codes.lowercaseC) {
|
|
120614
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120615
|
-
effects.enter('magicBlockData');
|
|
120616
|
-
if (code === codes.quotationMark)
|
|
120617
|
-
jsonState.inString = true;
|
|
120618
|
-
effects.consume(code);
|
|
120619
|
-
return captureData;
|
|
120620
|
-
}
|
|
120621
|
-
effects.consume(code);
|
|
120622
|
-
return expectClosingK;
|
|
120623
|
-
}
|
|
120624
|
-
function expectClosingK(code) {
|
|
120625
|
-
if (code === null) {
|
|
120626
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120627
|
-
effects.exit('magicBlock');
|
|
120628
|
-
return nok(code);
|
|
120629
|
-
}
|
|
120630
|
-
if (code !== codes.lowercaseK) {
|
|
120631
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120632
|
-
effects.enter('magicBlockData');
|
|
120633
|
-
if (code === codes.quotationMark)
|
|
120634
|
-
jsonState.inString = true;
|
|
120635
|
-
effects.consume(code);
|
|
120636
|
-
return captureData;
|
|
120637
|
-
}
|
|
120638
|
-
effects.consume(code);
|
|
120639
|
-
return expectClosingBracket;
|
|
120640
|
-
}
|
|
120641
|
-
function expectClosingBracket(code) {
|
|
120642
|
-
if (code === null) {
|
|
120643
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120644
|
-
effects.exit('magicBlock');
|
|
120645
|
-
return nok(code);
|
|
120646
|
-
}
|
|
120647
|
-
if (code !== codes.rightSquareBracket) {
|
|
120648
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120649
|
-
effects.enter('magicBlockData');
|
|
120650
|
-
if (code === codes.quotationMark)
|
|
120651
|
-
jsonState.inString = true;
|
|
120652
|
-
effects.consume(code);
|
|
120653
|
-
return captureData;
|
|
120654
|
-
}
|
|
120655
|
-
effects.consume(code);
|
|
120656
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120657
|
-
// Check for trailing whitespace on the same line
|
|
120658
|
-
return consumeTrailing;
|
|
120659
|
-
}
|
|
120660
|
-
/**
|
|
120661
|
-
* Consume trailing whitespace (spaces/tabs) on the same line after [/block].
|
|
120662
|
-
* For concrete flow constructs, we must end at eol/eof or fail.
|
|
120663
|
-
* Trailing whitespace is consumed; other content causes nok (text tokenizer handles it).
|
|
120664
|
-
*/
|
|
120665
|
-
function consumeTrailing(code) {
|
|
120666
|
-
// End of file - done
|
|
120667
|
-
if (code === null) {
|
|
120668
|
-
effects.exit('magicBlock');
|
|
120669
|
-
return ok(code);
|
|
120670
|
-
}
|
|
120671
|
-
// Line ending - done
|
|
120672
|
-
if (markdownLineEnding(code)) {
|
|
120673
|
-
effects.exit('magicBlock');
|
|
120674
|
-
return ok(code);
|
|
120675
|
-
}
|
|
120676
|
-
// Space or tab - consume as trailing whitespace
|
|
120677
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120678
|
-
effects.enter('magicBlockTrailing');
|
|
120679
|
-
effects.consume(code);
|
|
120680
|
-
return consumeTrailingContinue;
|
|
120681
|
-
}
|
|
120682
|
-
// Any other character - fail flow tokenizer, let text tokenizer handle it
|
|
120683
|
-
effects.exit('magicBlock');
|
|
120684
|
-
return nok(code);
|
|
120685
|
-
}
|
|
120686
|
-
/**
|
|
120687
|
-
* Continue consuming trailing whitespace.
|
|
120688
|
-
*/
|
|
120689
|
-
function consumeTrailingContinue(code) {
|
|
120690
|
-
// End of file - done
|
|
120691
|
-
if (code === null) {
|
|
120692
|
-
effects.exit('magicBlockTrailing');
|
|
120693
|
-
effects.exit('magicBlock');
|
|
120694
|
-
return ok(code);
|
|
120695
|
-
}
|
|
120696
|
-
// Line ending - done
|
|
120697
|
-
if (markdownLineEnding(code)) {
|
|
120698
|
-
effects.exit('magicBlockTrailing');
|
|
120699
|
-
effects.exit('magicBlock');
|
|
120700
|
-
return ok(code);
|
|
120701
|
-
}
|
|
120702
|
-
// More space or tab - keep consuming
|
|
120703
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120704
|
-
effects.consume(code);
|
|
120705
|
-
return consumeTrailingContinue;
|
|
120706
|
-
}
|
|
120707
|
-
// Non-whitespace after whitespace - fail flow tokenizer
|
|
120708
|
-
effects.exit('magicBlockTrailing');
|
|
120709
|
-
effects.exit('magicBlock');
|
|
120710
|
-
return nok(code);
|
|
120711
|
-
}
|
|
120712
|
-
/**
|
|
120713
|
-
* Called when we can't continue (lazy line or EOF) - exit the construct.
|
|
120714
|
-
*/
|
|
120715
|
-
function after(code) {
|
|
120716
|
-
effects.exit('magicBlock');
|
|
120717
|
-
return nok(code);
|
|
120718
|
-
}
|
|
120719
|
-
}
|
|
120720
|
-
/**
|
|
120721
|
-
* Text tokenizer for single-line magic blocks only.
|
|
120722
|
-
* Used in inline contexts like list items and paragraphs.
|
|
120723
|
-
* Multiline blocks are handled by the flow tokenizer.
|
|
120724
|
-
*/
|
|
120725
|
-
function tokenizeMagicBlockText(effects, ok, nok) {
|
|
120726
|
-
// State for tracking JSON content
|
|
120727
|
-
const jsonState = { escapeNext: false, inString: false };
|
|
120728
|
-
const blockTypeRef = { value: '' };
|
|
120729
|
-
let seenOpenBrace = false;
|
|
120730
|
-
// Create shared parsers for opening marker and type capture
|
|
120731
|
-
const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
|
|
120732
|
-
const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
|
|
120733
|
-
// Success handler for closing marker - exits tokens and returns ok
|
|
120734
|
-
const closingSuccess = (code) => {
|
|
120735
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120736
|
-
effects.exit('magicBlock');
|
|
120737
|
-
return ok(code);
|
|
120738
|
-
};
|
|
120739
|
-
// Mismatch handler - falls back to data capture
|
|
120740
|
-
const closingMismatch = (code) => {
|
|
120741
|
-
effects.exit('magicBlockMarkerEnd');
|
|
120742
|
-
effects.enter('magicBlockData');
|
|
120743
|
-
if (code === codes.quotationMark)
|
|
120744
|
-
jsonState.inString = true;
|
|
120745
|
-
effects.consume(code);
|
|
120746
|
-
return captureData;
|
|
120747
|
-
};
|
|
120748
|
-
// EOF handler
|
|
120749
|
-
const closingEof = (_code) => nok(_code);
|
|
120750
|
-
// Create closing marker parsers
|
|
120751
|
-
const closingFromBeforeData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
|
|
120752
|
-
const closingFromData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
|
|
120753
|
-
return start;
|
|
120754
|
-
function start(code) {
|
|
120755
|
-
if (code !== codes.leftSquareBracket)
|
|
120756
|
-
return nok(code);
|
|
120757
|
-
effects.enter('magicBlock');
|
|
120758
|
-
effects.enter('magicBlockMarkerStart');
|
|
120759
|
-
effects.consume(code);
|
|
120760
|
-
return openingMarkerParser;
|
|
120761
|
-
}
|
|
120762
|
-
/**
|
|
120763
|
-
* State before data content - handles line endings before entering data token.
|
|
120764
|
-
* Whitespace before '{' is allowed.
|
|
120765
|
-
*/
|
|
120766
|
-
function beforeData(code) {
|
|
120767
|
-
// Fail on EOF - magic block must be closed
|
|
120768
|
-
if (code === null) {
|
|
120769
|
-
return nok(code);
|
|
120770
|
-
}
|
|
120771
|
-
// Handle line endings before any data - consume them without entering data token
|
|
120772
|
-
if (markdownLineEnding(code)) {
|
|
120773
|
-
effects.enter('magicBlockLineEnding');
|
|
120774
|
-
effects.consume(code);
|
|
120775
|
-
effects.exit('magicBlockLineEnding');
|
|
120776
|
-
return beforeData;
|
|
120777
|
-
}
|
|
120778
|
-
// Check for closing marker directly (without entering data)
|
|
120779
|
-
if (code === codes.leftSquareBracket) {
|
|
120780
|
-
effects.enter('magicBlockMarkerEnd');
|
|
120781
|
-
effects.consume(code);
|
|
120782
|
-
return closingFromBeforeData.expectSlash;
|
|
120783
|
-
}
|
|
120784
|
-
// If we've already seen the opening brace, just continue capturing data
|
|
120785
|
-
if (seenOpenBrace) {
|
|
120786
|
-
effects.enter('magicBlockData');
|
|
120787
|
-
return captureData(code);
|
|
120788
|
-
}
|
|
120789
|
-
// Skip whitespace (spaces/tabs) before the data
|
|
120790
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120791
|
-
return beforeDataWhitespace(code);
|
|
120792
|
-
}
|
|
120793
|
-
// Data must start with '{' for valid JSON
|
|
120794
|
-
if (code !== codes.leftCurlyBrace) {
|
|
120795
|
-
return nok(code);
|
|
120796
|
-
}
|
|
120797
|
-
// We have '{' - enter data token and start capturing
|
|
120798
|
-
seenOpenBrace = true;
|
|
120799
|
-
effects.enter('magicBlockData');
|
|
120800
|
-
return captureData(code);
|
|
120801
|
-
}
|
|
120802
|
-
/**
|
|
120803
|
-
* Consume whitespace before the data.
|
|
120804
|
-
*/
|
|
120805
|
-
function beforeDataWhitespace(code) {
|
|
120806
|
-
if (code === null) {
|
|
120807
|
-
return nok(code);
|
|
120808
|
-
}
|
|
120809
|
-
if (markdownLineEnding(code)) {
|
|
120810
|
-
effects.enter('magicBlockLineEnding');
|
|
120811
|
-
effects.consume(code);
|
|
120812
|
-
effects.exit('magicBlockLineEnding');
|
|
120813
|
-
return beforeData;
|
|
120814
|
-
}
|
|
120815
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120816
|
-
effects.enter('magicBlockData');
|
|
120817
|
-
effects.consume(code);
|
|
120818
|
-
return beforeDataWhitespaceContinue;
|
|
120819
|
-
}
|
|
120820
|
-
if (code === codes.leftCurlyBrace) {
|
|
120821
|
-
seenOpenBrace = true;
|
|
120822
|
-
effects.enter('magicBlockData');
|
|
120823
|
-
return captureData(code);
|
|
120824
|
-
}
|
|
120825
|
-
return nok(code);
|
|
120826
|
-
}
|
|
120827
|
-
/**
|
|
120828
|
-
* Continue consuming whitespace or validate the opening brace.
|
|
120829
|
-
*/
|
|
120830
|
-
function beforeDataWhitespaceContinue(code) {
|
|
120831
|
-
if (code === null) {
|
|
120832
|
-
effects.exit('magicBlockData');
|
|
120833
|
-
return nok(code);
|
|
120834
|
-
}
|
|
120835
|
-
if (markdownLineEnding(code)) {
|
|
120836
|
-
effects.exit('magicBlockData');
|
|
120837
|
-
effects.enter('magicBlockLineEnding');
|
|
120838
|
-
effects.consume(code);
|
|
120839
|
-
effects.exit('magicBlockLineEnding');
|
|
120840
|
-
return beforeData;
|
|
120841
|
-
}
|
|
120842
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
120843
|
-
effects.consume(code);
|
|
120844
|
-
return beforeDataWhitespaceContinue;
|
|
120845
|
-
}
|
|
120846
|
-
if (code === codes.leftCurlyBrace) {
|
|
120847
|
-
seenOpenBrace = true;
|
|
120848
|
-
return captureData(code);
|
|
120849
|
-
}
|
|
120850
|
-
effects.exit('magicBlockData');
|
|
120851
|
-
return nok(code);
|
|
120852
|
-
}
|
|
120853
|
-
function captureData(code) {
|
|
120854
|
-
// Fail on EOF - magic block must be closed
|
|
120855
|
-
if (code === null) {
|
|
120856
|
-
effects.exit('magicBlockData');
|
|
120857
|
-
return nok(code);
|
|
120858
|
-
}
|
|
120859
|
-
// Handle multiline magic blocks within text/paragraphs
|
|
120860
|
-
// Exit data, consume line ending with proper token, then re-enter data
|
|
120861
|
-
if (markdownLineEnding(code)) {
|
|
120862
|
-
effects.exit('magicBlockData');
|
|
120863
|
-
effects.enter('magicBlockLineEnding');
|
|
120864
|
-
effects.consume(code);
|
|
120865
|
-
effects.exit('magicBlockLineEnding');
|
|
120866
|
-
return beforeData; // Go back to beforeData to handle potential empty lines
|
|
120867
|
-
}
|
|
120868
|
-
if (jsonState.escapeNext) {
|
|
120869
|
-
jsonState.escapeNext = false;
|
|
120870
|
-
effects.consume(code);
|
|
120871
|
-
return captureData;
|
|
120872
|
-
}
|
|
120873
|
-
if (jsonState.inString) {
|
|
120874
|
-
if (code === codes.backslash) {
|
|
120875
|
-
jsonState.escapeNext = true;
|
|
120876
|
-
effects.consume(code);
|
|
120877
|
-
return captureData;
|
|
120878
|
-
}
|
|
120879
|
-
if (code === codes.quotationMark) {
|
|
120880
|
-
jsonState.inString = false;
|
|
120881
|
-
}
|
|
120882
|
-
effects.consume(code);
|
|
120883
|
-
return captureData;
|
|
120884
|
-
}
|
|
120885
|
-
if (code === codes.quotationMark) {
|
|
120886
|
-
jsonState.inString = true;
|
|
120887
|
-
effects.consume(code);
|
|
120888
|
-
return captureData;
|
|
120889
|
-
}
|
|
120890
|
-
if (code === codes.leftSquareBracket) {
|
|
120891
|
-
effects.exit('magicBlockData');
|
|
120892
|
-
effects.enter('magicBlockMarkerEnd');
|
|
120893
|
-
effects.consume(code);
|
|
120894
|
-
return closingFromData.expectSlash;
|
|
120895
|
-
}
|
|
120896
|
-
effects.consume(code);
|
|
120897
|
-
return captureData;
|
|
120898
|
-
}
|
|
120899
|
-
}
|
|
120900
|
-
/* harmony default export */ const syntax = ((/* unused pure expression or super */ null && (magicBlock)));
|
|
120901
|
-
|
|
120902
|
-
;// ./lib/micromark/magic-block/index.ts
|
|
120903
|
-
/**
|
|
120904
|
-
* Micromark extension for magic block syntax.
|
|
120905
|
-
*
|
|
120906
|
-
* Usage:
|
|
120907
|
-
* ```ts
|
|
120908
|
-
* import { magicBlock } from './lib/micromark/magic-block';
|
|
120909
|
-
*
|
|
120910
|
-
* const processor = unified()
|
|
120911
|
-
* .data('micromarkExtensions', [magicBlock()])
|
|
120912
|
-
* ```
|
|
120913
|
-
*/
|
|
120914
|
-
|
|
120915
|
-
|
|
120916
|
-
;// ./node_modules/micromark-util-symbol/lib/types.js
|
|
120917
|
-
/**
|
|
120918
|
-
* This module is compiled away!
|
|
120919
|
-
*
|
|
120920
|
-
* Here is the list of all types of tokens exposed by micromark, with a short
|
|
120921
|
-
* explanation of what they include and where they are found.
|
|
120922
|
-
* In picking names, generally, the rule is to be as explicit as possible
|
|
120923
|
-
* instead of reusing names.
|
|
120924
|
-
* For example, there is a `definitionDestination` and a `resourceDestination`,
|
|
120925
|
-
* instead of one shared name.
|
|
120137
|
+
* Here is the list of all types of tokens exposed by micromark, with a short
|
|
120138
|
+
* explanation of what they include and where they are found.
|
|
120139
|
+
* In picking names, generally, the rule is to be as explicit as possible
|
|
120140
|
+
* instead of reusing names.
|
|
120141
|
+
* For example, there is a `definitionDestination` and a `resourceDestination`,
|
|
120142
|
+
* instead of one shared name.
|
|
120926
120143
|
*/
|
|
120927
120144
|
|
|
120928
120145
|
// Note: when changing the next record, you must also change `TokenTypeMap`
|
|
@@ -121368,36 +120585,18 @@ const types_types = /** @type {const} */ ({
|
|
|
121368
120585
|
chunkString: 'chunkString'
|
|
121369
120586
|
})
|
|
121370
120587
|
|
|
121371
|
-
;// ./lib/micromark/
|
|
121372
|
-
|
|
121373
|
-
|
|
121374
|
-
|
|
120588
|
+
;// ./lib/micromark/jsx-table/syntax.ts
|
|
121375
120589
|
|
|
121376
120590
|
|
|
121377
|
-
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
121378
|
-
// section, …) always start a block, so they stay flow even with trailing
|
|
121379
|
-
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
121380
|
-
// stay flow when nothing trails the close tag.
|
|
121381
|
-
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
121382
|
-
// Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
|
|
121383
|
-
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
121384
|
-
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
121385
|
-
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
121386
120591
|
const syntax_nonLazyContinuationStart = {
|
|
121387
120592
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
121388
120593
|
partial: true,
|
|
121389
120594
|
};
|
|
121390
|
-
|
|
121391
|
-
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
121392
|
-
const markupOnlyContinuation = {
|
|
121393
|
-
tokenize: tokenizeMarkupOnlyContinuation,
|
|
121394
|
-
partial: true,
|
|
121395
|
-
};
|
|
121396
|
-
function resolveToMdxComponent(events) {
|
|
120595
|
+
function resolveToJsxTable(events) {
|
|
121397
120596
|
let index = events.length;
|
|
121398
120597
|
while (index > 0) {
|
|
121399
120598
|
index -= 1;
|
|
121400
|
-
if (events[index][0] === 'enter' && events[index][1].type === '
|
|
120599
|
+
if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
|
|
121401
120600
|
break;
|
|
121402
120601
|
}
|
|
121403
120602
|
}
|
|
@@ -121408,71 +120607,1177 @@ function resolveToMdxComponent(events) {
|
|
|
121408
120607
|
}
|
|
121409
120608
|
return events;
|
|
121410
120609
|
}
|
|
121411
|
-
const
|
|
121412
|
-
name: '
|
|
121413
|
-
tokenize:
|
|
121414
|
-
resolveTo:
|
|
120610
|
+
const jsxTableConstruct = {
|
|
120611
|
+
name: 'jsxTable',
|
|
120612
|
+
tokenize: tokenizeJsxTable,
|
|
120613
|
+
resolveTo: resolveToJsxTable,
|
|
121415
120614
|
concrete: true,
|
|
121416
120615
|
};
|
|
121417
|
-
|
|
121418
|
-
|
|
121419
|
-
|
|
121420
|
-
|
|
121421
|
-
|
|
121422
|
-
|
|
121423
|
-
|
|
121424
|
-
|
|
121425
|
-
|
|
121426
|
-
|
|
121427
|
-
|
|
121428
|
-
|
|
121429
|
-
|
|
121430
|
-
|
|
121431
|
-
|
|
121432
|
-
|
|
121433
|
-
|
|
121434
|
-
|
|
121435
|
-
function
|
|
121436
|
-
|
|
121437
|
-
|
|
121438
|
-
|
|
121439
|
-
|
|
121440
|
-
|
|
121441
|
-
|
|
121442
|
-
|
|
121443
|
-
|
|
121444
|
-
|
|
121445
|
-
|
|
121446
|
-
|
|
121447
|
-
|
|
121448
|
-
|
|
121449
|
-
|
|
121450
|
-
|
|
121451
|
-
|
|
121452
|
-
|
|
121453
|
-
|
|
121454
|
-
|
|
121455
|
-
|
|
121456
|
-
|
|
121457
|
-
|
|
121458
|
-
|
|
121459
|
-
|
|
121460
|
-
|
|
121461
|
-
|
|
121462
|
-
|
|
121463
|
-
|
|
121464
|
-
|
|
121465
|
-
|
|
121466
|
-
|
|
121467
|
-
|
|
121468
|
-
|
|
121469
|
-
|
|
121470
|
-
|
|
121471
|
-
|
|
121472
|
-
|
|
121473
|
-
|
|
121474
|
-
|
|
121475
|
-
|
|
120616
|
+
function tokenizeJsxTable(effects, ok, nok) {
|
|
120617
|
+
let codeSpanOpenSize = 0;
|
|
120618
|
+
let codeSpanCloseSize = 0;
|
|
120619
|
+
let depth = 1;
|
|
120620
|
+
const ABLE_SUFFIX = [codes.lowercaseA, codes.lowercaseB, codes.lowercaseL, codes.lowercaseE];
|
|
120621
|
+
/** Build a state chain that matches a sequence of character codes. */
|
|
120622
|
+
function matchChars(chars, onMatch, onFail) {
|
|
120623
|
+
if (chars.length === 0)
|
|
120624
|
+
return onMatch;
|
|
120625
|
+
return ((code) => {
|
|
120626
|
+
if (code === chars[0]) {
|
|
120627
|
+
effects.consume(code);
|
|
120628
|
+
return matchChars(chars.slice(1), onMatch, onFail);
|
|
120629
|
+
}
|
|
120630
|
+
return onFail(code);
|
|
120631
|
+
});
|
|
120632
|
+
}
|
|
120633
|
+
return start;
|
|
120634
|
+
function start(code) {
|
|
120635
|
+
if (code !== codes.lessThan)
|
|
120636
|
+
return nok(code);
|
|
120637
|
+
effects.enter('jsxTable');
|
|
120638
|
+
effects.enter('jsxTableData');
|
|
120639
|
+
effects.consume(code);
|
|
120640
|
+
return afterLessThan;
|
|
120641
|
+
}
|
|
120642
|
+
function afterLessThan(code) {
|
|
120643
|
+
if (code === codes.uppercaseT || code === codes.lowercaseT) {
|
|
120644
|
+
effects.consume(code);
|
|
120645
|
+
return matchChars(ABLE_SUFFIX, afterTagName, nok);
|
|
120646
|
+
}
|
|
120647
|
+
return nok(code);
|
|
120648
|
+
}
|
|
120649
|
+
function afterTagName(code) {
|
|
120650
|
+
if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
|
|
120651
|
+
effects.consume(code);
|
|
120652
|
+
return body;
|
|
120653
|
+
}
|
|
120654
|
+
return nok(code);
|
|
120655
|
+
}
|
|
120656
|
+
function body(code) {
|
|
120657
|
+
// Reject unclosed <Table> so it falls back to normal HTML block parsing
|
|
120658
|
+
// instead of swallowing all subsequent content to EOF
|
|
120659
|
+
if (code === null) {
|
|
120660
|
+
return nok(code);
|
|
120661
|
+
}
|
|
120662
|
+
if (markdownLineEnding(code)) {
|
|
120663
|
+
effects.exit('jsxTableData');
|
|
120664
|
+
return continuationStart(code);
|
|
120665
|
+
}
|
|
120666
|
+
if (code === codes.backslash) {
|
|
120667
|
+
effects.consume(code);
|
|
120668
|
+
return escapedChar;
|
|
120669
|
+
}
|
|
120670
|
+
if (code === codes.lessThan) {
|
|
120671
|
+
effects.consume(code);
|
|
120672
|
+
return closeSlash;
|
|
120673
|
+
}
|
|
120674
|
+
// Skip over backtick code spans so `</Table>` in inline code isn't
|
|
120675
|
+
// treated as the closing tag
|
|
120676
|
+
if (code === codes.graveAccent) {
|
|
120677
|
+
codeSpanOpenSize = 0;
|
|
120678
|
+
return countOpenTicks(code);
|
|
120679
|
+
}
|
|
120680
|
+
effects.consume(code);
|
|
120681
|
+
return body;
|
|
120682
|
+
}
|
|
120683
|
+
function countOpenTicks(code) {
|
|
120684
|
+
if (code === codes.graveAccent) {
|
|
120685
|
+
codeSpanOpenSize += 1;
|
|
120686
|
+
effects.consume(code);
|
|
120687
|
+
return countOpenTicks;
|
|
120688
|
+
}
|
|
120689
|
+
return inCodeSpan(code);
|
|
120690
|
+
}
|
|
120691
|
+
function inCodeSpan(code) {
|
|
120692
|
+
if (code === null || markdownLineEnding(code))
|
|
120693
|
+
return body(code);
|
|
120694
|
+
if (code === codes.graveAccent) {
|
|
120695
|
+
codeSpanCloseSize = 0;
|
|
120696
|
+
return countCloseTicks(code);
|
|
120697
|
+
}
|
|
120698
|
+
effects.consume(code);
|
|
120699
|
+
return inCodeSpan;
|
|
120700
|
+
}
|
|
120701
|
+
function countCloseTicks(code) {
|
|
120702
|
+
if (code === codes.graveAccent) {
|
|
120703
|
+
codeSpanCloseSize += 1;
|
|
120704
|
+
effects.consume(code);
|
|
120705
|
+
return countCloseTicks;
|
|
120706
|
+
}
|
|
120707
|
+
return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
|
|
120708
|
+
}
|
|
120709
|
+
function escapedChar(code) {
|
|
120710
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120711
|
+
return body(code);
|
|
120712
|
+
}
|
|
120713
|
+
effects.consume(code);
|
|
120714
|
+
return body;
|
|
120715
|
+
}
|
|
120716
|
+
function closeSlash(code) {
|
|
120717
|
+
if (code === codes.slash) {
|
|
120718
|
+
effects.consume(code);
|
|
120719
|
+
return closeTagFirstChar;
|
|
120720
|
+
}
|
|
120721
|
+
if (code === codes.uppercaseT || code === codes.lowercaseT) {
|
|
120722
|
+
effects.consume(code);
|
|
120723
|
+
return matchChars(ABLE_SUFFIX, openAfterTagName, body);
|
|
120724
|
+
}
|
|
120725
|
+
return body(code);
|
|
120726
|
+
}
|
|
120727
|
+
function closeTagFirstChar(code) {
|
|
120728
|
+
if (code === codes.uppercaseT || code === codes.lowercaseT) {
|
|
120729
|
+
effects.consume(code);
|
|
120730
|
+
return matchChars(ABLE_SUFFIX, closeGt, body);
|
|
120731
|
+
}
|
|
120732
|
+
return body(code);
|
|
120733
|
+
}
|
|
120734
|
+
function openAfterTagName(code) {
|
|
120735
|
+
if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
|
|
120736
|
+
depth += 1;
|
|
120737
|
+
effects.consume(code);
|
|
120738
|
+
return body;
|
|
120739
|
+
}
|
|
120740
|
+
return body(code);
|
|
120741
|
+
}
|
|
120742
|
+
function closeGt(code) {
|
|
120743
|
+
if (code === codes.greaterThan) {
|
|
120744
|
+
depth -= 1;
|
|
120745
|
+
effects.consume(code);
|
|
120746
|
+
if (depth === 0) {
|
|
120747
|
+
return afterClose;
|
|
120748
|
+
}
|
|
120749
|
+
return body;
|
|
120750
|
+
}
|
|
120751
|
+
return body(code);
|
|
120752
|
+
}
|
|
120753
|
+
function afterClose(code) {
|
|
120754
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120755
|
+
effects.exit('jsxTableData');
|
|
120756
|
+
effects.exit('jsxTable');
|
|
120757
|
+
return ok(code);
|
|
120758
|
+
}
|
|
120759
|
+
effects.consume(code);
|
|
120760
|
+
return afterClose;
|
|
120761
|
+
}
|
|
120762
|
+
// Line ending handling — follows the htmlFlow pattern
|
|
120763
|
+
function continuationStart(code) {
|
|
120764
|
+
return effects.check(syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
|
|
120765
|
+
}
|
|
120766
|
+
function continuationStartNonLazy(code) {
|
|
120767
|
+
effects.enter(types_types.lineEnding);
|
|
120768
|
+
effects.consume(code);
|
|
120769
|
+
effects.exit(types_types.lineEnding);
|
|
120770
|
+
return continuationBefore;
|
|
120771
|
+
}
|
|
120772
|
+
function continuationBefore(code) {
|
|
120773
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120774
|
+
return continuationStart(code);
|
|
120775
|
+
}
|
|
120776
|
+
effects.enter('jsxTableData');
|
|
120777
|
+
return body(code);
|
|
120778
|
+
}
|
|
120779
|
+
function continuationAfter(code) {
|
|
120780
|
+
// At EOF without </Table>, reject so content isn't swallowed
|
|
120781
|
+
if (code === null) {
|
|
120782
|
+
return nok(code);
|
|
120783
|
+
}
|
|
120784
|
+
effects.exit('jsxTable');
|
|
120785
|
+
return ok(code);
|
|
120786
|
+
}
|
|
120787
|
+
}
|
|
120788
|
+
function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
120789
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
120790
|
+
const self = this;
|
|
120791
|
+
return start;
|
|
120792
|
+
function start(code) {
|
|
120793
|
+
if (markdownLineEnding(code)) {
|
|
120794
|
+
effects.enter(types_types.lineEnding);
|
|
120795
|
+
effects.consume(code);
|
|
120796
|
+
effects.exit(types_types.lineEnding);
|
|
120797
|
+
return after;
|
|
120798
|
+
}
|
|
120799
|
+
return nok(code);
|
|
120800
|
+
}
|
|
120801
|
+
function after(code) {
|
|
120802
|
+
if (self.parser.lazy[self.now().line]) {
|
|
120803
|
+
return nok(code);
|
|
120804
|
+
}
|
|
120805
|
+
return ok(code);
|
|
120806
|
+
}
|
|
120807
|
+
}
|
|
120808
|
+
/**
|
|
120809
|
+
* Micromark extension that tokenizes `<Table>...</Table>` and `<table>...</table>`
|
|
120810
|
+
* as a single flow block.
|
|
120811
|
+
*
|
|
120812
|
+
* Prevents CommonMark HTML block type 6 from fragmenting table blocks at blank lines.
|
|
120813
|
+
*/
|
|
120814
|
+
function jsxTable() {
|
|
120815
|
+
return {
|
|
120816
|
+
flow: {
|
|
120817
|
+
[codes.lessThan]: [jsxTableConstruct],
|
|
120818
|
+
},
|
|
120819
|
+
};
|
|
120820
|
+
}
|
|
120821
|
+
|
|
120822
|
+
;// ./lib/micromark/jsx-table/index.ts
|
|
120823
|
+
|
|
120824
|
+
|
|
120825
|
+
;// ./lib/micromark/magic-block/syntax.ts
|
|
120826
|
+
|
|
120827
|
+
|
|
120828
|
+
/**
|
|
120829
|
+
* Known magic block types that the tokenizer will recognize.
|
|
120830
|
+
* Unknown types will not be tokenized as magic blocks.
|
|
120831
|
+
*/
|
|
120832
|
+
const KNOWN_BLOCK_TYPES = new Set([
|
|
120833
|
+
'code',
|
|
120834
|
+
'api-header',
|
|
120835
|
+
'image',
|
|
120836
|
+
'callout',
|
|
120837
|
+
'parameters',
|
|
120838
|
+
'table',
|
|
120839
|
+
'embed',
|
|
120840
|
+
'html',
|
|
120841
|
+
'recipe',
|
|
120842
|
+
'tutorial-tile',
|
|
120843
|
+
]);
|
|
120844
|
+
/**
|
|
120845
|
+
* Check if a character is valid for a magic block type identifier.
|
|
120846
|
+
* Types can contain alphanumeric characters and hyphens (e.g., "api-header", "tutorial-tile")
|
|
120847
|
+
*/
|
|
120848
|
+
function isTypeChar(code) {
|
|
120849
|
+
return asciiAlphanumeric(code) || code === codes.dash;
|
|
120850
|
+
}
|
|
120851
|
+
/**
|
|
120852
|
+
* Creates the opening marker state machine: [block:
|
|
120853
|
+
* Returns the first state function to start parsing.
|
|
120854
|
+
*/
|
|
120855
|
+
function createOpeningMarkerParser(effects, nok, onComplete) {
|
|
120856
|
+
const expectB = (code) => {
|
|
120857
|
+
if (code !== codes.lowercaseB)
|
|
120858
|
+
return nok(code);
|
|
120859
|
+
effects.consume(code);
|
|
120860
|
+
return expectL;
|
|
120861
|
+
};
|
|
120862
|
+
const expectL = (code) => {
|
|
120863
|
+
if (code !== codes.lowercaseL)
|
|
120864
|
+
return nok(code);
|
|
120865
|
+
effects.consume(code);
|
|
120866
|
+
return expectO;
|
|
120867
|
+
};
|
|
120868
|
+
const expectO = (code) => {
|
|
120869
|
+
if (code !== codes.lowercaseO)
|
|
120870
|
+
return nok(code);
|
|
120871
|
+
effects.consume(code);
|
|
120872
|
+
return expectC;
|
|
120873
|
+
};
|
|
120874
|
+
const expectC = (code) => {
|
|
120875
|
+
if (code !== codes.lowercaseC)
|
|
120876
|
+
return nok(code);
|
|
120877
|
+
effects.consume(code);
|
|
120878
|
+
return expectK;
|
|
120879
|
+
};
|
|
120880
|
+
const expectK = (code) => {
|
|
120881
|
+
if (code !== codes.lowercaseK)
|
|
120882
|
+
return nok(code);
|
|
120883
|
+
effects.consume(code);
|
|
120884
|
+
return expectColon;
|
|
120885
|
+
};
|
|
120886
|
+
const expectColon = (code) => {
|
|
120887
|
+
if (code !== codes.colon)
|
|
120888
|
+
return nok(code);
|
|
120889
|
+
effects.consume(code);
|
|
120890
|
+
effects.exit('magicBlockMarkerStart');
|
|
120891
|
+
effects.enter('magicBlockType');
|
|
120892
|
+
return onComplete;
|
|
120893
|
+
};
|
|
120894
|
+
return expectB;
|
|
120895
|
+
}
|
|
120896
|
+
/**
|
|
120897
|
+
* Creates the type capture state machine.
|
|
120898
|
+
* Captures type characters until ] and validates against known types.
|
|
120899
|
+
*/
|
|
120900
|
+
function createTypeCaptureParser(effects, nok, onComplete, blockTypeRef) {
|
|
120901
|
+
const captureTypeFirst = (code) => {
|
|
120902
|
+
// Reject empty type name [block:]
|
|
120903
|
+
if (code === codes.rightSquareBracket) {
|
|
120904
|
+
return nok(code);
|
|
120905
|
+
}
|
|
120906
|
+
if (isTypeChar(code)) {
|
|
120907
|
+
blockTypeRef.value += String.fromCharCode(code);
|
|
120908
|
+
effects.consume(code);
|
|
120909
|
+
return captureType;
|
|
120910
|
+
}
|
|
120911
|
+
return nok(code);
|
|
120912
|
+
};
|
|
120913
|
+
const captureType = (code) => {
|
|
120914
|
+
if (code === codes.rightSquareBracket) {
|
|
120915
|
+
if (!KNOWN_BLOCK_TYPES.has(blockTypeRef.value)) {
|
|
120916
|
+
return nok(code);
|
|
120917
|
+
}
|
|
120918
|
+
effects.exit('magicBlockType');
|
|
120919
|
+
effects.enter('magicBlockMarkerTypeEnd');
|
|
120920
|
+
effects.consume(code);
|
|
120921
|
+
effects.exit('magicBlockMarkerTypeEnd');
|
|
120922
|
+
return onComplete;
|
|
120923
|
+
}
|
|
120924
|
+
if (isTypeChar(code)) {
|
|
120925
|
+
blockTypeRef.value += String.fromCharCode(code);
|
|
120926
|
+
effects.consume(code);
|
|
120927
|
+
return captureType;
|
|
120928
|
+
}
|
|
120929
|
+
return nok(code);
|
|
120930
|
+
};
|
|
120931
|
+
return { first: captureTypeFirst, remaining: captureType };
|
|
120932
|
+
}
|
|
120933
|
+
/**
|
|
120934
|
+
* Creates the closing marker state machine: /block]
|
|
120935
|
+
* Handles partial matches by calling onMismatch to fall back to data capture.
|
|
120936
|
+
*/
|
|
120937
|
+
function createClosingMarkerParser(effects, onSuccess, onMismatch, onEof, jsonState) {
|
|
120938
|
+
const handleMismatch = (code) => {
|
|
120939
|
+
if (jsonState && code === codes.quotationMark) {
|
|
120940
|
+
jsonState.inString = true;
|
|
120941
|
+
}
|
|
120942
|
+
return onMismatch(code);
|
|
120943
|
+
};
|
|
120944
|
+
const expectSlash = (code) => {
|
|
120945
|
+
if (code === null)
|
|
120946
|
+
return onEof(code);
|
|
120947
|
+
if (code !== codes.slash)
|
|
120948
|
+
return handleMismatch(code);
|
|
120949
|
+
effects.consume(code);
|
|
120950
|
+
return expectB;
|
|
120951
|
+
};
|
|
120952
|
+
const expectB = (code) => {
|
|
120953
|
+
if (code === null)
|
|
120954
|
+
return onEof(code);
|
|
120955
|
+
if (code !== codes.lowercaseB)
|
|
120956
|
+
return handleMismatch(code);
|
|
120957
|
+
effects.consume(code);
|
|
120958
|
+
return expectL;
|
|
120959
|
+
};
|
|
120960
|
+
const expectL = (code) => {
|
|
120961
|
+
if (code === null)
|
|
120962
|
+
return onEof(code);
|
|
120963
|
+
if (code !== codes.lowercaseL)
|
|
120964
|
+
return handleMismatch(code);
|
|
120965
|
+
effects.consume(code);
|
|
120966
|
+
return expectO;
|
|
120967
|
+
};
|
|
120968
|
+
const expectO = (code) => {
|
|
120969
|
+
if (code === null)
|
|
120970
|
+
return onEof(code);
|
|
120971
|
+
if (code !== codes.lowercaseO)
|
|
120972
|
+
return handleMismatch(code);
|
|
120973
|
+
effects.consume(code);
|
|
120974
|
+
return expectC;
|
|
120975
|
+
};
|
|
120976
|
+
const expectC = (code) => {
|
|
120977
|
+
if (code === null)
|
|
120978
|
+
return onEof(code);
|
|
120979
|
+
if (code !== codes.lowercaseC)
|
|
120980
|
+
return handleMismatch(code);
|
|
120981
|
+
effects.consume(code);
|
|
120982
|
+
return expectK;
|
|
120983
|
+
};
|
|
120984
|
+
const expectK = (code) => {
|
|
120985
|
+
if (code === null)
|
|
120986
|
+
return onEof(code);
|
|
120987
|
+
if (code !== codes.lowercaseK)
|
|
120988
|
+
return handleMismatch(code);
|
|
120989
|
+
effects.consume(code);
|
|
120990
|
+
return expectBracket;
|
|
120991
|
+
};
|
|
120992
|
+
const expectBracket = (code) => {
|
|
120993
|
+
if (code === null)
|
|
120994
|
+
return onEof(code);
|
|
120995
|
+
if (code !== codes.rightSquareBracket)
|
|
120996
|
+
return handleMismatch(code);
|
|
120997
|
+
effects.consume(code);
|
|
120998
|
+
return onSuccess;
|
|
120999
|
+
};
|
|
121000
|
+
return { expectSlash };
|
|
121001
|
+
}
|
|
121002
|
+
/**
|
|
121003
|
+
* Partial construct for checking non-lazy continuation.
|
|
121004
|
+
* This is used by the flow tokenizer to check if we can continue
|
|
121005
|
+
* parsing on the next line.
|
|
121006
|
+
*/
|
|
121007
|
+
const syntax_nonLazyContinuation = {
|
|
121008
|
+
partial: true,
|
|
121009
|
+
tokenize: syntax_tokenizeNonLazyContinuation,
|
|
121010
|
+
};
|
|
121011
|
+
/**
|
|
121012
|
+
* Tokenizer for non-lazy continuation checking.
|
|
121013
|
+
* Returns ok if the next line is non-lazy (can continue), nok if lazy.
|
|
121014
|
+
*/
|
|
121015
|
+
function syntax_tokenizeNonLazyContinuation(effects, ok, nok) {
|
|
121016
|
+
const lineStart = (code) => {
|
|
121017
|
+
// `this` here refers to the micromark parser
|
|
121018
|
+
// since we are just passing functions as references and not actually calling them
|
|
121019
|
+
// micromarks's internal parser will call this automatically with appropriate arguments
|
|
121020
|
+
return this.parser.lazy[this.now().line] ? nok(code) : ok(code);
|
|
121021
|
+
};
|
|
121022
|
+
const start = (code) => {
|
|
121023
|
+
if (code === null) {
|
|
121024
|
+
return nok(code);
|
|
121025
|
+
}
|
|
121026
|
+
if (!markdownLineEnding(code)) {
|
|
121027
|
+
return nok(code);
|
|
121028
|
+
}
|
|
121029
|
+
effects.enter('magicBlockLineEnding');
|
|
121030
|
+
effects.consume(code);
|
|
121031
|
+
effects.exit('magicBlockLineEnding');
|
|
121032
|
+
return lineStart;
|
|
121033
|
+
};
|
|
121034
|
+
return start;
|
|
121035
|
+
}
|
|
121036
|
+
/**
|
|
121037
|
+
* Create a micromark extension for magic block syntax.
|
|
121038
|
+
*
|
|
121039
|
+
* This extension handles both single-line and multiline magic blocks:
|
|
121040
|
+
* - Flow construct (concrete): Handles block-level multiline magic blocks at document level
|
|
121041
|
+
* - Text construct: Handles inline magic blocks in lists, paragraphs, etc.
|
|
121042
|
+
*
|
|
121043
|
+
* The flow construct is marked as "concrete" which prevents it from being
|
|
121044
|
+
* interrupted by container markers (like `>` for blockquotes or `-` for lists).
|
|
121045
|
+
*/
|
|
121046
|
+
function magicBlock() {
|
|
121047
|
+
return {
|
|
121048
|
+
// Flow construct - handles block-level magic blocks at document root
|
|
121049
|
+
// Marked as concrete to prevent interruption by containers
|
|
121050
|
+
flow: {
|
|
121051
|
+
[codes.leftSquareBracket]: {
|
|
121052
|
+
name: 'magicBlock',
|
|
121053
|
+
concrete: true,
|
|
121054
|
+
tokenize: tokenizeMagicBlockFlow,
|
|
121055
|
+
},
|
|
121056
|
+
},
|
|
121057
|
+
// Text construct - handles magic blocks in inline contexts (lists, paragraphs)
|
|
121058
|
+
text: {
|
|
121059
|
+
[codes.leftSquareBracket]: {
|
|
121060
|
+
name: 'magicBlock',
|
|
121061
|
+
tokenize: tokenizeMagicBlockText,
|
|
121062
|
+
},
|
|
121063
|
+
},
|
|
121064
|
+
};
|
|
121065
|
+
}
|
|
121066
|
+
/**
|
|
121067
|
+
* Flow tokenizer for block-level magic blocks (multiline).
|
|
121068
|
+
* Uses the continuation checking pattern from code fences.
|
|
121069
|
+
*/
|
|
121070
|
+
function tokenizeMagicBlockFlow(effects, ok, nok) {
|
|
121071
|
+
// State for tracking JSON content
|
|
121072
|
+
const jsonState = { escapeNext: false, inString: false };
|
|
121073
|
+
const blockTypeRef = { value: '' };
|
|
121074
|
+
let seenOpenBrace = false;
|
|
121075
|
+
// Create shared parsers for opening marker and type capture
|
|
121076
|
+
const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
|
|
121077
|
+
const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
|
|
121078
|
+
return start;
|
|
121079
|
+
function start(code) {
|
|
121080
|
+
if (code !== codes.leftSquareBracket)
|
|
121081
|
+
return nok(code);
|
|
121082
|
+
effects.enter('magicBlock');
|
|
121083
|
+
effects.enter('magicBlockMarkerStart');
|
|
121084
|
+
effects.consume(code);
|
|
121085
|
+
return openingMarkerParser;
|
|
121086
|
+
}
|
|
121087
|
+
/**
|
|
121088
|
+
* State before data content - handles line endings or starts data capture.
|
|
121089
|
+
*/
|
|
121090
|
+
function beforeData(code) {
|
|
121091
|
+
// EOF - magic block must be closed
|
|
121092
|
+
if (code === null) {
|
|
121093
|
+
effects.exit('magicBlock');
|
|
121094
|
+
return nok(code);
|
|
121095
|
+
}
|
|
121096
|
+
// Line ending before any data - check continuation
|
|
121097
|
+
if (markdownLineEnding(code)) {
|
|
121098
|
+
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
121099
|
+
}
|
|
121100
|
+
// Check for closing marker directly (without entering data)
|
|
121101
|
+
// This handles cases like [block:type]\n{}\n\n[/block] where there are
|
|
121102
|
+
// newlines after the data object
|
|
121103
|
+
if (code === codes.leftSquareBracket) {
|
|
121104
|
+
effects.enter('magicBlockMarkerEnd');
|
|
121105
|
+
effects.consume(code);
|
|
121106
|
+
return expectSlashFromContinuation;
|
|
121107
|
+
}
|
|
121108
|
+
// If we've already seen the opening brace, just continue capturing data
|
|
121109
|
+
if (seenOpenBrace) {
|
|
121110
|
+
effects.enter('magicBlockData');
|
|
121111
|
+
return captureData(code);
|
|
121112
|
+
}
|
|
121113
|
+
// Skip whitespace (spaces/tabs) before the data - stay in beforeData
|
|
121114
|
+
// Don't enter magicBlockData token yet until we confirm there's a '{'
|
|
121115
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121116
|
+
return beforeDataWhitespace(code);
|
|
121117
|
+
}
|
|
121118
|
+
// Data must start with '{' for valid JSON
|
|
121119
|
+
if (code !== codes.leftCurlyBrace) {
|
|
121120
|
+
effects.exit('magicBlock');
|
|
121121
|
+
return nok(code);
|
|
121122
|
+
}
|
|
121123
|
+
// We have '{' - enter data token and start capturing
|
|
121124
|
+
seenOpenBrace = true;
|
|
121125
|
+
effects.enter('magicBlockData');
|
|
121126
|
+
return captureData(code);
|
|
121127
|
+
}
|
|
121128
|
+
/**
|
|
121129
|
+
* Consume whitespace before the data without creating a token.
|
|
121130
|
+
* Uses a temporary token to satisfy micromark's requirement.
|
|
121131
|
+
*/
|
|
121132
|
+
function beforeDataWhitespace(code) {
|
|
121133
|
+
if (code === null) {
|
|
121134
|
+
effects.exit('magicBlock');
|
|
121135
|
+
return nok(code);
|
|
121136
|
+
}
|
|
121137
|
+
if (markdownLineEnding(code)) {
|
|
121138
|
+
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
121139
|
+
}
|
|
121140
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121141
|
+
// We need to consume this but can't without a token - use magicBlockData
|
|
121142
|
+
// and track that we haven't seen '{' yet
|
|
121143
|
+
effects.enter('magicBlockData');
|
|
121144
|
+
effects.consume(code);
|
|
121145
|
+
return beforeDataWhitespaceContinue;
|
|
121146
|
+
}
|
|
121147
|
+
if (code === codes.leftCurlyBrace) {
|
|
121148
|
+
seenOpenBrace = true;
|
|
121149
|
+
effects.enter('magicBlockData');
|
|
121150
|
+
return captureData(code);
|
|
121151
|
+
}
|
|
121152
|
+
effects.exit('magicBlock');
|
|
121153
|
+
return nok(code);
|
|
121154
|
+
}
|
|
121155
|
+
/**
|
|
121156
|
+
* Continue consuming whitespace or validate the opening brace.
|
|
121157
|
+
*/
|
|
121158
|
+
function beforeDataWhitespaceContinue(code) {
|
|
121159
|
+
if (code === null) {
|
|
121160
|
+
effects.exit('magicBlockData');
|
|
121161
|
+
effects.exit('magicBlock');
|
|
121162
|
+
return nok(code);
|
|
121163
|
+
}
|
|
121164
|
+
if (markdownLineEnding(code)) {
|
|
121165
|
+
effects.exit('magicBlockData');
|
|
121166
|
+
return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
|
|
121167
|
+
}
|
|
121168
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121169
|
+
effects.consume(code);
|
|
121170
|
+
return beforeDataWhitespaceContinue;
|
|
121171
|
+
}
|
|
121172
|
+
if (code === codes.leftCurlyBrace) {
|
|
121173
|
+
seenOpenBrace = true;
|
|
121174
|
+
return captureData(code);
|
|
121175
|
+
}
|
|
121176
|
+
effects.exit('magicBlockData');
|
|
121177
|
+
effects.exit('magicBlock');
|
|
121178
|
+
return nok(code);
|
|
121179
|
+
}
|
|
121180
|
+
/**
|
|
121181
|
+
* Continuation OK before we've entered data token.
|
|
121182
|
+
*/
|
|
121183
|
+
function continuationOkBeforeData(code) {
|
|
121184
|
+
effects.enter('magicBlockLineEnding');
|
|
121185
|
+
effects.consume(code);
|
|
121186
|
+
effects.exit('magicBlockLineEnding');
|
|
121187
|
+
return beforeData; // Stay in beforeData state - don't enter magicBlockData yet
|
|
121188
|
+
}
|
|
121189
|
+
function captureData(code) {
|
|
121190
|
+
// EOF - magic block must be closed
|
|
121191
|
+
if (code === null) {
|
|
121192
|
+
effects.exit('magicBlockData');
|
|
121193
|
+
effects.exit('magicBlock');
|
|
121194
|
+
return nok(code);
|
|
121195
|
+
}
|
|
121196
|
+
// At line ending, check if we can continue on the next line
|
|
121197
|
+
if (markdownLineEnding(code)) {
|
|
121198
|
+
effects.exit('magicBlockData');
|
|
121199
|
+
return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
|
|
121200
|
+
}
|
|
121201
|
+
if (jsonState.escapeNext) {
|
|
121202
|
+
jsonState.escapeNext = false;
|
|
121203
|
+
effects.consume(code);
|
|
121204
|
+
return captureData;
|
|
121205
|
+
}
|
|
121206
|
+
if (jsonState.inString) {
|
|
121207
|
+
if (code === codes.backslash) {
|
|
121208
|
+
jsonState.escapeNext = true;
|
|
121209
|
+
effects.consume(code);
|
|
121210
|
+
return captureData;
|
|
121211
|
+
}
|
|
121212
|
+
if (code === codes.quotationMark) {
|
|
121213
|
+
jsonState.inString = false;
|
|
121214
|
+
}
|
|
121215
|
+
effects.consume(code);
|
|
121216
|
+
return captureData;
|
|
121217
|
+
}
|
|
121218
|
+
if (code === codes.quotationMark) {
|
|
121219
|
+
jsonState.inString = true;
|
|
121220
|
+
effects.consume(code);
|
|
121221
|
+
return captureData;
|
|
121222
|
+
}
|
|
121223
|
+
if (code === codes.leftSquareBracket) {
|
|
121224
|
+
effects.exit('magicBlockData');
|
|
121225
|
+
effects.enter('magicBlockMarkerEnd');
|
|
121226
|
+
effects.consume(code);
|
|
121227
|
+
return expectSlash;
|
|
121228
|
+
}
|
|
121229
|
+
effects.consume(code);
|
|
121230
|
+
return captureData;
|
|
121231
|
+
}
|
|
121232
|
+
/**
|
|
121233
|
+
* Called when non-lazy continuation check passes - we can continue parsing.
|
|
121234
|
+
*/
|
|
121235
|
+
function continuationOk(code) {
|
|
121236
|
+
// Consume the line ending
|
|
121237
|
+
effects.enter('magicBlockLineEnding');
|
|
121238
|
+
effects.consume(code);
|
|
121239
|
+
effects.exit('magicBlockLineEnding');
|
|
121240
|
+
return continuationStart;
|
|
121241
|
+
}
|
|
121242
|
+
/**
|
|
121243
|
+
* Start of continuation line - check for more line endings, closing marker, or start capturing data.
|
|
121244
|
+
*/
|
|
121245
|
+
function continuationStart(code) {
|
|
121246
|
+
// Handle consecutive line endings
|
|
121247
|
+
if (code === null) {
|
|
121248
|
+
effects.exit('magicBlock');
|
|
121249
|
+
return nok(code);
|
|
121250
|
+
}
|
|
121251
|
+
if (markdownLineEnding(code)) {
|
|
121252
|
+
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
121253
|
+
}
|
|
121254
|
+
// Check if this is the start of the closing marker [/block]
|
|
121255
|
+
// If so, handle it directly without entering magicBlockData
|
|
121256
|
+
if (code === codes.leftSquareBracket) {
|
|
121257
|
+
effects.enter('magicBlockMarkerEnd');
|
|
121258
|
+
effects.consume(code);
|
|
121259
|
+
return expectSlashFromContinuation;
|
|
121260
|
+
}
|
|
121261
|
+
effects.enter('magicBlockData');
|
|
121262
|
+
return captureData(code);
|
|
121263
|
+
}
|
|
121264
|
+
/**
|
|
121265
|
+
* Check for closing marker slash when coming from continuation.
|
|
121266
|
+
* If not a closing marker, create an empty data token and continue.
|
|
121267
|
+
*/
|
|
121268
|
+
function expectSlashFromContinuation(code) {
|
|
121269
|
+
if (code === null) {
|
|
121270
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121271
|
+
effects.exit('magicBlock');
|
|
121272
|
+
return nok(code);
|
|
121273
|
+
}
|
|
121274
|
+
if (markdownLineEnding(code)) {
|
|
121275
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121276
|
+
return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
|
|
121277
|
+
}
|
|
121278
|
+
if (code === codes.slash) {
|
|
121279
|
+
effects.consume(code);
|
|
121280
|
+
return expectClosingB;
|
|
121281
|
+
}
|
|
121282
|
+
// Not a closing marker - this is data content
|
|
121283
|
+
// Exit marker and enter data
|
|
121284
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121285
|
+
effects.enter('magicBlockData');
|
|
121286
|
+
// The [ was consumed by the marker, so we need to conceptually "have it" in our data
|
|
121287
|
+
// But since we already consumed it into the marker, we need a different approach
|
|
121288
|
+
// Re-classify: consume this character as data and continue
|
|
121289
|
+
if (code === codes.quotationMark)
|
|
121290
|
+
jsonState.inString = true;
|
|
121291
|
+
effects.consume(code);
|
|
121292
|
+
return captureData;
|
|
121293
|
+
}
|
|
121294
|
+
function expectSlash(code) {
|
|
121295
|
+
if (code === null) {
|
|
121296
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121297
|
+
effects.exit('magicBlock');
|
|
121298
|
+
return nok(code);
|
|
121299
|
+
}
|
|
121300
|
+
// At line ending during marker parsing
|
|
121301
|
+
if (markdownLineEnding(code)) {
|
|
121302
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121303
|
+
return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
|
|
121304
|
+
}
|
|
121305
|
+
if (code !== codes.slash) {
|
|
121306
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121307
|
+
effects.enter('magicBlockData');
|
|
121308
|
+
if (code === codes.quotationMark)
|
|
121309
|
+
jsonState.inString = true;
|
|
121310
|
+
effects.consume(code);
|
|
121311
|
+
return captureData;
|
|
121312
|
+
}
|
|
121313
|
+
effects.consume(code);
|
|
121314
|
+
return expectClosingB;
|
|
121315
|
+
}
|
|
121316
|
+
function expectClosingB(code) {
|
|
121317
|
+
if (code === null) {
|
|
121318
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121319
|
+
effects.exit('magicBlock');
|
|
121320
|
+
return nok(code);
|
|
121321
|
+
}
|
|
121322
|
+
if (code !== codes.lowercaseB) {
|
|
121323
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121324
|
+
effects.enter('magicBlockData');
|
|
121325
|
+
if (code === codes.quotationMark)
|
|
121326
|
+
jsonState.inString = true;
|
|
121327
|
+
effects.consume(code);
|
|
121328
|
+
return captureData;
|
|
121329
|
+
}
|
|
121330
|
+
effects.consume(code);
|
|
121331
|
+
return expectClosingL;
|
|
121332
|
+
}
|
|
121333
|
+
function expectClosingL(code) {
|
|
121334
|
+
if (code === null) {
|
|
121335
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121336
|
+
effects.exit('magicBlock');
|
|
121337
|
+
return nok(code);
|
|
121338
|
+
}
|
|
121339
|
+
if (code !== codes.lowercaseL) {
|
|
121340
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121341
|
+
effects.enter('magicBlockData');
|
|
121342
|
+
if (code === codes.quotationMark)
|
|
121343
|
+
jsonState.inString = true;
|
|
121344
|
+
effects.consume(code);
|
|
121345
|
+
return captureData;
|
|
121346
|
+
}
|
|
121347
|
+
effects.consume(code);
|
|
121348
|
+
return expectClosingO;
|
|
121349
|
+
}
|
|
121350
|
+
function expectClosingO(code) {
|
|
121351
|
+
if (code === null) {
|
|
121352
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121353
|
+
effects.exit('magicBlock');
|
|
121354
|
+
return nok(code);
|
|
121355
|
+
}
|
|
121356
|
+
if (code !== codes.lowercaseO) {
|
|
121357
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121358
|
+
effects.enter('magicBlockData');
|
|
121359
|
+
if (code === codes.quotationMark)
|
|
121360
|
+
jsonState.inString = true;
|
|
121361
|
+
effects.consume(code);
|
|
121362
|
+
return captureData;
|
|
121363
|
+
}
|
|
121364
|
+
effects.consume(code);
|
|
121365
|
+
return expectClosingC;
|
|
121366
|
+
}
|
|
121367
|
+
function expectClosingC(code) {
|
|
121368
|
+
if (code === null) {
|
|
121369
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121370
|
+
effects.exit('magicBlock');
|
|
121371
|
+
return nok(code);
|
|
121372
|
+
}
|
|
121373
|
+
if (code !== codes.lowercaseC) {
|
|
121374
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121375
|
+
effects.enter('magicBlockData');
|
|
121376
|
+
if (code === codes.quotationMark)
|
|
121377
|
+
jsonState.inString = true;
|
|
121378
|
+
effects.consume(code);
|
|
121379
|
+
return captureData;
|
|
121380
|
+
}
|
|
121381
|
+
effects.consume(code);
|
|
121382
|
+
return expectClosingK;
|
|
121383
|
+
}
|
|
121384
|
+
function expectClosingK(code) {
|
|
121385
|
+
if (code === null) {
|
|
121386
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121387
|
+
effects.exit('magicBlock');
|
|
121388
|
+
return nok(code);
|
|
121389
|
+
}
|
|
121390
|
+
if (code !== codes.lowercaseK) {
|
|
121391
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121392
|
+
effects.enter('magicBlockData');
|
|
121393
|
+
if (code === codes.quotationMark)
|
|
121394
|
+
jsonState.inString = true;
|
|
121395
|
+
effects.consume(code);
|
|
121396
|
+
return captureData;
|
|
121397
|
+
}
|
|
121398
|
+
effects.consume(code);
|
|
121399
|
+
return expectClosingBracket;
|
|
121400
|
+
}
|
|
121401
|
+
function expectClosingBracket(code) {
|
|
121402
|
+
if (code === null) {
|
|
121403
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121404
|
+
effects.exit('magicBlock');
|
|
121405
|
+
return nok(code);
|
|
121406
|
+
}
|
|
121407
|
+
if (code !== codes.rightSquareBracket) {
|
|
121408
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121409
|
+
effects.enter('magicBlockData');
|
|
121410
|
+
if (code === codes.quotationMark)
|
|
121411
|
+
jsonState.inString = true;
|
|
121412
|
+
effects.consume(code);
|
|
121413
|
+
return captureData;
|
|
121414
|
+
}
|
|
121415
|
+
effects.consume(code);
|
|
121416
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121417
|
+
// Check for trailing whitespace on the same line
|
|
121418
|
+
return consumeTrailing;
|
|
121419
|
+
}
|
|
121420
|
+
/**
|
|
121421
|
+
* Consume trailing whitespace (spaces/tabs) on the same line after [/block].
|
|
121422
|
+
* For concrete flow constructs, we must end at eol/eof or fail.
|
|
121423
|
+
* Trailing whitespace is consumed; other content causes nok (text tokenizer handles it).
|
|
121424
|
+
*/
|
|
121425
|
+
function consumeTrailing(code) {
|
|
121426
|
+
// End of file - done
|
|
121427
|
+
if (code === null) {
|
|
121428
|
+
effects.exit('magicBlock');
|
|
121429
|
+
return ok(code);
|
|
121430
|
+
}
|
|
121431
|
+
// Line ending - done
|
|
121432
|
+
if (markdownLineEnding(code)) {
|
|
121433
|
+
effects.exit('magicBlock');
|
|
121434
|
+
return ok(code);
|
|
121435
|
+
}
|
|
121436
|
+
// Space or tab - consume as trailing whitespace
|
|
121437
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121438
|
+
effects.enter('magicBlockTrailing');
|
|
121439
|
+
effects.consume(code);
|
|
121440
|
+
return consumeTrailingContinue;
|
|
121441
|
+
}
|
|
121442
|
+
// Any other character - fail flow tokenizer, let text tokenizer handle it
|
|
121443
|
+
effects.exit('magicBlock');
|
|
121444
|
+
return nok(code);
|
|
121445
|
+
}
|
|
121446
|
+
/**
|
|
121447
|
+
* Continue consuming trailing whitespace.
|
|
121448
|
+
*/
|
|
121449
|
+
function consumeTrailingContinue(code) {
|
|
121450
|
+
// End of file - done
|
|
121451
|
+
if (code === null) {
|
|
121452
|
+
effects.exit('magicBlockTrailing');
|
|
121453
|
+
effects.exit('magicBlock');
|
|
121454
|
+
return ok(code);
|
|
121455
|
+
}
|
|
121456
|
+
// Line ending - done
|
|
121457
|
+
if (markdownLineEnding(code)) {
|
|
121458
|
+
effects.exit('magicBlockTrailing');
|
|
121459
|
+
effects.exit('magicBlock');
|
|
121460
|
+
return ok(code);
|
|
121461
|
+
}
|
|
121462
|
+
// More space or tab - keep consuming
|
|
121463
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121464
|
+
effects.consume(code);
|
|
121465
|
+
return consumeTrailingContinue;
|
|
121466
|
+
}
|
|
121467
|
+
// Non-whitespace after whitespace - fail flow tokenizer
|
|
121468
|
+
effects.exit('magicBlockTrailing');
|
|
121469
|
+
effects.exit('magicBlock');
|
|
121470
|
+
return nok(code);
|
|
121471
|
+
}
|
|
121472
|
+
/**
|
|
121473
|
+
* Called when we can't continue (lazy line or EOF) - exit the construct.
|
|
121474
|
+
*/
|
|
121475
|
+
function after(code) {
|
|
121476
|
+
effects.exit('magicBlock');
|
|
121477
|
+
return nok(code);
|
|
121478
|
+
}
|
|
121479
|
+
}
|
|
121480
|
+
/**
|
|
121481
|
+
* Text tokenizer for single-line magic blocks only.
|
|
121482
|
+
* Used in inline contexts like list items and paragraphs.
|
|
121483
|
+
* Multiline blocks are handled by the flow tokenizer.
|
|
121484
|
+
*/
|
|
121485
|
+
function tokenizeMagicBlockText(effects, ok, nok) {
|
|
121486
|
+
// State for tracking JSON content
|
|
121487
|
+
const jsonState = { escapeNext: false, inString: false };
|
|
121488
|
+
const blockTypeRef = { value: '' };
|
|
121489
|
+
let seenOpenBrace = false;
|
|
121490
|
+
// Create shared parsers for opening marker and type capture
|
|
121491
|
+
const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
|
|
121492
|
+
const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
|
|
121493
|
+
// Success handler for closing marker - exits tokens and returns ok
|
|
121494
|
+
const closingSuccess = (code) => {
|
|
121495
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121496
|
+
effects.exit('magicBlock');
|
|
121497
|
+
return ok(code);
|
|
121498
|
+
};
|
|
121499
|
+
// Mismatch handler - falls back to data capture
|
|
121500
|
+
const closingMismatch = (code) => {
|
|
121501
|
+
effects.exit('magicBlockMarkerEnd');
|
|
121502
|
+
effects.enter('magicBlockData');
|
|
121503
|
+
if (code === codes.quotationMark)
|
|
121504
|
+
jsonState.inString = true;
|
|
121505
|
+
effects.consume(code);
|
|
121506
|
+
return captureData;
|
|
121507
|
+
};
|
|
121508
|
+
// EOF handler
|
|
121509
|
+
const closingEof = (_code) => nok(_code);
|
|
121510
|
+
// Create closing marker parsers
|
|
121511
|
+
const closingFromBeforeData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
|
|
121512
|
+
const closingFromData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
|
|
121513
|
+
return start;
|
|
121514
|
+
function start(code) {
|
|
121515
|
+
if (code !== codes.leftSquareBracket)
|
|
121516
|
+
return nok(code);
|
|
121517
|
+
effects.enter('magicBlock');
|
|
121518
|
+
effects.enter('magicBlockMarkerStart');
|
|
121519
|
+
effects.consume(code);
|
|
121520
|
+
return openingMarkerParser;
|
|
121521
|
+
}
|
|
121522
|
+
/**
|
|
121523
|
+
* State before data content - handles line endings before entering data token.
|
|
121524
|
+
* Whitespace before '{' is allowed.
|
|
121525
|
+
*/
|
|
121526
|
+
function beforeData(code) {
|
|
121527
|
+
// Fail on EOF - magic block must be closed
|
|
121528
|
+
if (code === null) {
|
|
121529
|
+
return nok(code);
|
|
121530
|
+
}
|
|
121531
|
+
// Handle line endings before any data - consume them without entering data token
|
|
121532
|
+
if (markdownLineEnding(code)) {
|
|
121533
|
+
effects.enter('magicBlockLineEnding');
|
|
121534
|
+
effects.consume(code);
|
|
121535
|
+
effects.exit('magicBlockLineEnding');
|
|
121536
|
+
return beforeData;
|
|
121537
|
+
}
|
|
121538
|
+
// Check for closing marker directly (without entering data)
|
|
121539
|
+
if (code === codes.leftSquareBracket) {
|
|
121540
|
+
effects.enter('magicBlockMarkerEnd');
|
|
121541
|
+
effects.consume(code);
|
|
121542
|
+
return closingFromBeforeData.expectSlash;
|
|
121543
|
+
}
|
|
121544
|
+
// If we've already seen the opening brace, just continue capturing data
|
|
121545
|
+
if (seenOpenBrace) {
|
|
121546
|
+
effects.enter('magicBlockData');
|
|
121547
|
+
return captureData(code);
|
|
121548
|
+
}
|
|
121549
|
+
// Skip whitespace (spaces/tabs) before the data
|
|
121550
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121551
|
+
return beforeDataWhitespace(code);
|
|
121552
|
+
}
|
|
121553
|
+
// Data must start with '{' for valid JSON
|
|
121554
|
+
if (code !== codes.leftCurlyBrace) {
|
|
121555
|
+
return nok(code);
|
|
121556
|
+
}
|
|
121557
|
+
// We have '{' - enter data token and start capturing
|
|
121558
|
+
seenOpenBrace = true;
|
|
121559
|
+
effects.enter('magicBlockData');
|
|
121560
|
+
return captureData(code);
|
|
121561
|
+
}
|
|
121562
|
+
/**
|
|
121563
|
+
* Consume whitespace before the data.
|
|
121564
|
+
*/
|
|
121565
|
+
function beforeDataWhitespace(code) {
|
|
121566
|
+
if (code === null) {
|
|
121567
|
+
return nok(code);
|
|
121568
|
+
}
|
|
121569
|
+
if (markdownLineEnding(code)) {
|
|
121570
|
+
effects.enter('magicBlockLineEnding');
|
|
121571
|
+
effects.consume(code);
|
|
121572
|
+
effects.exit('magicBlockLineEnding');
|
|
121573
|
+
return beforeData;
|
|
121574
|
+
}
|
|
121575
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121576
|
+
effects.enter('magicBlockData');
|
|
121577
|
+
effects.consume(code);
|
|
121578
|
+
return beforeDataWhitespaceContinue;
|
|
121579
|
+
}
|
|
121580
|
+
if (code === codes.leftCurlyBrace) {
|
|
121581
|
+
seenOpenBrace = true;
|
|
121582
|
+
effects.enter('magicBlockData');
|
|
121583
|
+
return captureData(code);
|
|
121584
|
+
}
|
|
121585
|
+
return nok(code);
|
|
121586
|
+
}
|
|
121587
|
+
/**
|
|
121588
|
+
* Continue consuming whitespace or validate the opening brace.
|
|
121589
|
+
*/
|
|
121590
|
+
function beforeDataWhitespaceContinue(code) {
|
|
121591
|
+
if (code === null) {
|
|
121592
|
+
effects.exit('magicBlockData');
|
|
121593
|
+
return nok(code);
|
|
121594
|
+
}
|
|
121595
|
+
if (markdownLineEnding(code)) {
|
|
121596
|
+
effects.exit('magicBlockData');
|
|
121597
|
+
effects.enter('magicBlockLineEnding');
|
|
121598
|
+
effects.consume(code);
|
|
121599
|
+
effects.exit('magicBlockLineEnding');
|
|
121600
|
+
return beforeData;
|
|
121601
|
+
}
|
|
121602
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121603
|
+
effects.consume(code);
|
|
121604
|
+
return beforeDataWhitespaceContinue;
|
|
121605
|
+
}
|
|
121606
|
+
if (code === codes.leftCurlyBrace) {
|
|
121607
|
+
seenOpenBrace = true;
|
|
121608
|
+
return captureData(code);
|
|
121609
|
+
}
|
|
121610
|
+
effects.exit('magicBlockData');
|
|
121611
|
+
return nok(code);
|
|
121612
|
+
}
|
|
121613
|
+
function captureData(code) {
|
|
121614
|
+
// Fail on EOF - magic block must be closed
|
|
121615
|
+
if (code === null) {
|
|
121616
|
+
effects.exit('magicBlockData');
|
|
121617
|
+
return nok(code);
|
|
121618
|
+
}
|
|
121619
|
+
// Handle multiline magic blocks within text/paragraphs
|
|
121620
|
+
// Exit data, consume line ending with proper token, then re-enter data
|
|
121621
|
+
if (markdownLineEnding(code)) {
|
|
121622
|
+
effects.exit('magicBlockData');
|
|
121623
|
+
effects.enter('magicBlockLineEnding');
|
|
121624
|
+
effects.consume(code);
|
|
121625
|
+
effects.exit('magicBlockLineEnding');
|
|
121626
|
+
return beforeData; // Go back to beforeData to handle potential empty lines
|
|
121627
|
+
}
|
|
121628
|
+
if (jsonState.escapeNext) {
|
|
121629
|
+
jsonState.escapeNext = false;
|
|
121630
|
+
effects.consume(code);
|
|
121631
|
+
return captureData;
|
|
121632
|
+
}
|
|
121633
|
+
if (jsonState.inString) {
|
|
121634
|
+
if (code === codes.backslash) {
|
|
121635
|
+
jsonState.escapeNext = true;
|
|
121636
|
+
effects.consume(code);
|
|
121637
|
+
return captureData;
|
|
121638
|
+
}
|
|
121639
|
+
if (code === codes.quotationMark) {
|
|
121640
|
+
jsonState.inString = false;
|
|
121641
|
+
}
|
|
121642
|
+
effects.consume(code);
|
|
121643
|
+
return captureData;
|
|
121644
|
+
}
|
|
121645
|
+
if (code === codes.quotationMark) {
|
|
121646
|
+
jsonState.inString = true;
|
|
121647
|
+
effects.consume(code);
|
|
121648
|
+
return captureData;
|
|
121649
|
+
}
|
|
121650
|
+
if (code === codes.leftSquareBracket) {
|
|
121651
|
+
effects.exit('magicBlockData');
|
|
121652
|
+
effects.enter('magicBlockMarkerEnd');
|
|
121653
|
+
effects.consume(code);
|
|
121654
|
+
return closingFromData.expectSlash;
|
|
121655
|
+
}
|
|
121656
|
+
effects.consume(code);
|
|
121657
|
+
return captureData;
|
|
121658
|
+
}
|
|
121659
|
+
}
|
|
121660
|
+
/* harmony default export */ const syntax = ((/* unused pure expression or super */ null && (magicBlock)));
|
|
121661
|
+
|
|
121662
|
+
;// ./lib/micromark/magic-block/index.ts
|
|
121663
|
+
/**
|
|
121664
|
+
* Micromark extension for magic block syntax.
|
|
121665
|
+
*
|
|
121666
|
+
* Usage:
|
|
121667
|
+
* ```ts
|
|
121668
|
+
* import { magicBlock } from './lib/micromark/magic-block';
|
|
121669
|
+
*
|
|
121670
|
+
* const processor = unified()
|
|
121671
|
+
* .data('micromarkExtensions', [magicBlock()])
|
|
121672
|
+
* ```
|
|
121673
|
+
*/
|
|
121674
|
+
|
|
121675
|
+
|
|
121676
|
+
;// ./lib/micromark/mdx-component/syntax.ts
|
|
121677
|
+
|
|
121678
|
+
|
|
121679
|
+
|
|
121680
|
+
|
|
121681
|
+
|
|
121682
|
+
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
121683
|
+
// section, …) always start a block, so they stay flow even with trailing
|
|
121684
|
+
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
121685
|
+
// stay flow when nothing trails the close tag.
|
|
121686
|
+
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
121687
|
+
// Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
|
|
121688
|
+
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
121689
|
+
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
121690
|
+
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
121691
|
+
const mdx_component_syntax_nonLazyContinuationStart = {
|
|
121692
|
+
tokenize: mdx_component_syntax_tokenizeNonLazyContinuationStart,
|
|
121693
|
+
partial: true,
|
|
121694
|
+
};
|
|
121695
|
+
// Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
|
|
121696
|
+
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
121697
|
+
const markupOnlyContinuation = {
|
|
121698
|
+
tokenize: tokenizeMarkupOnlyContinuation,
|
|
121699
|
+
partial: true,
|
|
121700
|
+
};
|
|
121701
|
+
function resolveToMdxComponent(events) {
|
|
121702
|
+
let index = events.length;
|
|
121703
|
+
while (index > 0) {
|
|
121704
|
+
index -= 1;
|
|
121705
|
+
if (events[index][0] === 'enter' && events[index][1].type === 'mdxComponent') {
|
|
121706
|
+
break;
|
|
121707
|
+
}
|
|
121708
|
+
}
|
|
121709
|
+
if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
|
|
121710
|
+
events[index][1].start = events[index - 2][1].start;
|
|
121711
|
+
events[index + 1][1].start = events[index - 2][1].start;
|
|
121712
|
+
events.splice(index - 2, 2);
|
|
121713
|
+
}
|
|
121714
|
+
return events;
|
|
121715
|
+
}
|
|
121716
|
+
const mdxComponentFlowConstruct = {
|
|
121717
|
+
name: 'mdxComponent',
|
|
121718
|
+
tokenize: createTokenize('flow'),
|
|
121719
|
+
resolveTo: resolveToMdxComponent,
|
|
121720
|
+
concrete: true,
|
|
121721
|
+
};
|
|
121722
|
+
const mdxComponentTextConstruct = {
|
|
121723
|
+
name: 'mdxComponentText',
|
|
121724
|
+
tokenize: createTokenize('text'),
|
|
121725
|
+
};
|
|
121726
|
+
/**
|
|
121727
|
+
* Factory for both flow (block) and text (inline) variants.
|
|
121728
|
+
*
|
|
121729
|
+
* **Flow** — the original behavior: claims PascalCase components (always) and
|
|
121730
|
+
* lowercase HTML tags that carry at least one `{…}` attribute expression.
|
|
121731
|
+
* Multi-line, concrete, `afterClose` consumes the rest of the line.
|
|
121732
|
+
*
|
|
121733
|
+
* **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
|
|
121734
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
|
|
121735
|
+
* gated on at least one `{…}` brace attribute. All other PascalCase stays
|
|
121736
|
+
* flow-only, matching how ReadMe's custom components are authored. Aborts on line
|
|
121737
|
+
* endings (inline constructs don't span lines) and exits immediately after
|
|
121738
|
+
* `</tag>` so the paragraph's inline parser picks up the trailing text.
|
|
121739
|
+
*/
|
|
121740
|
+
function createTokenize(mode) {
|
|
121741
|
+
const isFlow = mode === 'flow';
|
|
121742
|
+
return function tokenize(effects, ok, nok) {
|
|
121743
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
121744
|
+
const self = this;
|
|
121745
|
+
let tagName = '';
|
|
121746
|
+
let depth = 0;
|
|
121747
|
+
let closingTagName = '';
|
|
121748
|
+
// For lowercase tags we only want to claim the block if it uses JSX
|
|
121749
|
+
// attribute expression syntax (`attr={...}`). Plain HTML should fall
|
|
121750
|
+
// through to CommonMark html-flow. Flow mode claims any PascalCase block
|
|
121751
|
+
// component; text mode claims only inline PascalCase components
|
|
121752
|
+
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
121753
|
+
let isLowercaseTag = false;
|
|
121754
|
+
let sawBraceAttr = false;
|
|
121755
|
+
// A plain lowercase block tag claimed without a `{…}` attribute, gated by
|
|
121756
|
+
// `plainClaimLineStart`: after a blank line it may only continue on a tag line.
|
|
121757
|
+
let isPlainBlockClaim = false;
|
|
121758
|
+
let pendingBlankLine = false;
|
|
121759
|
+
// Code span tracking
|
|
121760
|
+
let codeSpanOpenSize = 0;
|
|
121761
|
+
let codeSpanCloseSize = 0;
|
|
121762
|
+
// Fenced code block tracking
|
|
121763
|
+
let fenceChar = null;
|
|
121764
|
+
let fenceLength = 0;
|
|
121765
|
+
let fenceCloseLength = 0;
|
|
121766
|
+
let atLineStart = false;
|
|
121767
|
+
// True once this construct consumes any line ending; lets `afterClose`
|
|
121768
|
+
// treat only single-line lowercase tags as inline candidates.
|
|
121769
|
+
let sawLineEnding = false;
|
|
121770
|
+
// Bail when the opener line has unmatched tag-like tokens in its body.
|
|
121771
|
+
// `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
|
|
121772
|
+
// `<Callout>x <strong>y</strong>` balance to 0. Without this,
|
|
121773
|
+
// `concrete: true` causes orphan openers to eat sibling blockquotes.
|
|
121774
|
+
let onOpenerLine = false;
|
|
121775
|
+
let openerLineHasContent = false;
|
|
121776
|
+
let openerLineOpens = 0;
|
|
121777
|
+
let openerLineCloses = 0;
|
|
121778
|
+
// Attribute parsing state
|
|
121779
|
+
let quoteChar = null;
|
|
121780
|
+
let braceDepth = 0;
|
|
121476
121781
|
let inTemplateLit = false; // true when inside a template literal (for line continuation)
|
|
121477
121782
|
// Stack of braceDepth values at each ${...} interpolation entry point.
|
|
121478
121783
|
// When a } brings braceDepth back to a saved value, we return to the
|
|
@@ -121750,7 +122055,7 @@ function createTokenize(mode) {
|
|
|
121750
122055
|
}
|
|
121751
122056
|
// Continuation for multi-line opening tags
|
|
121752
122057
|
function openTagContinuationStart(code) {
|
|
121753
|
-
return effects.check(
|
|
122058
|
+
return effects.check(mdx_component_syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
|
|
121754
122059
|
}
|
|
121755
122060
|
function openTagContinuationNonLazy(code) {
|
|
121756
122061
|
sawLineEnding = true;
|
|
@@ -121875,7 +122180,7 @@ function createTokenize(mode) {
|
|
|
121875
122180
|
return inFencedCode;
|
|
121876
122181
|
}
|
|
121877
122182
|
function fencedCodeContinuationStart(code) {
|
|
121878
|
-
return effects.check(
|
|
122183
|
+
return effects.check(mdx_component_syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
|
|
121879
122184
|
}
|
|
121880
122185
|
function fencedCodeContinuationNonLazy(code) {
|
|
121881
122186
|
sawLineEnding = true;
|
|
@@ -121890,6 +122195,16 @@ function createTokenize(mode) {
|
|
|
121890
122195
|
}
|
|
121891
122196
|
effects.enter('mdxComponentData');
|
|
121892
122197
|
fenceCloseLength = 0;
|
|
122198
|
+
return fencedCodeMaybeClose(code);
|
|
122199
|
+
}
|
|
122200
|
+
// Skip leading indentation before the closing-fence check: an indented fence
|
|
122201
|
+
// (the norm in a component body) closes on an equally-indented line, else the
|
|
122202
|
+
// closer is never matched and scanning runs to EOF (CX-3704).
|
|
122203
|
+
function fencedCodeMaybeClose(code) {
|
|
122204
|
+
if (markdownSpace(code)) {
|
|
122205
|
+
effects.consume(code);
|
|
122206
|
+
return fencedCodeMaybeClose;
|
|
122207
|
+
}
|
|
121893
122208
|
// Check for closing fence
|
|
121894
122209
|
if (code === fenceChar) {
|
|
121895
122210
|
fenceCloseLength = 1;
|
|
@@ -122073,7 +122388,7 @@ function createTokenize(mode) {
|
|
|
122073
122388
|
}
|
|
122074
122389
|
// ── Body continuation (line endings) ───────────────────────────────────
|
|
122075
122390
|
function bodyContinuationStart(code) {
|
|
122076
|
-
return effects.check(
|
|
122391
|
+
return effects.check(mdx_component_syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
|
|
122077
122392
|
}
|
|
122078
122393
|
function bodyContinuationNonLazy(code) {
|
|
122079
122394
|
sawLineEnding = true;
|
|
@@ -122105,6 +122420,13 @@ function createTokenize(mode) {
|
|
|
122105
122420
|
}
|
|
122106
122421
|
// Dispatch a non-blank continuation line: fenced code at line start, else body.
|
|
122107
122422
|
function bodyLineStart(code) {
|
|
122423
|
+
// Skip leading indentation while staying "at line start" so an indented
|
|
122424
|
+
// fence is still recognized. Otherwise the first space clears `atLineStart`
|
|
122425
|
+
// and its content — including any unbalanced `{` — stays live text (CX-3704).
|
|
122426
|
+
if (atLineStart && markdownSpace(code)) {
|
|
122427
|
+
effects.consume(code);
|
|
122428
|
+
return bodyLineStart;
|
|
122429
|
+
}
|
|
122108
122430
|
if (atLineStart && code === codes.tilde)
|
|
122109
122431
|
return bodyAfterLineStart(code);
|
|
122110
122432
|
if (atLineStart && code === codes.graveAccent) {
|
|
@@ -122155,7 +122477,7 @@ function createTokenize(mode) {
|
|
|
122155
122477
|
}
|
|
122156
122478
|
};
|
|
122157
122479
|
}
|
|
122158
|
-
function
|
|
122480
|
+
function mdx_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
122159
122481
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
122160
122482
|
const self = this;
|
|
122161
122483
|
return start;
|
|
@@ -122263,9 +122585,20 @@ function mdxComponent() {
|
|
|
122263
122585
|
|
|
122264
122586
|
|
|
122265
122587
|
|
|
122588
|
+
|
|
122589
|
+
|
|
122590
|
+
|
|
122591
|
+
|
|
122592
|
+
|
|
122593
|
+
|
|
122266
122594
|
const buildInlineMdProcessor = (safeMode) => {
|
|
122267
|
-
|
|
122595
|
+
// `jsxTable` must be present so a `<Table>`/`<table>` nested in a component
|
|
122596
|
+
// body (e.g. a `<Callout>`) is captured as one html node. Without it, blank
|
|
122597
|
+
// lines between rows let CommonMark HTML block type 6 fragment the table and
|
|
122598
|
+
// its rows spill out as text / indented code blocks (CX-3705).
|
|
122599
|
+
const micromarkExts = [jsxTable(), mdxComponent(), syntax_gemoji(), legacyVariable(), magicBlock()];
|
|
122268
122600
|
const fromMarkdownExts = [
|
|
122601
|
+
jsxTableFromMarkdown(),
|
|
122269
122602
|
mdxComponentFromMarkdown(),
|
|
122270
122603
|
gemojiFromMarkdown(),
|
|
122271
122604
|
legacyVariableFromMarkdown(),
|
|
@@ -122325,6 +122658,65 @@ const toMdxJsxTextElement = (name, attributes, children, position) => ({
|
|
|
122325
122658
|
children,
|
|
122326
122659
|
...(position ? { position } : {}),
|
|
122327
122660
|
});
|
|
122661
|
+
// Raw-body tags (pre/script/style/textarea) must stay byte-exact; table
|
|
122662
|
+
// structure (`table` + `tableTags`) is owned by `mdxishTables` and figures by
|
|
122663
|
+
// `mdxishJsxToMdast`, both of which run later on raw html nodes.
|
|
122664
|
+
const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table', 'figure', 'figcaption']);
|
|
122665
|
+
const NESTED_TABLE_RE = /<table[\s>]/i;
|
|
122666
|
+
const isMarkdownPromotableHtmlTag = (tag) => !NON_PROMOTABLE_PLAIN_TAGS.has(tag);
|
|
122667
|
+
// Expression nodes count as plain so `<div>{1+1}</div>` keeps its current
|
|
122668
|
+
// literal-brace behavior; variables/glossary already resolve inside raw html.
|
|
122669
|
+
const PLAIN_CONTENT_TYPES = new Set([
|
|
122670
|
+
'paragraph',
|
|
122671
|
+
'text',
|
|
122672
|
+
'html',
|
|
122673
|
+
'mdxTextExpression',
|
|
122674
|
+
'mdxFlowExpression',
|
|
122675
|
+
NodeTypes.variable,
|
|
122676
|
+
NodeTypes.glossary,
|
|
122677
|
+
]);
|
|
122678
|
+
// Promoting plain HTML is only worth bypassing rehype-raw's parse5 pass when
|
|
122679
|
+
// the body parses into an actual markdown construct.
|
|
122680
|
+
const containsMarkdownConstruct = (nodes) => nodes.some(node => !PLAIN_CONTENT_TYPES.has(node.type) ||
|
|
122681
|
+
('children' in node && Array.isArray(node.children) && containsMarkdownConstruct(node.children)));
|
|
122682
|
+
/**
|
|
122683
|
+
* Index of the `</tag>` that balances the already-consumed opening tag (the
|
|
122684
|
+
* caller starts us one level deep). `lastIndexOf` mis-slices sibling same-tag
|
|
122685
|
+
* pairs like `<div>**a**</div><div>**b**</div>`, so we depth-match instead —
|
|
122686
|
+
* delegating to `walkTags` (htmlparser2) so quoted attributes (`title="</div>"`),
|
|
122687
|
+
* code spans, and legacy `<<VARIABLE>>` are handled for free. Returns -1 when
|
|
122688
|
+
* the wrapper is left open.
|
|
122689
|
+
*/
|
|
122690
|
+
function findBalancedClosingTagIndex(content, tag) {
|
|
122691
|
+
const target = tag.toLowerCase();
|
|
122692
|
+
const canonicalCloserLength = tag.length + 3; // `</tag>`
|
|
122693
|
+
// The caller already stripped the opening tag, so re-attach one: htmlparser2
|
|
122694
|
+
// drops an unmatched closer, and we want it balanced. Offsets shift by the
|
|
122695
|
+
// prefix length.
|
|
122696
|
+
const prefix = `<${tag}>`;
|
|
122697
|
+
let depth = 0;
|
|
122698
|
+
let closeIndex = -1;
|
|
122699
|
+
walkTags(prefix + content, {
|
|
122700
|
+
onOpen: ({ name, isSelfClosing, isStrayCloser }) => {
|
|
122701
|
+
if (closeIndex >= 0 || isSelfClosing || isStrayCloser)
|
|
122702
|
+
return;
|
|
122703
|
+
if (name.toLowerCase() === target)
|
|
122704
|
+
depth += 1;
|
|
122705
|
+
},
|
|
122706
|
+
onClose: ({ name, start, end, implicit }) => {
|
|
122707
|
+
if (closeIndex >= 0 || implicit || name.toLowerCase() !== target)
|
|
122708
|
+
return;
|
|
122709
|
+
// Only canonical `</tag>` closers — the caller slices by that length, so a
|
|
122710
|
+
// whitespaced `</tag >` would misalign; leaving it unmatched keeps it raw.
|
|
122711
|
+
if (end - start !== canonicalCloserLength)
|
|
122712
|
+
return;
|
|
122713
|
+
depth -= 1;
|
|
122714
|
+
if (depth === 0)
|
|
122715
|
+
closeIndex = start - prefix.length;
|
|
122716
|
+
},
|
|
122717
|
+
});
|
|
122718
|
+
return closeIndex;
|
|
122719
|
+
}
|
|
122328
122720
|
|
|
122329
122721
|
;// ./processor/transform/mdxish/components/inline-html.ts
|
|
122330
122722
|
|
|
@@ -122649,6 +123041,10 @@ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
|
|
|
122649
123041
|
* This transformer identifies these patterns and converts them to proper MDX JSX elements so they
|
|
122650
123042
|
* can be accurately recognized and rendered later with their component definition code.
|
|
122651
123043
|
*
|
|
123044
|
+
* Note: The main goal is to promote PascalCase tags to MDX elements, but we want to promote
|
|
123045
|
+
* normal HTML to MDX elements in some cases so they get the full custom parsing behavior.
|
|
123046
|
+
* E.g. tags with JSX expressions, nested components, etc.
|
|
123047
|
+
*
|
|
122652
123048
|
* The mdx-component micromark tokenizer ensures that multi-line components are captured
|
|
122653
123049
|
* as single HTML nodes, so this transformer only needs to handle two cases:
|
|
122654
123050
|
*
|
|
@@ -122695,6 +123091,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
122695
123091
|
if (GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(tag))
|
|
122696
123092
|
return; // owned by dedicated transformers
|
|
122697
123093
|
const isPascal = isPascalCase(tag);
|
|
123094
|
+
// ==== SPECIAL CASES TO PROMOTE NORMAL HTML TO MDX ELEMENTS ====
|
|
122698
123095
|
// Lowercase inline tags with `{…}` attributes belong to
|
|
122699
123096
|
// mdxishInlineComponentBlocks; leave them as html for that pass. PascalCase
|
|
122700
123097
|
// components stay flow-level even when inline (ReadMe's component model).
|
|
@@ -122703,11 +123100,19 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
122703
123100
|
// A lowercase wrapper is only promoted when it (or a descendant) carries a
|
|
122704
123101
|
// JSX expression or nests a component; otherwise it would swallow that inner
|
|
122705
123102
|
// JSX/component as literal text that rehype-raw's parse5 pass can't handle.
|
|
122706
|
-
// Table-structural wrappers are excluded — `mdxishTables` re-parses
|
|
122707
|
-
|
|
123103
|
+
// Table-structural wrappers are excluded from both — `mdxishTables` re-parses
|
|
123104
|
+
// those, so a `{…}` in a cell (e.g. `<code>--depth={n}</code>`) must not
|
|
123105
|
+
// accidentally promote the table to an MDX element prematurely.
|
|
122708
123106
|
const isTableStructuralTag = tag === 'table' || tableTags.has(tag);
|
|
123107
|
+
const hasNestedExpressionAttr = !selfClosing && !isTableStructuralTag && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
|
|
122709
123108
|
const hasNestedComponentTag = !selfClosing && !isTableStructuralTag && hasNestedGenericComponentTag(contentAfterTag);
|
|
122710
|
-
|
|
123109
|
+
// Promotion: By default commonmark doesn't parse markdown in single line HTML tags (e.g. <div>**bold**</div>)
|
|
123110
|
+
// To support that, we try to promote them to MDX elements so the markdown gets parsed
|
|
123111
|
+
const isPlainLowercaseHtml = !isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr && !hasNestedComponentTag;
|
|
123112
|
+
const plainClosingTagIndex = isPlainLowercaseHtml && !selfClosing && isMarkdownPromotableHtmlTag(tag) && !NESTED_TABLE_RE.test(contentAfterTag)
|
|
123113
|
+
? findBalancedClosingTagIndex(contentAfterTag, tag)
|
|
123114
|
+
: -1;
|
|
123115
|
+
if (isPlainLowercaseHtml && plainClosingTagIndex < 0)
|
|
122711
123116
|
return;
|
|
122712
123117
|
const closingTagStr = `</${tag}>`;
|
|
122713
123118
|
// Case 1: Self-closing tag
|
|
@@ -122728,14 +123133,26 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
122728
123133
|
return;
|
|
122729
123134
|
}
|
|
122730
123135
|
// Case 2: Self-contained block (closing tag in content)
|
|
122731
|
-
|
|
122732
|
-
|
|
123136
|
+
const closingTagIndex = isPlainLowercaseHtml ? plainClosingTagIndex : contentAfterTag.lastIndexOf(closingTagStr);
|
|
123137
|
+
if (closingTagIndex >= 0) {
|
|
122733
123138
|
// Untrimmed so parseMdChildren can dedent before trimming.
|
|
122734
123139
|
const componentInnerContent = contentAfterTag.substring(0, closingTagIndex);
|
|
122735
123140
|
const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
|
|
122736
|
-
let parsedChildren =
|
|
122737
|
-
|
|
122738
|
-
|
|
123141
|
+
let parsedChildren = [];
|
|
123142
|
+
if (componentInnerContent.trim()) {
|
|
123143
|
+
try {
|
|
123144
|
+
parsedChildren = parseMdChildren(componentInnerContent, safeMode);
|
|
123145
|
+
}
|
|
123146
|
+
catch (error) {
|
|
123147
|
+
// Plain HTML bodies can hold anything (e.g. stray braces the strict
|
|
123148
|
+
// expression parser rejects) — keep the node raw instead of throwing.
|
|
123149
|
+
if (isPlainLowercaseHtml)
|
|
123150
|
+
return;
|
|
123151
|
+
throw error;
|
|
123152
|
+
}
|
|
123153
|
+
}
|
|
123154
|
+
if (isPlainLowercaseHtml && !containsMarkdownConstruct(parsedChildren))
|
|
123155
|
+
return;
|
|
122739
123156
|
// Lowercase tags are usually inline; unwrap a sole paragraph so their
|
|
122740
123157
|
// phrasing content isn't spuriously block-wrapped.
|
|
122741
123158
|
if (!isPascal && parsedChildren.length === 1 && parsedChildren[0].type === 'paragraph') {
|
|
@@ -124300,9 +124717,6 @@ const magicBlockTransformer = (options = {}) => tree => {
|
|
|
124300
124717
|
// single-line `<div>…</div>`). CommonMark slurps the whole div as one `html`
|
|
124301
124718
|
// node, so the tokenizer never sees the HTMLBlock — we recover it here.
|
|
124302
124719
|
const RAW_HTML_BLOCK_RE = /<HTMLBlock\b([^>]*)>\s*\{\s*`((?:[^`\\]|\\.)*)`\s*\}\s*<\/HTMLBlock>/g;
|
|
124303
|
-
// Opening `<HTMLBlock …>` as its own `html` node — produced inside a paragraph
|
|
124304
|
-
// when an HTMLBlock appears inline alongside text.
|
|
124305
|
-
const HTML_BLOCK_OPEN_RE = /^<HTMLBlock\b([^>]*)>$/;
|
|
124306
124720
|
/**
|
|
124307
124721
|
* Builds the canonical `html-block` MDAST node the renderer expects.
|
|
124308
124722
|
*/
|
|
@@ -124383,13 +124797,14 @@ const splitRawHtmlBlocks = (node) => {
|
|
|
124383
124797
|
/**
|
|
124384
124798
|
* Converts every `<HTMLBlock>` shape that survives parsing into the canonical
|
|
124385
124799
|
* `html-block` MDAST node, reading the body from the tokenizer's template-literal
|
|
124386
|
-
* expression.
|
|
124800
|
+
* expression. Two shapes occur:
|
|
124387
124801
|
*
|
|
124388
|
-
* 1. JSX element (`mdxJsxFlowElement`/`mdxJsxTextElement`) —
|
|
124389
|
-
*
|
|
124390
|
-
*
|
|
124391
|
-
*
|
|
124392
|
-
*
|
|
124802
|
+
* 1. JSX element (`mdxJsxFlowElement`/`mdxJsxTextElement`) — table cells, after
|
|
124803
|
+
* their remarkMdx re-parse (that re-parse runs without the htmlBlockComponent
|
|
124804
|
+
* tokenizer, so `<HTMLBlock>` arrives as JSX rather than an opaque `html` node).
|
|
124805
|
+
* 2. Raw `html` blob (`splitRawHtmlBlocks`) — the htmlBlockComponent tokenizer's
|
|
124806
|
+
* opaque output (top-level and inline), or an `<HTMLBlock>` embedded in a
|
|
124807
|
+
* larger raw-HTML node like an inline `<div>` that the tokenizer never saw.
|
|
124393
124808
|
*
|
|
124394
124809
|
* Runs *after* `mdxishTables` so table cells are re-parsed first;
|
|
124395
124810
|
* `mdxishTables` recognizes the still-JSX `<HTMLBlock>` element when deciding to
|
|
@@ -124414,36 +124829,6 @@ const mdxishHtmlBlocks = () => tree => {
|
|
|
124414
124829
|
if (replacement)
|
|
124415
124830
|
parent.children.splice(index, 1, ...replacement);
|
|
124416
124831
|
});
|
|
124417
|
-
// Shape 3: inline within a paragraph — `<HTMLBlock>` open/close arrive as
|
|
124418
|
-
// separate `html` siblings with the template-literal expression between them.
|
|
124419
|
-
visit(tree, 'paragraph', (paragraph) => {
|
|
124420
|
-
// An html-block is block content, so it isn't a valid PhrasingContent child;
|
|
124421
|
-
// widen to RootContent (which HTMLBlock belongs to) for the in-place splice.
|
|
124422
|
-
const children = paragraph.children;
|
|
124423
|
-
for (let i = 0; i < children.length; i += 1) {
|
|
124424
|
-
const open = children[i];
|
|
124425
|
-
const openMatch = open.type === 'html' ? open.value.match(HTML_BLOCK_OPEN_RE) : null;
|
|
124426
|
-
if (!openMatch)
|
|
124427
|
-
continue; // eslint-disable-line no-continue
|
|
124428
|
-
const closeIdx = children.findIndex((child, j) => j > i && child.type === 'html' && child.value === '</HTMLBlock>');
|
|
124429
|
-
if (closeIdx === -1)
|
|
124430
|
-
continue; // eslint-disable-line no-continue
|
|
124431
|
-
const body = children
|
|
124432
|
-
.slice(i + 1, closeIdx)
|
|
124433
|
-
.map(child => {
|
|
124434
|
-
if (child.type === 'mdxTextExpression' || child.type === 'mdxFlowExpression') {
|
|
124435
|
-
return extractTemplateLiteral(child.value);
|
|
124436
|
-
}
|
|
124437
|
-
// Preserve raw text from any other phrasing sibling (e.g. stray
|
|
124438
|
-
// whitespace or content the tokenizer didn't claim) so it isn't
|
|
124439
|
-
// silently dropped from the html payload.
|
|
124440
|
-
return 'value' in child && typeof child.value === 'string' ? child.value : '';
|
|
124441
|
-
})
|
|
124442
|
-
.join('');
|
|
124443
|
-
const openingTagIndent = (open.position?.start.column ?? 1) - 1;
|
|
124444
|
-
children.splice(i, closeIdx - i + 1, htmlBlockFromRaw(openMatch[1], body, open.position, openingTagIndent));
|
|
124445
|
-
}
|
|
124446
|
-
});
|
|
124447
124832
|
};
|
|
124448
124833
|
/* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
|
|
124449
124834
|
|
|
@@ -125143,6 +125528,29 @@ const mdxishMermaidTransformer = () => (tree) => {
|
|
|
125143
125528
|
};
|
|
125144
125529
|
/* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
|
|
125145
125530
|
|
|
125531
|
+
;// ./processor/transform/mdxish/normalize-closing-tag-whitespace.ts
|
|
125532
|
+
|
|
125533
|
+
|
|
125534
|
+
// Spaces/tabs only — newlines would let prose `<` / `>` across lines look like one tag.
|
|
125535
|
+
const SPACED_CLOSING_TAG_RE = /<\/[ \t]*([a-zA-Z][a-zA-Z0-9-]*)[ \t]*>/g;
|
|
125536
|
+
/**
|
|
125537
|
+
* Canonicalize spaced closing tags (`</ td >` → `</td>`) for known HTML names.
|
|
125538
|
+
*
|
|
125539
|
+
* In HTML, `</` + whitespace is a bogus comment, so `</ table >` never closes the
|
|
125540
|
+
* table (jsxTable misses it → empty table + pre; CX-3706). Only standard HTML tags;
|
|
125541
|
+
* custom components, prose (`a </ b`), and code blocks are left alone.
|
|
125542
|
+
*
|
|
125543
|
+
* @example
|
|
125544
|
+
* normalizeClosingTagWhitespace('</ td >') // '</td>'
|
|
125545
|
+
* normalizeClosingTagWhitespace('</table >') // '</table>'
|
|
125546
|
+
* normalizeClosingTagWhitespace('a </ b >') // unchanged
|
|
125547
|
+
*/
|
|
125548
|
+
function normalizeClosingTagWhitespace(content) {
|
|
125549
|
+
const { protectedContent, protectedCode } = protectCodeBlocks(content);
|
|
125550
|
+
const result = protectedContent.replace(SPACED_CLOSING_TAG_RE, (match, tagName) => STANDARD_HTML_TAGS.has(tagName.toLowerCase()) ? `</${tagName}>` : match);
|
|
125551
|
+
return restoreCodeBlocks(result, protectedCode);
|
|
125552
|
+
}
|
|
125553
|
+
|
|
125146
125554
|
;// ./processor/transform/mdxish/normalize-compact-headings.ts
|
|
125147
125555
|
|
|
125148
125556
|
/**
|
|
@@ -125623,186 +126031,463 @@ function resolveCodeVariables(value, resolvedVariables) {
|
|
|
125623
126031
|
return name.toUpperCase();
|
|
125624
126032
|
return name in resolvedVariables ? resolvedVariables[name] : name.toUpperCase();
|
|
125625
126033
|
}
|
|
125626
|
-
// MDX variable: {user.*}
|
|
125627
|
-
if (mdxEscapePrefix || mdxEscapeSuffix)
|
|
125628
|
-
return match;
|
|
125629
|
-
if (mdxVarName in resolvedVariables)
|
|
125630
|
-
return resolvedVariables[mdxVarName];
|
|
125631
|
-
const fullPath = match.slice(1, -1);
|
|
125632
|
-
return fullPath.toUpperCase();
|
|
125633
|
-
});
|
|
125634
|
-
}
|
|
125635
|
-
/**
|
|
125636
|
-
* A remark mdast plugin that resolves legacy variables <<...>> and MDX variables {user.*} inside code and inline code nodes
|
|
125637
|
-
* to their values. Uses regexes from the readme variable to search for variables in the code string.
|
|
125638
|
-
*
|
|
125639
|
-
* This is needed because variables in code blocks and inline cannot be tokenized, and also we need to maintain the code string
|
|
125640
|
-
* in the code nodes. This enables engine side variable resolution in codes which improves UX
|
|
125641
|
-
*/
|
|
125642
|
-
const variablesCodeResolver = ({ variables } = {}) => tree => {
|
|
125643
|
-
const resolvedVariables = variables_code_flattenVariables(variables);
|
|
125644
|
-
visit(tree, 'inlineCode', (node) => {
|
|
125645
|
-
if (!node.value)
|
|
125646
|
-
return;
|
|
125647
|
-
node.value = resolveCodeVariables(node.value, resolvedVariables);
|
|
125648
|
-
});
|
|
125649
|
-
visit(tree, 'code', (node) => {
|
|
125650
|
-
if (!node.value)
|
|
125651
|
-
return;
|
|
125652
|
-
if (node.lang === 'mermaid')
|
|
125653
|
-
return;
|
|
125654
|
-
const nextValue = resolveCodeVariables(node.value, resolvedVariables);
|
|
125655
|
-
node.value = nextValue;
|
|
125656
|
-
// Keep code-tabs/readme-components hProperties in sync with node.value
|
|
125657
|
-
// because renderers read `value` from hProperties.
|
|
125658
|
-
if (node.data?.hProperties && typeof node.data.hProperties === 'object') {
|
|
125659
|
-
node.data.hProperties.value = nextValue;
|
|
126034
|
+
// MDX variable: {user.*}
|
|
126035
|
+
if (mdxEscapePrefix || mdxEscapeSuffix)
|
|
126036
|
+
return match;
|
|
126037
|
+
if (mdxVarName in resolvedVariables)
|
|
126038
|
+
return resolvedVariables[mdxVarName];
|
|
126039
|
+
const fullPath = match.slice(1, -1);
|
|
126040
|
+
return fullPath.toUpperCase();
|
|
126041
|
+
});
|
|
126042
|
+
}
|
|
126043
|
+
/**
|
|
126044
|
+
* A remark mdast plugin that resolves legacy variables <<...>> and MDX variables {user.*} inside code and inline code nodes
|
|
126045
|
+
* to their values. Uses regexes from the readme variable to search for variables in the code string.
|
|
126046
|
+
*
|
|
126047
|
+
* This is needed because variables in code blocks and inline cannot be tokenized, and also we need to maintain the code string
|
|
126048
|
+
* in the code nodes. This enables engine side variable resolution in codes which improves UX
|
|
126049
|
+
*/
|
|
126050
|
+
const variablesCodeResolver = ({ variables } = {}) => tree => {
|
|
126051
|
+
const resolvedVariables = variables_code_flattenVariables(variables);
|
|
126052
|
+
visit(tree, 'inlineCode', (node) => {
|
|
126053
|
+
if (!node.value)
|
|
126054
|
+
return;
|
|
126055
|
+
node.value = resolveCodeVariables(node.value, resolvedVariables);
|
|
126056
|
+
});
|
|
126057
|
+
visit(tree, 'code', (node) => {
|
|
126058
|
+
if (!node.value)
|
|
126059
|
+
return;
|
|
126060
|
+
if (node.lang === 'mermaid')
|
|
126061
|
+
return;
|
|
126062
|
+
const nextValue = resolveCodeVariables(node.value, resolvedVariables);
|
|
126063
|
+
node.value = nextValue;
|
|
126064
|
+
// Keep code-tabs/readme-components hProperties in sync with node.value
|
|
126065
|
+
// because renderers read `value` from hProperties.
|
|
126066
|
+
if (node.data?.hProperties && typeof node.data.hProperties === 'object') {
|
|
126067
|
+
node.data.hProperties.value = nextValue;
|
|
126068
|
+
}
|
|
126069
|
+
});
|
|
126070
|
+
return tree;
|
|
126071
|
+
};
|
|
126072
|
+
/* harmony default export */ const variables_code = (variablesCodeResolver);
|
|
126073
|
+
|
|
126074
|
+
;// ./processor/transform/mdxish/variables-text.ts
|
|
126075
|
+
|
|
126076
|
+
|
|
126077
|
+
/**
|
|
126078
|
+
* Matches {user.<field>} patterns:
|
|
126079
|
+
* - {user.name}
|
|
126080
|
+
* - {user.email}
|
|
126081
|
+
* - {user['field']}
|
|
126082
|
+
* - {user["field"]}
|
|
126083
|
+
*
|
|
126084
|
+
* Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
|
|
126085
|
+
*/
|
|
126086
|
+
const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
|
|
126087
|
+
function makeVariableNode(varName, rawValue) {
|
|
126088
|
+
return {
|
|
126089
|
+
type: NodeTypes.variable,
|
|
126090
|
+
data: {
|
|
126091
|
+
hName: 'Variable',
|
|
126092
|
+
hProperties: { name: varName },
|
|
126093
|
+
},
|
|
126094
|
+
value: rawValue,
|
|
126095
|
+
};
|
|
126096
|
+
}
|
|
126097
|
+
/**
|
|
126098
|
+
* A remark plugin that parses {user.<field>} patterns from text nodes and
|
|
126099
|
+
* mdx expression nodes, creating Variable nodes for runtime resolution.
|
|
126100
|
+
*
|
|
126101
|
+
* Handles:
|
|
126102
|
+
* - `text` nodes: when safeMode is true or after expression evaluation
|
|
126103
|
+
* - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
|
|
126104
|
+
* - `mdxFlowExpression` nodes: when {user.*} appears on its own line (e.g. inside JSX table cells)
|
|
126105
|
+
*
|
|
126106
|
+
* Supports any user field: name, email, email_verified, exp, iat, etc.
|
|
126107
|
+
*/
|
|
126108
|
+
function visitExpressionNode(node, index, parent) {
|
|
126109
|
+
if (index === undefined || !parent)
|
|
126110
|
+
return;
|
|
126111
|
+
const wrapped = `{${(node.value ?? '').trim()}}`;
|
|
126112
|
+
const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
|
|
126113
|
+
if (matches.length !== 1)
|
|
126114
|
+
return;
|
|
126115
|
+
const varName = matches[0][1] || matches[0][2];
|
|
126116
|
+
parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
|
|
126117
|
+
}
|
|
126118
|
+
const variablesTextTransformer = () => tree => {
|
|
126119
|
+
visit(tree, 'mdxTextExpression', (node, index, parent) => {
|
|
126120
|
+
visitExpressionNode(node, index, parent);
|
|
126121
|
+
});
|
|
126122
|
+
visit(tree, 'mdxFlowExpression', (node, index, parent) => {
|
|
126123
|
+
visitExpressionNode(node, index, parent);
|
|
126124
|
+
});
|
|
126125
|
+
visit(tree, 'text', (node, index, parent) => {
|
|
126126
|
+
if (index === undefined || !parent)
|
|
126127
|
+
return;
|
|
126128
|
+
// Skip if inside inline code
|
|
126129
|
+
if (parent.type === 'inlineCode')
|
|
126130
|
+
return;
|
|
126131
|
+
const text = node.value;
|
|
126132
|
+
if (typeof text !== 'string' || !text.trim())
|
|
126133
|
+
return;
|
|
126134
|
+
if (!text.includes('{user.') && !text.includes('{user['))
|
|
126135
|
+
return;
|
|
126136
|
+
const matches = [...text.matchAll(USER_VAR_REGEX)];
|
|
126137
|
+
if (matches.length === 0)
|
|
126138
|
+
return;
|
|
126139
|
+
const parts = [];
|
|
126140
|
+
let lastIndex = 0;
|
|
126141
|
+
matches.forEach(match => {
|
|
126142
|
+
const matchIndex = match.index ?? 0;
|
|
126143
|
+
// Add text before the match
|
|
126144
|
+
if (matchIndex > lastIndex) {
|
|
126145
|
+
parts.push({ type: 'text', value: text.slice(lastIndex, matchIndex) });
|
|
126146
|
+
}
|
|
126147
|
+
// Extract variable name from either capture group (dot or bracket notation)
|
|
126148
|
+
const varName = match[1] || match[2];
|
|
126149
|
+
parts.push(makeVariableNode(varName, match[0]));
|
|
126150
|
+
lastIndex = matchIndex + match[0].length;
|
|
126151
|
+
});
|
|
126152
|
+
// Add remaining text after last match
|
|
126153
|
+
if (lastIndex < text.length) {
|
|
126154
|
+
parts.push({ type: 'text', value: text.slice(lastIndex) });
|
|
126155
|
+
}
|
|
126156
|
+
// Replace node with parts
|
|
126157
|
+
if (parts.length > 1 || (parts.length === 1 && parts[0].type !== 'text')) {
|
|
126158
|
+
parent.children.splice(index, 1, ...parts);
|
|
126159
|
+
}
|
|
126160
|
+
});
|
|
126161
|
+
return tree;
|
|
126162
|
+
};
|
|
126163
|
+
/* harmony default export */ const variables_text = (variablesTextTransformer);
|
|
126164
|
+
|
|
126165
|
+
;// ./lib/mdast-util/html-block-component/index.ts
|
|
126166
|
+
const html_block_component_contextMap = new WeakMap();
|
|
126167
|
+
function findHtmlBlockComponentToken() {
|
|
126168
|
+
const events = this.tokenStack;
|
|
126169
|
+
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
126170
|
+
if (events[i][0].type === 'htmlBlockComponent')
|
|
126171
|
+
return events[i][0];
|
|
126172
|
+
}
|
|
126173
|
+
return undefined;
|
|
126174
|
+
}
|
|
126175
|
+
function enterHtmlBlockComponent(token) {
|
|
126176
|
+
html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
|
|
126177
|
+
this.enter({ type: 'html', value: '' }, token);
|
|
126178
|
+
}
|
|
126179
|
+
function exitHtmlBlockComponentData(token) {
|
|
126180
|
+
const componentToken = findHtmlBlockComponentToken.call(this);
|
|
126181
|
+
if (!componentToken)
|
|
126182
|
+
return;
|
|
126183
|
+
const ctx = html_block_component_contextMap.get(componentToken);
|
|
126184
|
+
if (ctx) {
|
|
126185
|
+
const gap = token.start.line - ctx.lastEndLine;
|
|
126186
|
+
if (ctx.chunks.length > 0 && gap > 0) {
|
|
126187
|
+
ctx.chunks.push('\n'.repeat(gap));
|
|
126188
|
+
}
|
|
126189
|
+
ctx.chunks.push(this.sliceSerialize(token));
|
|
126190
|
+
ctx.lastEndLine = token.end.line;
|
|
126191
|
+
}
|
|
126192
|
+
}
|
|
126193
|
+
function exitHtmlBlockComponent(token) {
|
|
126194
|
+
const ctx = html_block_component_contextMap.get(token);
|
|
126195
|
+
const node = this.stack[this.stack.length - 1];
|
|
126196
|
+
if (ctx) {
|
|
126197
|
+
node.value = ctx.chunks.join('');
|
|
126198
|
+
html_block_component_contextMap.delete(token);
|
|
126199
|
+
}
|
|
126200
|
+
this.exit(token);
|
|
126201
|
+
}
|
|
126202
|
+
function htmlBlockComponentFromMarkdown() {
|
|
126203
|
+
return {
|
|
126204
|
+
enter: {
|
|
126205
|
+
htmlBlockComponent: enterHtmlBlockComponent,
|
|
126206
|
+
},
|
|
126207
|
+
exit: {
|
|
126208
|
+
htmlBlockComponentData: exitHtmlBlockComponentData,
|
|
126209
|
+
htmlBlockComponent: exitHtmlBlockComponent,
|
|
126210
|
+
},
|
|
126211
|
+
};
|
|
126212
|
+
}
|
|
126213
|
+
|
|
126214
|
+
;// ./lib/micromark/html-block-component/syntax.ts
|
|
126215
|
+
|
|
126216
|
+
|
|
126217
|
+
const TAG_SUFFIX = [
|
|
126218
|
+
codes.uppercaseT,
|
|
126219
|
+
codes.uppercaseM,
|
|
126220
|
+
codes.uppercaseL,
|
|
126221
|
+
codes.uppercaseB,
|
|
126222
|
+
codes.lowercaseL,
|
|
126223
|
+
codes.lowercaseO,
|
|
126224
|
+
codes.lowercaseC,
|
|
126225
|
+
codes.lowercaseK,
|
|
126226
|
+
];
|
|
126227
|
+
// ---------------------------------------------------------------------------
|
|
126228
|
+
// Shared tokenizer factory
|
|
126229
|
+
// ---------------------------------------------------------------------------
|
|
126230
|
+
/**
|
|
126231
|
+
* Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
|
|
126232
|
+
*
|
|
126233
|
+
* - **flow** (block-level): supports multiline content via line continuations,
|
|
126234
|
+
* consumes trailing whitespace after the closing tag.
|
|
126235
|
+
* - **text** (inline): single-line only, exits immediately after the closing tag.
|
|
126236
|
+
*/
|
|
126237
|
+
function syntax_createTokenize(mode) {
|
|
126238
|
+
return function tokenize(effects, ok, nok) {
|
|
126239
|
+
let depth = 1;
|
|
126240
|
+
function matchChars(chars, onMatch, onFail) {
|
|
126241
|
+
if (chars.length === 0)
|
|
126242
|
+
return onMatch;
|
|
126243
|
+
const next = (code) => {
|
|
126244
|
+
if (code === chars[0]) {
|
|
126245
|
+
effects.consume(code);
|
|
126246
|
+
return matchChars(chars.slice(1), onMatch, onFail);
|
|
126247
|
+
}
|
|
126248
|
+
return onFail(code);
|
|
126249
|
+
};
|
|
126250
|
+
return next;
|
|
126251
|
+
}
|
|
126252
|
+
function matchTagName(onMatch, onFail) {
|
|
126253
|
+
const next = (code) => {
|
|
126254
|
+
if (code === codes.uppercaseH) {
|
|
126255
|
+
effects.consume(code);
|
|
126256
|
+
return matchChars(TAG_SUFFIX, onMatch, onFail);
|
|
126257
|
+
}
|
|
126258
|
+
return onFail(code);
|
|
126259
|
+
};
|
|
126260
|
+
return next;
|
|
126261
|
+
}
|
|
126262
|
+
return start;
|
|
126263
|
+
function start(code) {
|
|
126264
|
+
if (code !== codes.lessThan)
|
|
126265
|
+
return nok(code);
|
|
126266
|
+
effects.enter('htmlBlockComponent');
|
|
126267
|
+
effects.enter('htmlBlockComponentData');
|
|
126268
|
+
effects.consume(code);
|
|
126269
|
+
return matchTagName(afterTagName, nok);
|
|
126270
|
+
}
|
|
126271
|
+
function afterTagName(code) {
|
|
126272
|
+
if (code === codes.greaterThan) {
|
|
126273
|
+
effects.consume(code);
|
|
126274
|
+
return body;
|
|
126275
|
+
}
|
|
126276
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
126277
|
+
effects.consume(code);
|
|
126278
|
+
return inAttributes;
|
|
126279
|
+
}
|
|
126280
|
+
if (mode === 'flow' && markdownLineEnding(code)) {
|
|
126281
|
+
effects.exit('htmlBlockComponentData');
|
|
126282
|
+
return attributeContinuationStart(code);
|
|
126283
|
+
}
|
|
126284
|
+
if (code === codes.slash) {
|
|
126285
|
+
effects.consume(code);
|
|
126286
|
+
return selfClose;
|
|
126287
|
+
}
|
|
126288
|
+
return nok(code);
|
|
126289
|
+
}
|
|
126290
|
+
function inAttributes(code) {
|
|
126291
|
+
if (code === codes.greaterThan) {
|
|
126292
|
+
effects.consume(code);
|
|
126293
|
+
return body;
|
|
126294
|
+
}
|
|
126295
|
+
if (code === null) {
|
|
126296
|
+
return nok(code);
|
|
126297
|
+
}
|
|
126298
|
+
if (markdownLineEnding(code)) {
|
|
126299
|
+
if (mode === 'text')
|
|
126300
|
+
return nok(code);
|
|
126301
|
+
effects.exit('htmlBlockComponentData');
|
|
126302
|
+
return attributeContinuationStart(code);
|
|
126303
|
+
}
|
|
126304
|
+
effects.consume(code);
|
|
126305
|
+
return inAttributes;
|
|
126306
|
+
}
|
|
126307
|
+
function attributeContinuationStart(code) {
|
|
126308
|
+
return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
|
|
126309
|
+
}
|
|
126310
|
+
function attributeContinuationNonLazy(code) {
|
|
126311
|
+
effects.enter(types_types.lineEnding);
|
|
126312
|
+
effects.consume(code);
|
|
126313
|
+
effects.exit(types_types.lineEnding);
|
|
126314
|
+
return attributeContinuationBefore;
|
|
126315
|
+
}
|
|
126316
|
+
function attributeContinuationBefore(code) {
|
|
126317
|
+
if (code === null || markdownLineEnding(code)) {
|
|
126318
|
+
return attributeContinuationStart(code);
|
|
126319
|
+
}
|
|
126320
|
+
effects.enter('htmlBlockComponentData');
|
|
126321
|
+
return inAttributes(code);
|
|
126322
|
+
}
|
|
126323
|
+
function selfClose(code) {
|
|
126324
|
+
if (code === codes.greaterThan) {
|
|
126325
|
+
effects.consume(code);
|
|
126326
|
+
return mode === 'flow' ? afterClose : done(code);
|
|
126327
|
+
}
|
|
126328
|
+
return nok(code);
|
|
126329
|
+
}
|
|
126330
|
+
function body(code) {
|
|
126331
|
+
if (code === null)
|
|
126332
|
+
return nok(code);
|
|
126333
|
+
if (markdownLineEnding(code)) {
|
|
126334
|
+
if (mode === 'text') {
|
|
126335
|
+
// Text constructs operate on paragraph content which spans lines
|
|
126336
|
+
effects.consume(code);
|
|
126337
|
+
return body;
|
|
126338
|
+
}
|
|
126339
|
+
effects.exit('htmlBlockComponentData');
|
|
126340
|
+
return continuationStart(code);
|
|
126341
|
+
}
|
|
126342
|
+
if (code === codes.lessThan) {
|
|
126343
|
+
effects.consume(code);
|
|
126344
|
+
return closeSlash;
|
|
126345
|
+
}
|
|
126346
|
+
effects.consume(code);
|
|
126347
|
+
return body;
|
|
126348
|
+
}
|
|
126349
|
+
function closeSlash(code) {
|
|
126350
|
+
if (code === codes.slash) {
|
|
126351
|
+
effects.consume(code);
|
|
126352
|
+
return matchTagName(closeGt, body);
|
|
126353
|
+
}
|
|
126354
|
+
return matchTagName(openAfterTagName, body)(code);
|
|
126355
|
+
}
|
|
126356
|
+
function openAfterTagName(code) {
|
|
126357
|
+
if (code === codes.greaterThan || code === codes.space || code === codes.horizontalTab) {
|
|
126358
|
+
depth += 1;
|
|
126359
|
+
effects.consume(code);
|
|
126360
|
+
return body;
|
|
126361
|
+
}
|
|
126362
|
+
return body(code);
|
|
126363
|
+
}
|
|
126364
|
+
function closeGt(code) {
|
|
126365
|
+
if (code === codes.greaterThan) {
|
|
126366
|
+
depth -= 1;
|
|
126367
|
+
effects.consume(code);
|
|
126368
|
+
if (depth === 0) {
|
|
126369
|
+
return mode === 'flow' ? afterClose : done(code);
|
|
126370
|
+
}
|
|
126371
|
+
return body;
|
|
126372
|
+
}
|
|
126373
|
+
return body(code);
|
|
125660
126374
|
}
|
|
125661
|
-
|
|
125662
|
-
|
|
125663
|
-
|
|
125664
|
-
|
|
125665
|
-
|
|
125666
|
-
;// ./processor/transform/mdxish/variables-text.ts
|
|
125667
|
-
|
|
125668
|
-
|
|
125669
|
-
/**
|
|
125670
|
-
* Matches {user.<field>} patterns:
|
|
125671
|
-
* - {user.name}
|
|
125672
|
-
* - {user.email}
|
|
125673
|
-
* - {user['field']}
|
|
125674
|
-
* - {user["field"]}
|
|
125675
|
-
*
|
|
125676
|
-
* Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
|
|
125677
|
-
*/
|
|
125678
|
-
const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
|
|
125679
|
-
function makeVariableNode(varName, rawValue) {
|
|
125680
|
-
return {
|
|
125681
|
-
type: NodeTypes.variable,
|
|
125682
|
-
data: {
|
|
125683
|
-
hName: 'Variable',
|
|
125684
|
-
hProperties: { name: varName },
|
|
125685
|
-
},
|
|
125686
|
-
value: rawValue,
|
|
125687
|
-
};
|
|
125688
|
-
}
|
|
125689
|
-
/**
|
|
125690
|
-
* A remark plugin that parses {user.<field>} patterns from text nodes and
|
|
125691
|
-
* mdx expression nodes, creating Variable nodes for runtime resolution.
|
|
125692
|
-
*
|
|
125693
|
-
* Handles:
|
|
125694
|
-
* - `text` nodes: when safeMode is true or after expression evaluation
|
|
125695
|
-
* - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
|
|
125696
|
-
* - `mdxFlowExpression` nodes: when {user.*} appears on its own line (e.g. inside JSX table cells)
|
|
125697
|
-
*
|
|
125698
|
-
* Supports any user field: name, email, email_verified, exp, iat, etc.
|
|
125699
|
-
*/
|
|
125700
|
-
function visitExpressionNode(node, index, parent) {
|
|
125701
|
-
if (index === undefined || !parent)
|
|
125702
|
-
return;
|
|
125703
|
-
const wrapped = `{${(node.value ?? '').trim()}}`;
|
|
125704
|
-
const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
|
|
125705
|
-
if (matches.length !== 1)
|
|
125706
|
-
return;
|
|
125707
|
-
const varName = matches[0][1] || matches[0][2];
|
|
125708
|
-
parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
|
|
125709
|
-
}
|
|
125710
|
-
const variablesTextTransformer = () => tree => {
|
|
125711
|
-
visit(tree, 'mdxTextExpression', (node, index, parent) => {
|
|
125712
|
-
visitExpressionNode(node, index, parent);
|
|
125713
|
-
});
|
|
125714
|
-
visit(tree, 'mdxFlowExpression', (node, index, parent) => {
|
|
125715
|
-
visitExpressionNode(node, index, parent);
|
|
125716
|
-
});
|
|
125717
|
-
visit(tree, 'text', (node, index, parent) => {
|
|
125718
|
-
if (index === undefined || !parent)
|
|
125719
|
-
return;
|
|
125720
|
-
// Skip if inside inline code
|
|
125721
|
-
if (parent.type === 'inlineCode')
|
|
125722
|
-
return;
|
|
125723
|
-
const text = node.value;
|
|
125724
|
-
if (typeof text !== 'string' || !text.trim())
|
|
125725
|
-
return;
|
|
125726
|
-
if (!text.includes('{user.') && !text.includes('{user['))
|
|
125727
|
-
return;
|
|
125728
|
-
const matches = [...text.matchAll(USER_VAR_REGEX)];
|
|
125729
|
-
if (matches.length === 0)
|
|
125730
|
-
return;
|
|
125731
|
-
const parts = [];
|
|
125732
|
-
let lastIndex = 0;
|
|
125733
|
-
matches.forEach(match => {
|
|
125734
|
-
const matchIndex = match.index ?? 0;
|
|
125735
|
-
// Add text before the match
|
|
125736
|
-
if (matchIndex > lastIndex) {
|
|
125737
|
-
parts.push({ type: 'text', value: text.slice(lastIndex, matchIndex) });
|
|
126375
|
+
// -- flow-only states ---------------------------------------------------
|
|
126376
|
+
function afterClose(code) {
|
|
126377
|
+
if (code === null || markdownLineEnding(code)) {
|
|
126378
|
+
return done(code);
|
|
125738
126379
|
}
|
|
125739
|
-
|
|
125740
|
-
|
|
125741
|
-
|
|
125742
|
-
|
|
125743
|
-
|
|
125744
|
-
|
|
125745
|
-
|
|
125746
|
-
parts.push({ type: 'text', value: text.slice(lastIndex) });
|
|
126380
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
126381
|
+
effects.consume(code);
|
|
126382
|
+
return afterClose;
|
|
126383
|
+
}
|
|
126384
|
+
// Reject so the block re-parses as a paragraph, deferring to the
|
|
126385
|
+
// text tokenizer which preserves trailing content in the same line.
|
|
126386
|
+
return nok(code);
|
|
125747
126387
|
}
|
|
125748
|
-
//
|
|
125749
|
-
|
|
125750
|
-
|
|
126388
|
+
// -- flow-only: line continuation ---------------------------------------
|
|
126389
|
+
function continuationStart(code) {
|
|
126390
|
+
return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
|
|
125751
126391
|
}
|
|
125752
|
-
|
|
125753
|
-
|
|
126392
|
+
function continuationStartNonLazy(code) {
|
|
126393
|
+
effects.enter(types_types.lineEnding);
|
|
126394
|
+
effects.consume(code);
|
|
126395
|
+
effects.exit(types_types.lineEnding);
|
|
126396
|
+
return continuationBefore;
|
|
126397
|
+
}
|
|
126398
|
+
function continuationBefore(code) {
|
|
126399
|
+
if (code === null || markdownLineEnding(code)) {
|
|
126400
|
+
return continuationStart(code);
|
|
126401
|
+
}
|
|
126402
|
+
effects.enter('htmlBlockComponentData');
|
|
126403
|
+
return body(code);
|
|
126404
|
+
}
|
|
126405
|
+
function continuationAfter(code) {
|
|
126406
|
+
if (code === null)
|
|
126407
|
+
return nok(code);
|
|
126408
|
+
effects.exit('htmlBlockComponent');
|
|
126409
|
+
return ok(code);
|
|
126410
|
+
}
|
|
126411
|
+
// -- shared exit --------------------------------------------------------
|
|
126412
|
+
function done(_code) {
|
|
126413
|
+
effects.exit('htmlBlockComponentData');
|
|
126414
|
+
effects.exit('htmlBlockComponent');
|
|
126415
|
+
return ok(_code);
|
|
126416
|
+
}
|
|
126417
|
+
};
|
|
126418
|
+
}
|
|
126419
|
+
// ---------------------------------------------------------------------------
|
|
126420
|
+
// Flow construct (block-level)
|
|
126421
|
+
// ---------------------------------------------------------------------------
|
|
126422
|
+
const html_block_component_syntax_nonLazyContinuationStart = {
|
|
126423
|
+
tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
|
|
126424
|
+
partial: true,
|
|
125754
126425
|
};
|
|
125755
|
-
|
|
125756
|
-
|
|
125757
|
-
|
|
125758
|
-
|
|
125759
|
-
|
|
125760
|
-
|
|
125761
|
-
|
|
125762
|
-
if (events[i][0].type === 'jsxTable')
|
|
125763
|
-
return events[i][0];
|
|
126426
|
+
function resolveToHtmlBlockComponent(events) {
|
|
126427
|
+
let index = events.length;
|
|
126428
|
+
while (index > 0) {
|
|
126429
|
+
index -= 1;
|
|
126430
|
+
if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
|
|
126431
|
+
break;
|
|
126432
|
+
}
|
|
125764
126433
|
}
|
|
125765
|
-
|
|
125766
|
-
|
|
125767
|
-
|
|
125768
|
-
|
|
125769
|
-
|
|
126434
|
+
if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
|
|
126435
|
+
events[index][1].start = events[index - 2][1].start;
|
|
126436
|
+
events[index + 1][1].start = events[index - 2][1].start;
|
|
126437
|
+
events.splice(index - 2, 2);
|
|
126438
|
+
}
|
|
126439
|
+
return events;
|
|
125770
126440
|
}
|
|
125771
|
-
|
|
125772
|
-
|
|
125773
|
-
|
|
125774
|
-
|
|
125775
|
-
|
|
125776
|
-
|
|
125777
|
-
|
|
125778
|
-
|
|
125779
|
-
|
|
126441
|
+
const htmlBlockComponentFlowConstruct = {
|
|
126442
|
+
name: 'htmlBlockComponent',
|
|
126443
|
+
tokenize: syntax_createTokenize('flow'),
|
|
126444
|
+
resolveTo: resolveToHtmlBlockComponent,
|
|
126445
|
+
concrete: true,
|
|
126446
|
+
};
|
|
126447
|
+
function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
126448
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
126449
|
+
const self = this;
|
|
126450
|
+
return start;
|
|
126451
|
+
function start(code) {
|
|
126452
|
+
if (markdownLineEnding(code)) {
|
|
126453
|
+
effects.enter(types_types.lineEnding);
|
|
126454
|
+
effects.consume(code);
|
|
126455
|
+
effects.exit(types_types.lineEnding);
|
|
126456
|
+
return after;
|
|
125780
126457
|
}
|
|
125781
|
-
|
|
125782
|
-
ctx.lastEndLine = token.end.line;
|
|
126458
|
+
return nok(code);
|
|
125783
126459
|
}
|
|
125784
|
-
|
|
125785
|
-
|
|
125786
|
-
|
|
125787
|
-
|
|
125788
|
-
|
|
125789
|
-
node.value = ctx.chunks.join('');
|
|
125790
|
-
jsx_table_contextMap.delete(token);
|
|
126460
|
+
function after(code) {
|
|
126461
|
+
if (self.parser.lazy[self.now().line]) {
|
|
126462
|
+
return nok(code);
|
|
126463
|
+
}
|
|
126464
|
+
return ok(code);
|
|
125791
126465
|
}
|
|
125792
|
-
this.exit(token);
|
|
125793
126466
|
}
|
|
125794
|
-
|
|
126467
|
+
// ---------------------------------------------------------------------------
|
|
126468
|
+
// Text construct (inline)
|
|
126469
|
+
// ---------------------------------------------------------------------------
|
|
126470
|
+
const htmlBlockComponentTextConstruct = {
|
|
126471
|
+
name: 'htmlBlockComponent',
|
|
126472
|
+
tokenize: syntax_createTokenize('text'),
|
|
126473
|
+
};
|
|
126474
|
+
// ---------------------------------------------------------------------------
|
|
126475
|
+
// Extension
|
|
126476
|
+
// ---------------------------------------------------------------------------
|
|
126477
|
+
function htmlBlockComponent() {
|
|
125795
126478
|
return {
|
|
125796
|
-
|
|
125797
|
-
|
|
126479
|
+
flow: {
|
|
126480
|
+
[codes.lessThan]: [htmlBlockComponentFlowConstruct],
|
|
125798
126481
|
},
|
|
125799
|
-
|
|
125800
|
-
|
|
125801
|
-
jsxTable: exitJsxTable,
|
|
126482
|
+
text: {
|
|
126483
|
+
[codes.lessThan]: [htmlBlockComponentTextConstruct],
|
|
125802
126484
|
},
|
|
125803
126485
|
};
|
|
125804
126486
|
}
|
|
125805
126487
|
|
|
126488
|
+
;// ./lib/micromark/html-block-component/index.ts
|
|
126489
|
+
|
|
126490
|
+
|
|
125806
126491
|
;// ./lib/micromark/jsx-comment/syntax.ts
|
|
125807
126492
|
|
|
125808
126493
|
|
|
@@ -125925,243 +126610,6 @@ function jsxComment() {
|
|
|
125925
126610
|
};
|
|
125926
126611
|
}
|
|
125927
126612
|
|
|
125928
|
-
;// ./lib/micromark/jsx-table/syntax.ts
|
|
125929
|
-
|
|
125930
|
-
|
|
125931
|
-
const jsx_table_syntax_nonLazyContinuationStart = {
|
|
125932
|
-
tokenize: jsx_table_syntax_tokenizeNonLazyContinuationStart,
|
|
125933
|
-
partial: true,
|
|
125934
|
-
};
|
|
125935
|
-
function resolveToJsxTable(events) {
|
|
125936
|
-
let index = events.length;
|
|
125937
|
-
while (index > 0) {
|
|
125938
|
-
index -= 1;
|
|
125939
|
-
if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
|
|
125940
|
-
break;
|
|
125941
|
-
}
|
|
125942
|
-
}
|
|
125943
|
-
if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
|
|
125944
|
-
events[index][1].start = events[index - 2][1].start;
|
|
125945
|
-
events[index + 1][1].start = events[index - 2][1].start;
|
|
125946
|
-
events.splice(index - 2, 2);
|
|
125947
|
-
}
|
|
125948
|
-
return events;
|
|
125949
|
-
}
|
|
125950
|
-
const jsxTableConstruct = {
|
|
125951
|
-
name: 'jsxTable',
|
|
125952
|
-
tokenize: tokenizeJsxTable,
|
|
125953
|
-
resolveTo: resolveToJsxTable,
|
|
125954
|
-
concrete: true,
|
|
125955
|
-
};
|
|
125956
|
-
function tokenizeJsxTable(effects, ok, nok) {
|
|
125957
|
-
let codeSpanOpenSize = 0;
|
|
125958
|
-
let codeSpanCloseSize = 0;
|
|
125959
|
-
let depth = 1;
|
|
125960
|
-
const ABLE_SUFFIX = [codes.lowercaseA, codes.lowercaseB, codes.lowercaseL, codes.lowercaseE];
|
|
125961
|
-
/** Build a state chain that matches a sequence of character codes. */
|
|
125962
|
-
function matchChars(chars, onMatch, onFail) {
|
|
125963
|
-
if (chars.length === 0)
|
|
125964
|
-
return onMatch;
|
|
125965
|
-
return ((code) => {
|
|
125966
|
-
if (code === chars[0]) {
|
|
125967
|
-
effects.consume(code);
|
|
125968
|
-
return matchChars(chars.slice(1), onMatch, onFail);
|
|
125969
|
-
}
|
|
125970
|
-
return onFail(code);
|
|
125971
|
-
});
|
|
125972
|
-
}
|
|
125973
|
-
return start;
|
|
125974
|
-
function start(code) {
|
|
125975
|
-
if (code !== codes.lessThan)
|
|
125976
|
-
return nok(code);
|
|
125977
|
-
effects.enter('jsxTable');
|
|
125978
|
-
effects.enter('jsxTableData');
|
|
125979
|
-
effects.consume(code);
|
|
125980
|
-
return afterLessThan;
|
|
125981
|
-
}
|
|
125982
|
-
function afterLessThan(code) {
|
|
125983
|
-
if (code === codes.uppercaseT || code === codes.lowercaseT) {
|
|
125984
|
-
effects.consume(code);
|
|
125985
|
-
return matchChars(ABLE_SUFFIX, afterTagName, nok);
|
|
125986
|
-
}
|
|
125987
|
-
return nok(code);
|
|
125988
|
-
}
|
|
125989
|
-
function afterTagName(code) {
|
|
125990
|
-
if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
|
|
125991
|
-
effects.consume(code);
|
|
125992
|
-
return body;
|
|
125993
|
-
}
|
|
125994
|
-
return nok(code);
|
|
125995
|
-
}
|
|
125996
|
-
function body(code) {
|
|
125997
|
-
// Reject unclosed <Table> so it falls back to normal HTML block parsing
|
|
125998
|
-
// instead of swallowing all subsequent content to EOF
|
|
125999
|
-
if (code === null) {
|
|
126000
|
-
return nok(code);
|
|
126001
|
-
}
|
|
126002
|
-
if (markdownLineEnding(code)) {
|
|
126003
|
-
effects.exit('jsxTableData');
|
|
126004
|
-
return continuationStart(code);
|
|
126005
|
-
}
|
|
126006
|
-
if (code === codes.backslash) {
|
|
126007
|
-
effects.consume(code);
|
|
126008
|
-
return escapedChar;
|
|
126009
|
-
}
|
|
126010
|
-
if (code === codes.lessThan) {
|
|
126011
|
-
effects.consume(code);
|
|
126012
|
-
return closeSlash;
|
|
126013
|
-
}
|
|
126014
|
-
// Skip over backtick code spans so `</Table>` in inline code isn't
|
|
126015
|
-
// treated as the closing tag
|
|
126016
|
-
if (code === codes.graveAccent) {
|
|
126017
|
-
codeSpanOpenSize = 0;
|
|
126018
|
-
return countOpenTicks(code);
|
|
126019
|
-
}
|
|
126020
|
-
effects.consume(code);
|
|
126021
|
-
return body;
|
|
126022
|
-
}
|
|
126023
|
-
function countOpenTicks(code) {
|
|
126024
|
-
if (code === codes.graveAccent) {
|
|
126025
|
-
codeSpanOpenSize += 1;
|
|
126026
|
-
effects.consume(code);
|
|
126027
|
-
return countOpenTicks;
|
|
126028
|
-
}
|
|
126029
|
-
return inCodeSpan(code);
|
|
126030
|
-
}
|
|
126031
|
-
function inCodeSpan(code) {
|
|
126032
|
-
if (code === null || markdownLineEnding(code))
|
|
126033
|
-
return body(code);
|
|
126034
|
-
if (code === codes.graveAccent) {
|
|
126035
|
-
codeSpanCloseSize = 0;
|
|
126036
|
-
return countCloseTicks(code);
|
|
126037
|
-
}
|
|
126038
|
-
effects.consume(code);
|
|
126039
|
-
return inCodeSpan;
|
|
126040
|
-
}
|
|
126041
|
-
function countCloseTicks(code) {
|
|
126042
|
-
if (code === codes.graveAccent) {
|
|
126043
|
-
codeSpanCloseSize += 1;
|
|
126044
|
-
effects.consume(code);
|
|
126045
|
-
return countCloseTicks;
|
|
126046
|
-
}
|
|
126047
|
-
return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
|
|
126048
|
-
}
|
|
126049
|
-
function escapedChar(code) {
|
|
126050
|
-
if (code === null || markdownLineEnding(code)) {
|
|
126051
|
-
return body(code);
|
|
126052
|
-
}
|
|
126053
|
-
effects.consume(code);
|
|
126054
|
-
return body;
|
|
126055
|
-
}
|
|
126056
|
-
function closeSlash(code) {
|
|
126057
|
-
if (code === codes.slash) {
|
|
126058
|
-
effects.consume(code);
|
|
126059
|
-
return closeTagFirstChar;
|
|
126060
|
-
}
|
|
126061
|
-
if (code === codes.uppercaseT || code === codes.lowercaseT) {
|
|
126062
|
-
effects.consume(code);
|
|
126063
|
-
return matchChars(ABLE_SUFFIX, openAfterTagName, body);
|
|
126064
|
-
}
|
|
126065
|
-
return body(code);
|
|
126066
|
-
}
|
|
126067
|
-
function closeTagFirstChar(code) {
|
|
126068
|
-
if (code === codes.uppercaseT || code === codes.lowercaseT) {
|
|
126069
|
-
effects.consume(code);
|
|
126070
|
-
return matchChars(ABLE_SUFFIX, closeGt, body);
|
|
126071
|
-
}
|
|
126072
|
-
return body(code);
|
|
126073
|
-
}
|
|
126074
|
-
function openAfterTagName(code) {
|
|
126075
|
-
if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
|
|
126076
|
-
depth += 1;
|
|
126077
|
-
effects.consume(code);
|
|
126078
|
-
return body;
|
|
126079
|
-
}
|
|
126080
|
-
return body(code);
|
|
126081
|
-
}
|
|
126082
|
-
function closeGt(code) {
|
|
126083
|
-
if (code === codes.greaterThan) {
|
|
126084
|
-
depth -= 1;
|
|
126085
|
-
effects.consume(code);
|
|
126086
|
-
if (depth === 0) {
|
|
126087
|
-
return afterClose;
|
|
126088
|
-
}
|
|
126089
|
-
return body;
|
|
126090
|
-
}
|
|
126091
|
-
return body(code);
|
|
126092
|
-
}
|
|
126093
|
-
function afterClose(code) {
|
|
126094
|
-
if (code === null || markdownLineEnding(code)) {
|
|
126095
|
-
effects.exit('jsxTableData');
|
|
126096
|
-
effects.exit('jsxTable');
|
|
126097
|
-
return ok(code);
|
|
126098
|
-
}
|
|
126099
|
-
effects.consume(code);
|
|
126100
|
-
return afterClose;
|
|
126101
|
-
}
|
|
126102
|
-
// Line ending handling — follows the htmlFlow pattern
|
|
126103
|
-
function continuationStart(code) {
|
|
126104
|
-
return effects.check(jsx_table_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
|
|
126105
|
-
}
|
|
126106
|
-
function continuationStartNonLazy(code) {
|
|
126107
|
-
effects.enter(types_types.lineEnding);
|
|
126108
|
-
effects.consume(code);
|
|
126109
|
-
effects.exit(types_types.lineEnding);
|
|
126110
|
-
return continuationBefore;
|
|
126111
|
-
}
|
|
126112
|
-
function continuationBefore(code) {
|
|
126113
|
-
if (code === null || markdownLineEnding(code)) {
|
|
126114
|
-
return continuationStart(code);
|
|
126115
|
-
}
|
|
126116
|
-
effects.enter('jsxTableData');
|
|
126117
|
-
return body(code);
|
|
126118
|
-
}
|
|
126119
|
-
function continuationAfter(code) {
|
|
126120
|
-
// At EOF without </Table>, reject so content isn't swallowed
|
|
126121
|
-
if (code === null) {
|
|
126122
|
-
return nok(code);
|
|
126123
|
-
}
|
|
126124
|
-
effects.exit('jsxTable');
|
|
126125
|
-
return ok(code);
|
|
126126
|
-
}
|
|
126127
|
-
}
|
|
126128
|
-
function jsx_table_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
126129
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
126130
|
-
const self = this;
|
|
126131
|
-
return start;
|
|
126132
|
-
function start(code) {
|
|
126133
|
-
if (markdownLineEnding(code)) {
|
|
126134
|
-
effects.enter(types_types.lineEnding);
|
|
126135
|
-
effects.consume(code);
|
|
126136
|
-
effects.exit(types_types.lineEnding);
|
|
126137
|
-
return after;
|
|
126138
|
-
}
|
|
126139
|
-
return nok(code);
|
|
126140
|
-
}
|
|
126141
|
-
function after(code) {
|
|
126142
|
-
if (self.parser.lazy[self.now().line]) {
|
|
126143
|
-
return nok(code);
|
|
126144
|
-
}
|
|
126145
|
-
return ok(code);
|
|
126146
|
-
}
|
|
126147
|
-
}
|
|
126148
|
-
/**
|
|
126149
|
-
* Micromark extension that tokenizes `<Table>...</Table>` and `<table>...</table>`
|
|
126150
|
-
* as a single flow block.
|
|
126151
|
-
*
|
|
126152
|
-
* Prevents CommonMark HTML block type 6 from fragmenting table blocks at blank lines.
|
|
126153
|
-
*/
|
|
126154
|
-
function jsxTable() {
|
|
126155
|
-
return {
|
|
126156
|
-
flow: {
|
|
126157
|
-
[codes.lessThan]: [jsxTableConstruct],
|
|
126158
|
-
},
|
|
126159
|
-
};
|
|
126160
|
-
}
|
|
126161
|
-
|
|
126162
|
-
;// ./lib/micromark/jsx-table/index.ts
|
|
126163
|
-
|
|
126164
|
-
|
|
126165
126613
|
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
126166
126614
|
|
|
126167
126615
|
|
|
@@ -126337,6 +126785,9 @@ function loadComponents() {
|
|
|
126337
126785
|
|
|
126338
126786
|
|
|
126339
126787
|
|
|
126788
|
+
|
|
126789
|
+
|
|
126790
|
+
|
|
126340
126791
|
|
|
126341
126792
|
|
|
126342
126793
|
|
|
@@ -126351,15 +126802,19 @@ const defaultTransformers = [
|
|
|
126351
126802
|
* CommonMark/remark limitations and reach parity with legacy (rdmd) rendering.
|
|
126352
126803
|
*
|
|
126353
126804
|
* Runs a series of string-level transformations before micromark/remark parsing:
|
|
126354
|
-
* 1.
|
|
126355
|
-
* 2.
|
|
126356
|
-
* 3.
|
|
126357
|
-
* 4.
|
|
126358
|
-
* 5.
|
|
126805
|
+
* 1. Canonicalize closing tags with stray whitespace (e.g., `</ td >` → `</td>`)
|
|
126806
|
+
* 2. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
126807
|
+
* 3. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
126808
|
+
* 4. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
126809
|
+
* 5. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
126810
|
+
* 6. Replace snake_case component names with parser-safe placeholders
|
|
126359
126811
|
*/
|
|
126360
126812
|
function preprocessContent(content, opts) {
|
|
126361
126813
|
const { knownComponents } = opts;
|
|
126362
|
-
|
|
126814
|
+
// Runs first so `jsxTable` sees a literal `</table>` (and the HTML-line
|
|
126815
|
+
// classification in `terminateHtmlFlowBlocks` is accurate)
|
|
126816
|
+
let result = normalizeClosingTagWhitespace(content);
|
|
126817
|
+
result = normalizeTableSeparator(result);
|
|
126363
126818
|
result = terminateHtmlFlowBlocks(result);
|
|
126364
126819
|
result = closeSelfClosingHtmlTags(result);
|
|
126365
126820
|
result = normalizeCompactHeadings(result);
|
|
@@ -126388,6 +126843,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
126388
126843
|
syntax_gemoji(),
|
|
126389
126844
|
legacyVariable(),
|
|
126390
126845
|
looseHtmlEntity(),
|
|
126846
|
+
htmlBlockComponent(),
|
|
126391
126847
|
];
|
|
126392
126848
|
const fromMarkdownExts = [
|
|
126393
126849
|
jsxTableFromMarkdown(),
|
|
@@ -126397,6 +126853,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
126397
126853
|
legacyVariableFromMarkdown(),
|
|
126398
126854
|
emptyTaskListItemFromMarkdown(),
|
|
126399
126855
|
looseHtmlEntityFromMarkdown(),
|
|
126856
|
+
htmlBlockComponentFromMarkdown(),
|
|
126400
126857
|
];
|
|
126401
126858
|
if (!safeMode) {
|
|
126402
126859
|
// Insert mdx expression (text-only, no flow) after gemoji at index 3
|
|
@@ -126410,6 +126867,10 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
126410
126867
|
// JSX comment tokenizer must come before magicBlock so it claims `{/* ... */}` first
|
|
126411
126868
|
micromarkExts.unshift(jsxComment());
|
|
126412
126869
|
}
|
|
126870
|
+
// Claim `<HTMLBlock>` as one opaque token so broad tokenizers can't fragment its body
|
|
126871
|
+
// We put this last as micromark tries the last-registered extension first, so push (not unshift) to win the `<` race.
|
|
126872
|
+
// micromarkExts.push(htmlBlockComponent());
|
|
126873
|
+
// fromMarkdownExts.push(htmlBlockComponentFromMarkdown());
|
|
126413
126874
|
const processor = unified()
|
|
126414
126875
|
.data('micromarkExtensions', micromarkExts)
|
|
126415
126876
|
.data('fromMarkdownExtensions', fromMarkdownExts)
|
|
@@ -127009,332 +127470,6 @@ const mdxishTags_tags = (doc) => {
|
|
|
127009
127470
|
};
|
|
127010
127471
|
/* harmony default export */ const mdxishTags = (mdxishTags_tags);
|
|
127011
127472
|
|
|
127012
|
-
;// ./lib/mdast-util/html-block-component/index.ts
|
|
127013
|
-
const html_block_component_contextMap = new WeakMap();
|
|
127014
|
-
function findHtmlBlockComponentToken() {
|
|
127015
|
-
const events = this.tokenStack;
|
|
127016
|
-
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
127017
|
-
if (events[i][0].type === 'htmlBlockComponent')
|
|
127018
|
-
return events[i][0];
|
|
127019
|
-
}
|
|
127020
|
-
return undefined;
|
|
127021
|
-
}
|
|
127022
|
-
function enterHtmlBlockComponent(token) {
|
|
127023
|
-
html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
|
|
127024
|
-
this.enter({ type: 'html', value: '' }, token);
|
|
127025
|
-
}
|
|
127026
|
-
function exitHtmlBlockComponentData(token) {
|
|
127027
|
-
const componentToken = findHtmlBlockComponentToken.call(this);
|
|
127028
|
-
if (!componentToken)
|
|
127029
|
-
return;
|
|
127030
|
-
const ctx = html_block_component_contextMap.get(componentToken);
|
|
127031
|
-
if (ctx) {
|
|
127032
|
-
const gap = token.start.line - ctx.lastEndLine;
|
|
127033
|
-
if (ctx.chunks.length > 0 && gap > 0) {
|
|
127034
|
-
ctx.chunks.push('\n'.repeat(gap));
|
|
127035
|
-
}
|
|
127036
|
-
ctx.chunks.push(this.sliceSerialize(token));
|
|
127037
|
-
ctx.lastEndLine = token.end.line;
|
|
127038
|
-
}
|
|
127039
|
-
}
|
|
127040
|
-
function exitHtmlBlockComponent(token) {
|
|
127041
|
-
const ctx = html_block_component_contextMap.get(token);
|
|
127042
|
-
const node = this.stack[this.stack.length - 1];
|
|
127043
|
-
if (ctx) {
|
|
127044
|
-
node.value = ctx.chunks.join('');
|
|
127045
|
-
html_block_component_contextMap.delete(token);
|
|
127046
|
-
}
|
|
127047
|
-
this.exit(token);
|
|
127048
|
-
}
|
|
127049
|
-
function htmlBlockComponentFromMarkdown() {
|
|
127050
|
-
return {
|
|
127051
|
-
enter: {
|
|
127052
|
-
htmlBlockComponent: enterHtmlBlockComponent,
|
|
127053
|
-
},
|
|
127054
|
-
exit: {
|
|
127055
|
-
htmlBlockComponentData: exitHtmlBlockComponentData,
|
|
127056
|
-
htmlBlockComponent: exitHtmlBlockComponent,
|
|
127057
|
-
},
|
|
127058
|
-
};
|
|
127059
|
-
}
|
|
127060
|
-
|
|
127061
|
-
;// ./lib/micromark/html-block-component/syntax.ts
|
|
127062
|
-
|
|
127063
|
-
|
|
127064
|
-
const TAG_SUFFIX = [
|
|
127065
|
-
codes.uppercaseT,
|
|
127066
|
-
codes.uppercaseM,
|
|
127067
|
-
codes.uppercaseL,
|
|
127068
|
-
codes.uppercaseB,
|
|
127069
|
-
codes.lowercaseL,
|
|
127070
|
-
codes.lowercaseO,
|
|
127071
|
-
codes.lowercaseC,
|
|
127072
|
-
codes.lowercaseK,
|
|
127073
|
-
];
|
|
127074
|
-
// ---------------------------------------------------------------------------
|
|
127075
|
-
// Shared tokenizer factory
|
|
127076
|
-
// ---------------------------------------------------------------------------
|
|
127077
|
-
/**
|
|
127078
|
-
* Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
|
|
127079
|
-
*
|
|
127080
|
-
* - **flow** (block-level): supports multiline content via line continuations,
|
|
127081
|
-
* consumes trailing whitespace after the closing tag.
|
|
127082
|
-
* - **text** (inline): single-line only, exits immediately after the closing tag.
|
|
127083
|
-
*/
|
|
127084
|
-
function syntax_createTokenize(mode) {
|
|
127085
|
-
return function tokenize(effects, ok, nok) {
|
|
127086
|
-
let depth = 1;
|
|
127087
|
-
function matchChars(chars, onMatch, onFail) {
|
|
127088
|
-
if (chars.length === 0)
|
|
127089
|
-
return onMatch;
|
|
127090
|
-
const next = (code) => {
|
|
127091
|
-
if (code === chars[0]) {
|
|
127092
|
-
effects.consume(code);
|
|
127093
|
-
return matchChars(chars.slice(1), onMatch, onFail);
|
|
127094
|
-
}
|
|
127095
|
-
return onFail(code);
|
|
127096
|
-
};
|
|
127097
|
-
return next;
|
|
127098
|
-
}
|
|
127099
|
-
function matchTagName(onMatch, onFail) {
|
|
127100
|
-
const next = (code) => {
|
|
127101
|
-
if (code === codes.uppercaseH) {
|
|
127102
|
-
effects.consume(code);
|
|
127103
|
-
return matchChars(TAG_SUFFIX, onMatch, onFail);
|
|
127104
|
-
}
|
|
127105
|
-
return onFail(code);
|
|
127106
|
-
};
|
|
127107
|
-
return next;
|
|
127108
|
-
}
|
|
127109
|
-
return start;
|
|
127110
|
-
function start(code) {
|
|
127111
|
-
if (code !== codes.lessThan)
|
|
127112
|
-
return nok(code);
|
|
127113
|
-
effects.enter('htmlBlockComponent');
|
|
127114
|
-
effects.enter('htmlBlockComponentData');
|
|
127115
|
-
effects.consume(code);
|
|
127116
|
-
return matchTagName(afterTagName, nok);
|
|
127117
|
-
}
|
|
127118
|
-
function afterTagName(code) {
|
|
127119
|
-
if (code === codes.greaterThan) {
|
|
127120
|
-
effects.consume(code);
|
|
127121
|
-
return body;
|
|
127122
|
-
}
|
|
127123
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
127124
|
-
effects.consume(code);
|
|
127125
|
-
return inAttributes;
|
|
127126
|
-
}
|
|
127127
|
-
if (mode === 'flow' && markdownLineEnding(code)) {
|
|
127128
|
-
effects.exit('htmlBlockComponentData');
|
|
127129
|
-
return attributeContinuationStart(code);
|
|
127130
|
-
}
|
|
127131
|
-
if (code === codes.slash) {
|
|
127132
|
-
effects.consume(code);
|
|
127133
|
-
return selfClose;
|
|
127134
|
-
}
|
|
127135
|
-
return nok(code);
|
|
127136
|
-
}
|
|
127137
|
-
function inAttributes(code) {
|
|
127138
|
-
if (code === codes.greaterThan) {
|
|
127139
|
-
effects.consume(code);
|
|
127140
|
-
return body;
|
|
127141
|
-
}
|
|
127142
|
-
if (code === null) {
|
|
127143
|
-
return nok(code);
|
|
127144
|
-
}
|
|
127145
|
-
if (markdownLineEnding(code)) {
|
|
127146
|
-
if (mode === 'text')
|
|
127147
|
-
return nok(code);
|
|
127148
|
-
effects.exit('htmlBlockComponentData');
|
|
127149
|
-
return attributeContinuationStart(code);
|
|
127150
|
-
}
|
|
127151
|
-
effects.consume(code);
|
|
127152
|
-
return inAttributes;
|
|
127153
|
-
}
|
|
127154
|
-
function attributeContinuationStart(code) {
|
|
127155
|
-
return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
|
|
127156
|
-
}
|
|
127157
|
-
function attributeContinuationNonLazy(code) {
|
|
127158
|
-
effects.enter(types_types.lineEnding);
|
|
127159
|
-
effects.consume(code);
|
|
127160
|
-
effects.exit(types_types.lineEnding);
|
|
127161
|
-
return attributeContinuationBefore;
|
|
127162
|
-
}
|
|
127163
|
-
function attributeContinuationBefore(code) {
|
|
127164
|
-
if (code === null || markdownLineEnding(code)) {
|
|
127165
|
-
return attributeContinuationStart(code);
|
|
127166
|
-
}
|
|
127167
|
-
effects.enter('htmlBlockComponentData');
|
|
127168
|
-
return inAttributes(code);
|
|
127169
|
-
}
|
|
127170
|
-
function selfClose(code) {
|
|
127171
|
-
if (code === codes.greaterThan) {
|
|
127172
|
-
effects.consume(code);
|
|
127173
|
-
return mode === 'flow' ? afterClose : done(code);
|
|
127174
|
-
}
|
|
127175
|
-
return nok(code);
|
|
127176
|
-
}
|
|
127177
|
-
function body(code) {
|
|
127178
|
-
if (code === null)
|
|
127179
|
-
return nok(code);
|
|
127180
|
-
if (markdownLineEnding(code)) {
|
|
127181
|
-
if (mode === 'text') {
|
|
127182
|
-
// Text constructs operate on paragraph content which spans lines
|
|
127183
|
-
effects.consume(code);
|
|
127184
|
-
return body;
|
|
127185
|
-
}
|
|
127186
|
-
effects.exit('htmlBlockComponentData');
|
|
127187
|
-
return continuationStart(code);
|
|
127188
|
-
}
|
|
127189
|
-
if (code === codes.lessThan) {
|
|
127190
|
-
effects.consume(code);
|
|
127191
|
-
return closeSlash;
|
|
127192
|
-
}
|
|
127193
|
-
effects.consume(code);
|
|
127194
|
-
return body;
|
|
127195
|
-
}
|
|
127196
|
-
function closeSlash(code) {
|
|
127197
|
-
if (code === codes.slash) {
|
|
127198
|
-
effects.consume(code);
|
|
127199
|
-
return matchTagName(closeGt, body);
|
|
127200
|
-
}
|
|
127201
|
-
return matchTagName(openAfterTagName, body)(code);
|
|
127202
|
-
}
|
|
127203
|
-
function openAfterTagName(code) {
|
|
127204
|
-
if (code === codes.greaterThan || code === codes.space || code === codes.horizontalTab) {
|
|
127205
|
-
depth += 1;
|
|
127206
|
-
effects.consume(code);
|
|
127207
|
-
return body;
|
|
127208
|
-
}
|
|
127209
|
-
return body(code);
|
|
127210
|
-
}
|
|
127211
|
-
function closeGt(code) {
|
|
127212
|
-
if (code === codes.greaterThan) {
|
|
127213
|
-
depth -= 1;
|
|
127214
|
-
effects.consume(code);
|
|
127215
|
-
if (depth === 0) {
|
|
127216
|
-
return mode === 'flow' ? afterClose : done(code);
|
|
127217
|
-
}
|
|
127218
|
-
return body;
|
|
127219
|
-
}
|
|
127220
|
-
return body(code);
|
|
127221
|
-
}
|
|
127222
|
-
// -- flow-only states ---------------------------------------------------
|
|
127223
|
-
function afterClose(code) {
|
|
127224
|
-
if (code === null || markdownLineEnding(code)) {
|
|
127225
|
-
return done(code);
|
|
127226
|
-
}
|
|
127227
|
-
if (code === codes.space || code === codes.horizontalTab) {
|
|
127228
|
-
effects.consume(code);
|
|
127229
|
-
return afterClose;
|
|
127230
|
-
}
|
|
127231
|
-
// Reject so the block re-parses as a paragraph, deferring to the
|
|
127232
|
-
// text tokenizer which preserves trailing content in the same line.
|
|
127233
|
-
return nok(code);
|
|
127234
|
-
}
|
|
127235
|
-
// -- flow-only: line continuation ---------------------------------------
|
|
127236
|
-
function continuationStart(code) {
|
|
127237
|
-
return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
|
|
127238
|
-
}
|
|
127239
|
-
function continuationStartNonLazy(code) {
|
|
127240
|
-
effects.enter(types_types.lineEnding);
|
|
127241
|
-
effects.consume(code);
|
|
127242
|
-
effects.exit(types_types.lineEnding);
|
|
127243
|
-
return continuationBefore;
|
|
127244
|
-
}
|
|
127245
|
-
function continuationBefore(code) {
|
|
127246
|
-
if (code === null || markdownLineEnding(code)) {
|
|
127247
|
-
return continuationStart(code);
|
|
127248
|
-
}
|
|
127249
|
-
effects.enter('htmlBlockComponentData');
|
|
127250
|
-
return body(code);
|
|
127251
|
-
}
|
|
127252
|
-
function continuationAfter(code) {
|
|
127253
|
-
if (code === null)
|
|
127254
|
-
return nok(code);
|
|
127255
|
-
effects.exit('htmlBlockComponent');
|
|
127256
|
-
return ok(code);
|
|
127257
|
-
}
|
|
127258
|
-
// -- shared exit --------------------------------------------------------
|
|
127259
|
-
function done(_code) {
|
|
127260
|
-
effects.exit('htmlBlockComponentData');
|
|
127261
|
-
effects.exit('htmlBlockComponent');
|
|
127262
|
-
return ok(_code);
|
|
127263
|
-
}
|
|
127264
|
-
};
|
|
127265
|
-
}
|
|
127266
|
-
// ---------------------------------------------------------------------------
|
|
127267
|
-
// Flow construct (block-level)
|
|
127268
|
-
// ---------------------------------------------------------------------------
|
|
127269
|
-
const html_block_component_syntax_nonLazyContinuationStart = {
|
|
127270
|
-
tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
|
|
127271
|
-
partial: true,
|
|
127272
|
-
};
|
|
127273
|
-
function resolveToHtmlBlockComponent(events) {
|
|
127274
|
-
let index = events.length;
|
|
127275
|
-
while (index > 0) {
|
|
127276
|
-
index -= 1;
|
|
127277
|
-
if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
|
|
127278
|
-
break;
|
|
127279
|
-
}
|
|
127280
|
-
}
|
|
127281
|
-
if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
|
|
127282
|
-
events[index][1].start = events[index - 2][1].start;
|
|
127283
|
-
events[index + 1][1].start = events[index - 2][1].start;
|
|
127284
|
-
events.splice(index - 2, 2);
|
|
127285
|
-
}
|
|
127286
|
-
return events;
|
|
127287
|
-
}
|
|
127288
|
-
const htmlBlockComponentFlowConstruct = {
|
|
127289
|
-
name: 'htmlBlockComponent',
|
|
127290
|
-
tokenize: syntax_createTokenize('flow'),
|
|
127291
|
-
resolveTo: resolveToHtmlBlockComponent,
|
|
127292
|
-
concrete: true,
|
|
127293
|
-
};
|
|
127294
|
-
function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
127295
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
127296
|
-
const self = this;
|
|
127297
|
-
return start;
|
|
127298
|
-
function start(code) {
|
|
127299
|
-
if (markdownLineEnding(code)) {
|
|
127300
|
-
effects.enter(types_types.lineEnding);
|
|
127301
|
-
effects.consume(code);
|
|
127302
|
-
effects.exit(types_types.lineEnding);
|
|
127303
|
-
return after;
|
|
127304
|
-
}
|
|
127305
|
-
return nok(code);
|
|
127306
|
-
}
|
|
127307
|
-
function after(code) {
|
|
127308
|
-
if (self.parser.lazy[self.now().line]) {
|
|
127309
|
-
return nok(code);
|
|
127310
|
-
}
|
|
127311
|
-
return ok(code);
|
|
127312
|
-
}
|
|
127313
|
-
}
|
|
127314
|
-
// ---------------------------------------------------------------------------
|
|
127315
|
-
// Text construct (inline)
|
|
127316
|
-
// ---------------------------------------------------------------------------
|
|
127317
|
-
const htmlBlockComponentTextConstruct = {
|
|
127318
|
-
name: 'htmlBlockComponent',
|
|
127319
|
-
tokenize: syntax_createTokenize('text'),
|
|
127320
|
-
};
|
|
127321
|
-
// ---------------------------------------------------------------------------
|
|
127322
|
-
// Extension
|
|
127323
|
-
// ---------------------------------------------------------------------------
|
|
127324
|
-
function htmlBlockComponent() {
|
|
127325
|
-
return {
|
|
127326
|
-
flow: {
|
|
127327
|
-
[codes.lessThan]: [htmlBlockComponentFlowConstruct],
|
|
127328
|
-
},
|
|
127329
|
-
text: {
|
|
127330
|
-
[codes.lessThan]: [htmlBlockComponentTextConstruct],
|
|
127331
|
-
},
|
|
127332
|
-
};
|
|
127333
|
-
}
|
|
127334
|
-
|
|
127335
|
-
;// ./lib/micromark/html-block-component/index.ts
|
|
127336
|
-
|
|
127337
|
-
|
|
127338
127473
|
;// ./lib/utils/extractMagicBlocks.ts
|
|
127339
127474
|
/**
|
|
127340
127475
|
* The content matching in this regex captures everything between `[block:TYPE]`
|