@readme/markdown 15.5.1 → 15.6.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.
@@ -19045,7 +19045,7 @@ module.exports = function () {
19045
19045
 
19046
19046
  /***/ },
19047
19047
 
19048
- /***/ 8691
19048
+ /***/ 5072
19049
19049
  (module, __webpack_exports__, __webpack_require__) {
19050
19050
 
19051
19051
  "use strict";
@@ -19208,6 +19208,8 @@ __webpack_unused_export__ = s.renderToPipeableStream;
19208
19208
  * Pattern to match component tags (PascalCase or snake_case)
19209
19209
  */
19210
19210
  const componentTagPattern = /<(\/?[A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>/g;
19211
+ /** A bare component name, the same shape `componentTagPattern` accepts inside `<…>`. */
19212
+ const componentNamePattern = /^[A-Z][A-Za-z0-9_]*$/;
19211
19213
  /**
19212
19214
  * MDAST flow (block-level) content types that cannot be represented
19213
19215
  * inside GFM table cells. Used to decide whether a table should be
@@ -96869,6 +96871,14 @@ function syntax_createTokenize(mode) {
96869
96871
  }
96870
96872
  // ── Tag detection inside body ──────────────────────────────────────────
96871
96873
  function bodyLessThan(code) {
96874
+ // A second `<` means legacy variable syntax (`<<var>>`), not a tag: the name that
96875
+ // follows belongs to the variable. Counting it as a nested opener would leave the
96876
+ // body unbalanced and lose the claim on this block.
96877
+ if (code === codes.lessThan) {
96878
+ effects.consume(code);
96879
+ atLineStart = false;
96880
+ return bodyAngleRun;
96881
+ }
96872
96882
  if (code === codes.slash) {
96873
96883
  if (onOpenerLine)
96874
96884
  openerLineCloses += 1;
@@ -96893,6 +96903,14 @@ function syntax_createTokenize(mode) {
96893
96903
  atLineStart = false;
96894
96904
  return body(code);
96895
96905
  }
96906
+ function bodyAngleRun(code) {
96907
+ if (code === codes.lessThan) {
96908
+ effects.consume(code);
96909
+ return bodyAngleRun;
96910
+ }
96911
+ atLineStart = false;
96912
+ return body(code);
96913
+ }
96896
96914
  // ── Nested opening tag ─────────────────────────────────────────────────
96897
96915
  function nestedOpenTagName(code) {
96898
96916
  if (code !== null &&
@@ -97113,11 +97131,61 @@ function mdxComponent() {
97113
97131
  ;// ./lib/micromark/mdx-expression-lenient/syntax.ts
97114
97132
 
97115
97133
 
97134
+
97116
97135
  /**
97117
- * Lenient MDX text-expression tokenizer (agnostic / no acorn).
97136
+ * The flow constructs allowed to end a multiline run, per parser. Everything but `<`: a
97137
+ * `<Component>` on its own line is the very shape the flow construct exists to keep together.
97138
+ */
97139
+ const interrupters = new WeakMap();
97140
+ const flowInterrupters = (flow) => {
97141
+ let record = interrupters.get(flow);
97142
+ if (!record) {
97143
+ record = Object.fromEntries(Object.entries(flow).filter(([code]) => Number(code) !== codes.lessThan));
97144
+ interrupters.set(flow, record);
97145
+ }
97146
+ return record;
97147
+ };
97148
+ /**
97149
+ * Lookahead run at every line ending of a flow run, mirroring the paragraph continuation check
97150
+ * in `micromark-core-commonmark/lib/content.js`: `ok` when the next line continues the run,
97151
+ * `nok` when it would start a fenced code block, heading, or thematic break — which the run
97152
+ * must then leave alone rather than swallow. A blank line (including whitespace-only) ends the
97153
+ * run too, unless `blankContinues`: see `nestedLineContinues`.
97154
+ */
97155
+ function tokenizeLineContinues(blankContinues) {
97156
+ return function tokenize(effects, ok, nok) {
97157
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
97158
+ const self = this;
97159
+ return start;
97160
+ function start(code) {
97161
+ effects.enter(types_types.lineEnding);
97162
+ effects.consume(code);
97163
+ effects.exit(types_types.lineEnding);
97164
+ return factorySpace(effects, prefixed, types_types.linePrefix);
97165
+ }
97166
+ // The paragraph rule also exempts lines indented 4+ columns (indented code can't interrupt);
97167
+ // mdxish disables indented code, so an indented line may still start a block here.
97168
+ function prefixed(code) {
97169
+ if (code === codes.eof)
97170
+ return nok(code);
97171
+ if (markdownLineEnding(code))
97172
+ return blankContinues ? ok(code) : nok(code);
97173
+ return effects.interrupt(flowInterrupters(self.parser.constructs.flow), nok, ok)(code);
97174
+ }
97175
+ };
97176
+ }
97177
+ const lineContinues = { tokenize: tokenizeLineContinues(false), partial: true };
97178
+ /**
97179
+ * Inside an open `{`, `(` or `[` a blank line is JavaScript formatting (between statements in a
97180
+ * callback, inside a JSX branch), so it may not end the run. At depth zero it's far more likely
97181
+ * a prose paragraph break after a stray `{`, and ending the run there keeps the paragraphs apart.
97182
+ */
97183
+ const nestedLineContinues = { tokenize: tokenizeLineContinues(true), partial: true };
97184
+ /**
97185
+ * Lenient MDX expression tokenizer (agnostic / no acorn).
97118
97186
  *
97119
97187
  * Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
97120
- * line breaks — and emits the standard `mdxTextExpression*` tokens so the
97188
+ * line breaks — and emits the standard `mdx*Expression*` tokens so the
97121
97189
  * upstream `mdxExpressionFromMarkdown()` builds the node.
97122
97190
  *
97123
97191
  * Reimplements the official micromark mdxExpression, but an unbalanced brace that
@@ -97125,70 +97193,115 @@ function mdxComponent() {
97125
97193
  * and the `{` renders as literal text, making the pipeline forgiving of stray
97126
97194
  * braces that upstream would hard-error on.
97127
97195
  */
97128
- function tokenizeTextExpression(effects, ok, nok) {
97129
- let depth = 0;
97130
- return start;
97131
- function start(code) {
97132
- if (code !== codes.leftCurlyBrace)
97133
- return nok(code);
97134
- effects.enter('mdxTextExpression');
97135
- effects.enter('mdxTextExpressionMarker');
97136
- effects.consume(code);
97137
- effects.exit('mdxTextExpressionMarker');
97138
- return before;
97139
- }
97140
- function before(code) {
97141
- if (code === codes.eof) {
97142
- effects.exit('mdxTextExpression');
97143
- return nok(code);
97196
+ function tokenizeExpression(variant) {
97197
+ const isFlow = variant === 'mdxFlowExpression';
97198
+ return function tokenize(effects, ok, nok) {
97199
+ // Read eagerly: micromark calls `tokenize` with a fresh context per attempt, so this is the
97200
+ // value for this attempt, and the state functions below don't receive `this` at all.
97201
+ const { interrupt } = this;
97202
+ let depth = 0;
97203
+ let nesting = 0;
97204
+ let multiline = false;
97205
+ return start;
97206
+ function start(code) {
97207
+ if (code !== codes.leftCurlyBrace)
97208
+ return nok(code);
97209
+ // Never end a paragraph. A `{` continuing the line above is prose or a magic-block body
97210
+ // (`[block:callout]` puts one on the next line), not a block of its own.
97211
+ if (isFlow && interrupt)
97212
+ return nok(code);
97213
+ effects.enter(variant);
97214
+ effects.enter(`${variant}Marker`);
97215
+ effects.consume(code);
97216
+ effects.exit(`${variant}Marker`);
97217
+ return before;
97144
97218
  }
97145
- if (markdownLineEnding(code)) {
97146
- effects.enter('lineEnding');
97219
+ function before(code) {
97220
+ if (code === codes.eof)
97221
+ return end(code);
97222
+ if (markdownLineEnding(code)) {
97223
+ // A text run lives in a paragraph micromark has already bounded. A flow run bounds
97224
+ // itself: a blank line or an interrupting block ends it, so a stray `{` can't claim
97225
+ // the rest of the document, and `{\n\n}` stays two literal paragraphs.
97226
+ if (!isFlow)
97227
+ return lineEnding(code);
97228
+ return effects.check(depth > 0 || nesting > 0 ? nestedLineContinues : lineContinues, lineEnding, end)(code);
97229
+ }
97230
+ if (code === codes.rightCurlyBrace && depth === 0)
97231
+ return close(code);
97232
+ effects.enter(`${variant}Chunk`);
97233
+ return inside(code);
97234
+ }
97235
+ function lineEnding(code) {
97236
+ multiline = true;
97237
+ effects.enter(types_types.lineEnding);
97147
97238
  effects.consume(code);
97148
- effects.exit('lineEnding');
97239
+ effects.exit(types_types.lineEnding);
97149
97240
  return before;
97150
97241
  }
97151
- if (code === codes.rightCurlyBrace && depth === 0) {
97152
- return close(code);
97242
+ function end(code) {
97243
+ effects.exit(variant);
97244
+ return nok(code);
97153
97245
  }
97154
- effects.enter('mdxTextExpressionChunk');
97155
- return inside(code);
97156
- }
97157
- function inside(code) {
97158
- if (code === codes.eof || markdownLineEnding(code)) {
97159
- effects.exit('mdxTextExpressionChunk');
97160
- return before(code);
97246
+ function inside(code) {
97247
+ if (code === codes.eof || markdownLineEnding(code)) {
97248
+ effects.exit(`${variant}Chunk`);
97249
+ return before(code);
97250
+ }
97251
+ if (code === codes.rightCurlyBrace && depth === 0) {
97252
+ effects.exit(`${variant}Chunk`);
97253
+ return close(code);
97254
+ }
97255
+ if (code === codes.leftCurlyBrace)
97256
+ depth += 1;
97257
+ else if (code === codes.rightCurlyBrace)
97258
+ depth -= 1;
97259
+ else if (code === codes.leftParenthesis || code === codes.leftSquareBracket)
97260
+ nesting += 1;
97261
+ else if (code === codes.rightParenthesis || code === codes.rightSquareBracket)
97262
+ nesting -= 1;
97263
+ effects.consume(code);
97264
+ return inside;
97161
97265
  }
97162
- if (code === codes.rightCurlyBrace && depth === 0) {
97163
- effects.exit('mdxTextExpressionChunk');
97164
- return close(code);
97266
+ function close(code) {
97267
+ effects.enter(`${variant}Marker`);
97268
+ effects.consume(code);
97269
+ effects.exit(`${variant}Marker`);
97270
+ effects.exit(variant);
97271
+ if (!isFlow)
97272
+ return ok;
97273
+ // A run that closes on the line it opened stays a text expression inside its paragraph:
97274
+ // claiming it as flow would strip the `<p>` every standalone `{expr}` line renders with.
97275
+ return multiline ? after : nok;
97165
97276
  }
97166
- if (code === codes.leftCurlyBrace)
97167
- depth += 1;
97168
- else if (code === codes.rightCurlyBrace)
97169
- depth -= 1;
97170
- effects.consume(code);
97171
- return inside;
97172
- }
97173
- function close(code) {
97174
- effects.enter('mdxTextExpressionMarker');
97175
- effects.consume(code);
97176
- effects.exit('mdxTextExpressionMarker');
97177
- effects.exit('mdxTextExpression');
97178
- return ok;
97179
- }
97277
+ function after(code) {
97278
+ return markdownSpace(code) ? factorySpace(effects, lineEnd, types_types.whitespace)(code) : lineEnd(code);
97279
+ }
97280
+ function lineEnd(code) {
97281
+ return code === codes.eof || markdownLineEnding(code) ? ok(code) : nok(code);
97282
+ }
97283
+ };
97180
97284
  }
97181
97285
  function mdxExpressionLenient() {
97182
97286
  return {
97287
+ flow: {
97288
+ [codes.leftCurlyBrace]: {
97289
+ name: 'mdxFlowExpression',
97290
+ tokenize: tokenizeExpression('mdxFlowExpression'),
97291
+ },
97292
+ },
97183
97293
  text: {
97184
97294
  [codes.leftCurlyBrace]: {
97185
97295
  name: 'mdxTextExpression',
97186
- tokenize: tokenizeTextExpression,
97296
+ tokenize: tokenizeExpression('mdxTextExpression'),
97187
97297
  },
97188
97298
  },
97189
97299
  };
97190
97300
  }
97191
97301
 
97302
+ ;// ./lib/micromark/mdx-expression-lenient/index.ts
97303
+
97304
+
97192
97305
  ;// ./lib/micromark/mdxish-extensions.ts
97193
97306
 
97194
97307
 
@@ -122682,6 +122795,111 @@ const parseTag = (value, opts = {}) => {
122682
122795
  };
122683
122796
  };
122684
122797
 
122798
+ ;// ./processor/transform/mdxish/variables-text.ts
122799
+
122800
+
122801
+ /**
122802
+ * Matches {user.<field>} patterns:
122803
+ * - {user.name}
122804
+ * - {user.email}
122805
+ * - {user['field']}
122806
+ * - {user["field"]}
122807
+ *
122808
+ * Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
122809
+ */
122810
+ const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
122811
+ /**
122812
+ * The lone `{user.<field>}` reference an expression node holds, or `null` when the node isn't an
122813
+ * expression or holds anything else (`{1 + 1}`, a CSS-looking body, two references in one brace).
122814
+ * Exported so promotion gates can tell a variable reference apart from an expression that must
122815
+ * stay literal.
122816
+ */
122817
+ function soleUserVariableExpression(node) {
122818
+ if (node.type !== 'mdxFlowExpression' && node.type !== 'mdxTextExpression')
122819
+ return null;
122820
+ const { value } = node;
122821
+ const wrapped = `{${(value ?? '').trim()}}`;
122822
+ const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
122823
+ if (matches.length !== 1 || matches[0][0] !== wrapped)
122824
+ return null;
122825
+ return { name: matches[0][1] || matches[0][2], wrapped };
122826
+ }
122827
+ function makeVariableNode(varName, rawValue) {
122828
+ return {
122829
+ type: NodeTypes.variable,
122830
+ data: {
122831
+ hName: 'Variable',
122832
+ hProperties: { name: varName },
122833
+ },
122834
+ value: rawValue,
122835
+ };
122836
+ }
122837
+ /**
122838
+ * A remark plugin that parses {user.<field>} patterns from text nodes and
122839
+ * mdx expression nodes, creating Variable nodes for runtime resolution.
122840
+ *
122841
+ * Handles:
122842
+ * - `text` nodes: when safeMode is true or after expression evaluation
122843
+ * - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
122844
+ * - `mdxFlowExpression` nodes: when {user.*} appears on its own line (e.g. inside JSX table cells)
122845
+ *
122846
+ * Supports any user field: name, email, email_verified, exp, iat, etc.
122847
+ */
122848
+ function visitExpressionNode(node, index, parent) {
122849
+ if (index === undefined || !parent)
122850
+ return;
122851
+ const match = soleUserVariableExpression(node);
122852
+ if (!match)
122853
+ return;
122854
+ parent.children.splice(index, 1, makeVariableNode(match.name, match.wrapped));
122855
+ }
122856
+ const variablesTextTransformer = () => tree => {
122857
+ visit(tree, 'mdxTextExpression', (node, index, parent) => {
122858
+ visitExpressionNode(node, index, parent);
122859
+ });
122860
+ visit(tree, 'mdxFlowExpression', (node, index, parent) => {
122861
+ visitExpressionNode(node, index, parent);
122862
+ });
122863
+ visit(tree, 'text', (node, index, parent) => {
122864
+ if (index === undefined || !parent)
122865
+ return;
122866
+ // Skip if inside inline code
122867
+ if (parent.type === 'inlineCode')
122868
+ return;
122869
+ const text = node.value;
122870
+ if (typeof text !== 'string' || !text.trim())
122871
+ return;
122872
+ if (!text.includes('{user.') && !text.includes('{user['))
122873
+ return;
122874
+ const matches = [...text.matchAll(USER_VAR_REGEX)];
122875
+ if (matches.length === 0)
122876
+ return;
122877
+ const parts = [];
122878
+ let lastIndex = 0;
122879
+ matches.forEach(match => {
122880
+ const matchIndex = match.index ?? 0;
122881
+ // Add text before the match
122882
+ if (matchIndex > lastIndex) {
122883
+ parts.push({ type: 'text', value: text.slice(lastIndex, matchIndex) });
122884
+ }
122885
+ // Extract variable name from either capture group (dot or bracket notation)
122886
+ const varName = match[1] || match[2];
122887
+ parts.push(makeVariableNode(varName, match[0]));
122888
+ lastIndex = matchIndex + match[0].length;
122889
+ });
122890
+ // Add remaining text after last match
122891
+ if (lastIndex < text.length) {
122892
+ parts.push({ type: 'text', value: text.slice(lastIndex) });
122893
+ }
122894
+ // Replace node with parts
122895
+ if (parts.length > 1 || (parts.length === 1 && parts[0].type !== 'text')) {
122896
+ parent.children.splice(index, 1, ...parts);
122897
+ }
122898
+ });
122899
+ return tree;
122900
+ };
122901
+ /* harmony default export */ const variables_text = (variablesTextTransformer);
122902
+
122685
122903
  ;// ./processor/transform/mdxish/components/utils.ts
122686
122904
 
122687
122905
 
@@ -122759,19 +122977,15 @@ const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table
122759
122977
  const NESTED_TABLE_RE = /<table[\s>]/i;
122760
122978
  const isMarkdownPromotableHtmlTag = (tag) => !NON_PROMOTABLE_PLAIN_TAGS.has(tag);
122761
122979
  // Expression nodes count as plain so `<div>{1+1}</div>` keeps its current
122762
- // literal-brace behavior; variables/glossary already resolve inside raw html.
122763
- const PLAIN_CONTENT_TYPES = new Set([
122764
- 'paragraph',
122765
- 'text',
122766
- 'html',
122767
- 'mdxTextExpression',
122768
- 'mdxFlowExpression',
122769
- NodeTypes.variable,
122770
- NodeTypes.glossary,
122771
- ]);
122980
+ // literal-brace behavior — authors put CSS-shaped braces in these bodies, and only
122981
+ // a reference that names a real variable may resolve.
122982
+ const PLAIN_CONTENT_TYPES = new Set(['paragraph', 'text', 'html', 'mdxTextExpression', 'mdxFlowExpression']);
122772
122983
  // Promoting plain HTML is only worth bypassing rehype-raw's parse5 pass when
122773
- // the body parses into an actual markdown construct.
122984
+ // the body parses into an actual markdown construct. Variables and glossary terms
122985
+ // count: parse5 renders `<<var>>` as a stray `<` plus a `<var>` tag, so a body that
122986
+ // holds nothing else still has to be promoted to resolve.
122774
122987
  const containsMarkdownConstruct = (nodes) => nodes.some(node => !PLAIN_CONTENT_TYPES.has(node.type) ||
122988
+ soleUserVariableExpression(node) !== null ||
122775
122989
  ('children' in node && Array.isArray(node.children) && containsMarkdownConstruct(node.children)));
122776
122990
  /**
122777
122991
  * Index of the `</tag>` that balances the already-consumed opening tag (the
@@ -123537,6 +123751,7 @@ const evaluateExports = () => (tree, file) => {
123537
123751
 
123538
123752
 
123539
123753
 
123754
+
123540
123755
  const parseExpression = (expression) => jsxAcornParser.parse(expression, { ecmaVersion: 'latest', sourceType: 'module' });
123541
123756
  /**
123542
123757
  * Recursively report whether an estree value contains any JSX element or fragment node.
@@ -123553,22 +123768,16 @@ const containsJsxNode = (value) => {
123553
123768
  return true;
123554
123769
  return Object.values(value).some(containsJsxNode);
123555
123770
  };
123556
- /** Read the component name off a JSX element name node (`Foo`, `Foo.Bar`, `foo:Bar`). */
123557
123771
  const jsxElementName = (name) => {
123558
123772
  if (name === null || typeof name !== 'object')
123559
123773
  return undefined;
123560
123774
  const node = name;
123561
- if (node.type === 'JSXIdentifier')
123562
- return typeof node.name === 'string' ? node.name : undefined;
123563
- // `<Foo.Bar/>` and `<foo:Bar/>` resolve through their leftmost part.
123564
- if (node.type === 'JSXMemberExpression')
123565
- return jsxElementName(node.object);
123566
- if (node.type === 'JSXNamespacedName')
123567
- return jsxElementName(node.namespace);
123568
- return undefined;
123775
+ if (node.type !== 'JSXIdentifier' || typeof node.name !== 'string')
123776
+ return undefined;
123777
+ return componentNamePattern.test(node.name) ? node.name : undefined;
123569
123778
  };
123570
123779
  /**
123571
- * Collect the capitalized names an expression uses as JSX tags. Parsed rather than pattern
123780
+ * Collect the component names an expression uses as JSX tags. Parsed rather than pattern
123572
123781
  * matched: `{count < Max ? <Foo/> : <Bar/>}` puts a capitalized name straight after a `<` without
123573
123782
  * it being a tag, and only the parser can tell the two apart. Unparseable input yields nothing —
123574
123783
  * evaluation is about to throw on it anyway.
@@ -123592,8 +123801,7 @@ const jsxComponentNames = (expression) => {
123592
123801
  const node = value;
123593
123802
  if (node.type === 'JSXOpeningElement') {
123594
123803
  const name = jsxElementName(node.name);
123595
- // Lowercase tags compile to a string type, never a variable reference.
123596
- if (name && /^[A-Z]/.test(name))
123804
+ if (name)
123597
123805
  names.add(name);
123598
123806
  }
123599
123807
  Object.values(node).forEach(walk);
@@ -123733,7 +123941,8 @@ function renderFallbackHtml(element) {
123733
123941
  const rawNode = { type: 'raw', value: __WEBPACK_CJS_EXPORT_renderToStaticMarkup__(element) };
123734
123942
  return [rawNode];
123735
123943
  }
123736
- catch {
123944
+ catch (error) {
123945
+ console.warn('[mdxish] Could not render expression result:', error);
123737
123946
  return [];
123738
123947
  }
123739
123948
  }
@@ -123791,6 +124000,7 @@ function reactElementToHast(node) {
123791
124000
 
123792
124001
 
123793
124002
 
124003
+
123794
124004
  /**
123795
124005
  * Bind the components a given expression actually uses as tags. Scoped per expression on purpose:
123796
124006
  * binding the whole hash would shadow same-named globals (a `math` component would break
@@ -123819,17 +124029,28 @@ const isRenderable = (value) => {
123819
124029
  return true;
123820
124030
  return Array.isArray(value) && value.some(isRenderable);
123821
124031
  };
124032
+ const isPhrasingTag = (tagName) => lib_phrasing({ type: 'element', tagName, properties: {}, children: [] });
123822
124033
  /**
123823
- * Whether an expression evaluated to block-level content. Components count as block-level
123824
- * unless they're on the inline list, matching the assumption the rest of the component
123825
- * pipeline makes.
124034
+ * Whether an expression evaluated to block-level content. A capitalized tag is a component,
124035
+ * block-level unless it's on the inline list (so a `Table` component isn't mistaken for an inline
124036
+ * `<table>`); a lowercase tag is HTML, block-level unless it's phrasing content. A `raw` node is
124037
+ * HTML from `renderFallbackHtml`, so it's parsed and judged by the same rule.
123826
124038
  */
123827
124039
  const isBlockResult = (children) => children.some(child => {
124040
+ if (child.type === 'raw')
124041
+ return isBlockResult(fromHtml(child.value, { fragment: true }).children);
123828
124042
  if (child.type !== 'element' && child.type !== 'mdx-jsx')
123829
124043
  return false;
123830
124044
  const { tagName } = child;
123831
- return !STANDARD_HTML_TAGS.has(tagName.toLowerCase()) && !INLINE_COMPONENT_TAGS.has(tagName);
124045
+ return /^[A-Z]/.test(tagName) ? !INLINE_COMPONENT_TAGS.has(tagName) : !isPhrasingTag(tagName);
123832
124046
  });
124047
+ const JSX_ELEMENT_TYPES = new Set(['mdxJsxFlowElement', 'mdxJsxTextElement']);
124048
+ const wrapInParagraph = (child) => ({
124049
+ type: 'paragraph',
124050
+ children: [child],
124051
+ position: child.position,
124052
+ });
124053
+ const placeText = (text, needsBlock) => (needsBlock ? wrapInParagraph(text) : text);
123833
124054
  /** Turn a non-renderable evaluation result into a text node. */
123834
124055
  const createTextNode = (result, position) => {
123835
124056
  if (result === null || result === undefined)
@@ -123865,6 +124086,7 @@ const evaluateExpressions = ({ components, variables } = {}) => (tree, file) =>
123865
124086
  const expression = value?.trim();
123866
124087
  if (!expression)
123867
124088
  return;
124089
+ const needsBlock = expressionNode.type === 'mdxFlowExpression' && !JSX_ELEMENT_TYPES.has(parent.type);
123868
124090
  try {
123869
124091
  const scope = { ...componentScope(expression, components ?? {}), ...baseScope };
123870
124092
  const result = evalExpression(expression, scope);
@@ -123873,10 +124095,17 @@ const evaluateExpressions = ({ components, variables } = {}) => (tree, file) =>
123873
124095
  // passes through rehypeRaw/parse5 step later in the pipeline. This ensures that the
123874
124096
  // expression result is not parsed by parse5 and fragmenting the nesting that is valid JSX
123875
124097
  // but invalid HTML — e.g. an `<a>` wrapping `<a>`.
123876
- expressionNode.data = { ...expressionNode.data, hChildren: reactElementToHast(result) };
124098
+ const hChildren = reactElementToHast(result);
124099
+ expressionNode.data = { ...expressionNode.data, hChildren };
124100
+ // An inline result in a block slot renders inside a `<p>`, as its one-line form does.
124101
+ // Retyping it as a text expression makes it legal paragraph content.
124102
+ if (needsBlock && !isBlockResult(hChildren)) {
124103
+ const inline = { ...expressionNode, type: 'mdxTextExpression' };
124104
+ parent.children.splice(index, 1, wrapInParagraph(inline));
124105
+ }
123877
124106
  }
123878
124107
  else {
123879
- parent.children.splice(index, 1, createTextNode(result, position));
124108
+ parent.children.splice(index, 1, placeText(createTextNode(result, position), needsBlock));
123880
124109
  }
123881
124110
  }
123882
124111
  catch (_error) {
@@ -123884,7 +124113,8 @@ const evaluateExpressions = ({ components, variables } = {}) => (tree, file) =>
123884
124113
  // parser treats contents as code, so backslash escapes aren't applied;
123885
124114
  // restore them here so e.g. `{\!}` round-trips to `{!}`.
123886
124115
  const processed = expression.replace(/\\([!-/:-@[-`{-~])/g, '$1');
123887
- parent.children.splice(index, 1, { type: 'text', value: `{${processed}}`, position });
124116
+ const literal = { type: 'text', value: `{${processed}}`, position };
124117
+ parent.children.splice(index, 1, placeText(literal, needsBlock));
123888
124118
  }
123889
124119
  });
123890
124120
  // A text expression is parsed inside a paragraph, but its result can be block content: a
@@ -123985,6 +124215,111 @@ const generateSlugForHeadings = () => (tree) => {
123985
124215
  };
123986
124216
  /* harmony default export */ const heading_slugs = (generateSlugForHeadings);
123987
124217
 
124218
+ ;// ./processor/transform/mdxish/images-to-jsx.ts
124219
+ /* unused harmony import specifier */ var images_to_jsx_toMarkdown;
124220
+ /* unused harmony import specifier */ var images_to_jsx_visit;
124221
+ /* unused harmony import specifier */ var images_to_jsx_NodeTypes;
124222
+ /* unused harmony import specifier */ var images_to_jsx_INLINE_ONLY_PARENT_TYPES;
124223
+ /* unused harmony import specifier */ var images_to_jsx_toAttributes;
124224
+
124225
+
124226
+
124227
+
124228
+
124229
+ const IMAGE_ATTRS = (/* unused pure expression or super */ null && (['align', 'alt', 'border', 'caption', 'className', 'height', 'lazy', 'src', 'title', 'width']));
124230
+ /** The three attributes markdown's `![alt](src "title")` can carry. Anything else forces JSX. */
124231
+ const PLAIN_IMAGE_ATTRS = (/* unused pure expression or super */ null && (['alt', 'src', 'title']));
124232
+ const EMOJI_COLONS = /^:(.*):$/;
124233
+ const hasExtra = (attributes) => attributes.some(attr => !PLAIN_IMAGE_ATTRS.includes(attr.name));
124234
+ const toImageJsx = (attributes, children = []) => ({
124235
+ type: 'mdxJsxFlowElement',
124236
+ name: 'Image',
124237
+ attributes,
124238
+ children,
124239
+ });
124240
+ /**
124241
+ * An `image` is phrasing content, but the nodes it replaces here (`image-block`, and a plain
124242
+ * `[block:image]`) sit where flow content belongs. `mdast-util-to-markdown` picks a block separator
124243
+ * from the two node types around it and has no rule for phrasing-next-to-flow, so it emits none and
124244
+ * glues the image to whatever follows (`![a](src)# Heading`), which then cascades through the rest
124245
+ * of the document. Wrapping restores a block for it to join against.
124246
+ */
124247
+ const placeImage = (parent, index, image) => {
124248
+ const wrapped = { type: 'paragraph', children: [image] };
124249
+ parent.children[index] = images_to_jsx_INLINE_ONLY_PARENT_TYPES.has(parent.type) ? image : wrapped;
124250
+ };
124251
+ /**
124252
+ * Serializes the three image shapes a parsed document carries. An image that picked up readme
124253
+ * attributes has no markdown spelling left and goes out as `<Image>`, a plain one stays
124254
+ * `![alt](src)`.
124255
+ *
124256
+ * Order matters: `figure` unwraps into the `image` its caption belongs to, so it runs first.
124257
+ */
124258
+ const imagesToJsx = () => tree => {
124259
+ images_to_jsx_visit(tree, images_to_jsx_NodeTypes.figure, (node, index, parent) => {
124260
+ if (!parent || index === undefined)
124261
+ return;
124262
+ const [image, caption] = node.children;
124263
+ const { align, className, width } = image.data.hProperties;
124264
+ parent.children[index] = toImageJsx(images_to_jsx_toAttributes({ ...image, align, width, ...(className === 'border' && { border: true }), src: image.src || image.url }, IMAGE_ATTRS),
124265
+ // The caption stays a child rather than a pre-serialized `caption` attribute, so readme nodes
124266
+ // inside it (emoji, variables, glossary) reach their own handlers instead of the bare
124267
+ // `toMarkdown` in `compatibility.figureToImageBlock`, which throws on them.
124268
+ caption.children);
124269
+ });
124270
+ images_to_jsx_visit(tree, 'image', (n, index, parent) => {
124271
+ const node = n;
124272
+ if (!parent || index === undefined)
124273
+ return undefined;
124274
+ const hProperties = node.data?.hProperties;
124275
+ // A `:joy:`-style shortcode round-trips as a gemoji rather than the image it parsed into.
124276
+ if (hProperties?.className === 'emoji' && node.title) {
124277
+ const emoji = {
124278
+ type: images_to_jsx_NodeTypes.emoji,
124279
+ name: node.title.replace(EMOJI_COLONS, '$1'),
124280
+ value: node.title,
124281
+ };
124282
+ parent.children[index] = emoji;
124283
+ return undefined;
124284
+ }
124285
+ if (hProperties) {
124286
+ const attributes = images_to_jsx_toAttributes({ ...node, ...hProperties, src: node.url }, IMAGE_ATTRS);
124287
+ if (hasExtra(attributes)) {
124288
+ parent.children[index] = toImageJsx(attributes);
124289
+ return undefined;
124290
+ }
124291
+ }
124292
+ // An attribute-less `[block:image]` parses straight to an `image` in a flow slot, so it needs
124293
+ // the same wrap. Editor images always arrive inside a paragraph and are left alone.
124294
+ if (images_to_jsx_INLINE_ONLY_PARENT_TYPES.has(parent.type))
124295
+ return undefined;
124296
+ placeImage(parent, index, node);
124297
+ // Step over the paragraph just created, or the visitor walks back into the same image.
124298
+ return [(/* inlined export .SKIP */"skip"), index + 1];
124299
+ });
124300
+ images_to_jsx_visit(tree, images_to_jsx_NodeTypes.imageBlock, (node, index, parent) => {
124301
+ if (!parent || index === undefined)
124302
+ return;
124303
+ // An image-block keeps its caption as children, so it has to be re-serialized back into the
124304
+ // `caption` attribute before the node is replaced.
124305
+ const captionChildren = node.children ?? [];
124306
+ const caption = captionChildren.length ? images_to_jsx_toMarkdown({ type: 'root', children: captionChildren }).trim() : '';
124307
+ const attributes = images_to_jsx_toAttributes({ ...node, ...node.data.hProperties, ...(caption && { caption }) }, IMAGE_ATTRS);
124308
+ if (hasExtra(attributes)) {
124309
+ parent.children[index] = toImageJsx(attributes);
124310
+ return;
124311
+ }
124312
+ placeImage(parent, index, {
124313
+ type: 'image',
124314
+ url: node.src,
124315
+ ...(node.title && { title: node.title }),
124316
+ ...(node.alt && { alt: node.alt }),
124317
+ });
124318
+ });
124319
+ return tree;
124320
+ };
124321
+ /* harmony default export */ const images_to_jsx = ((/* unused pure expression or super */ null && (imagesToJsx)));
124322
+
123988
124323
  // EXTERNAL MODULE: ./node_modules/@readme/variable/dist/index.js
123989
124324
  var variable_dist = __webpack_require__(4355);
123990
124325
  var variable_dist_default = /*#__PURE__*/__webpack_require__.n(variable_dist);
@@ -127479,97 +127814,6 @@ const variablesCodeResolver = ({ variables } = {}) => tree => {
127479
127814
  };
127480
127815
  /* harmony default export */ const variables_code = (variablesCodeResolver);
127481
127816
 
127482
- ;// ./processor/transform/mdxish/variables-text.ts
127483
-
127484
-
127485
- /**
127486
- * Matches {user.<field>} patterns:
127487
- * - {user.name}
127488
- * - {user.email}
127489
- * - {user['field']}
127490
- * - {user["field"]}
127491
- *
127492
- * Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
127493
- */
127494
- const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
127495
- function makeVariableNode(varName, rawValue) {
127496
- return {
127497
- type: NodeTypes.variable,
127498
- data: {
127499
- hName: 'Variable',
127500
- hProperties: { name: varName },
127501
- },
127502
- value: rawValue,
127503
- };
127504
- }
127505
- /**
127506
- * A remark plugin that parses {user.<field>} patterns from text nodes and
127507
- * mdx expression nodes, creating Variable nodes for runtime resolution.
127508
- *
127509
- * Handles:
127510
- * - `text` nodes: when safeMode is true or after expression evaluation
127511
- * - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
127512
- * - `mdxFlowExpression` nodes: when {user.*} appears on its own line (e.g. inside JSX table cells)
127513
- *
127514
- * Supports any user field: name, email, email_verified, exp, iat, etc.
127515
- */
127516
- function visitExpressionNode(node, index, parent) {
127517
- if (index === undefined || !parent)
127518
- return;
127519
- const wrapped = `{${(node.value ?? '').trim()}}`;
127520
- const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
127521
- if (matches.length !== 1)
127522
- return;
127523
- const varName = matches[0][1] || matches[0][2];
127524
- parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
127525
- }
127526
- const variablesTextTransformer = () => tree => {
127527
- visit(tree, 'mdxTextExpression', (node, index, parent) => {
127528
- visitExpressionNode(node, index, parent);
127529
- });
127530
- visit(tree, 'mdxFlowExpression', (node, index, parent) => {
127531
- visitExpressionNode(node, index, parent);
127532
- });
127533
- visit(tree, 'text', (node, index, parent) => {
127534
- if (index === undefined || !parent)
127535
- return;
127536
- // Skip if inside inline code
127537
- if (parent.type === 'inlineCode')
127538
- return;
127539
- const text = node.value;
127540
- if (typeof text !== 'string' || !text.trim())
127541
- return;
127542
- if (!text.includes('{user.') && !text.includes('{user['))
127543
- return;
127544
- const matches = [...text.matchAll(USER_VAR_REGEX)];
127545
- if (matches.length === 0)
127546
- return;
127547
- const parts = [];
127548
- let lastIndex = 0;
127549
- matches.forEach(match => {
127550
- const matchIndex = match.index ?? 0;
127551
- // Add text before the match
127552
- if (matchIndex > lastIndex) {
127553
- parts.push({ type: 'text', value: text.slice(lastIndex, matchIndex) });
127554
- }
127555
- // Extract variable name from either capture group (dot or bracket notation)
127556
- const varName = match[1] || match[2];
127557
- parts.push(makeVariableNode(varName, match[0]));
127558
- lastIndex = matchIndex + match[0].length;
127559
- });
127560
- // Add remaining text after last match
127561
- if (lastIndex < text.length) {
127562
- parts.push({ type: 'text', value: text.slice(lastIndex) });
127563
- }
127564
- // Replace node with parts
127565
- if (parts.length > 1 || (parts.length === 1 && parts[0].type !== 'text')) {
127566
- parent.children.splice(index, 1, ...parts);
127567
- }
127568
- });
127569
- return tree;
127570
- };
127571
- /* harmony default export */ const variables_text = (variablesTextTransformer);
127572
-
127573
127817
  ;// ./lib/utils/mdxish/mdxish-load-components.ts
127574
127818
 
127575
127819
 
@@ -127603,7 +127847,9 @@ function loadComponents() {
127603
127847
  }
127604
127848
 
127605
127849
  ;// ./lib/mdxish.ts
127850
+ /* unused harmony import specifier */ var mdxish_mdxExpressionToMarkdown;
127606
127851
  /* unused harmony import specifier */ var mdxish_mdxJsxToMarkdown;
127852
+ /* unused harmony import specifier */ var mdxish_mdxjsEsmToMarkdown;
127607
127853
  /* unused harmony import specifier */ var mdxish_remarkGfm;
127608
127854
  /* unused harmony import specifier */ var mdxish_remarkStringify;
127609
127855
  /* unused harmony import specifier */ var mdxish_unified;
@@ -127611,7 +127857,13 @@ function loadComponents() {
127611
127857
  /* unused harmony import specifier */ var mdxish_DEFAULT_BULLET;
127612
127858
  /* unused harmony import specifier */ var mdxish_mdxishAnchorToJsx;
127613
127859
  /* unused harmony import specifier */ var mdxish_mdxishCalloutToJsx;
127860
+ /* unused harmony import specifier */ var mdxishImagesToJsx;
127614
127861
  /* unused harmony import specifier */ var mdxish_mdxishTablesToJsx;
127862
+ /* unused harmony import specifier */ var unwrapPins;
127863
+
127864
+
127865
+
127866
+
127615
127867
 
127616
127868
 
127617
127869
 
@@ -127742,35 +127994,43 @@ function mdxishAstProcessor(mdContent, opts = {}) {
127742
127994
  };
127743
127995
  }
127744
127996
  /**
127745
- * Registers the mdx-jsx serialization extension so remark-stringify
127746
- * can convert JSX nodes (e.g. `<Table>`) to markdown.
127997
+ * Registers serialization for the node types remark-stringify can't write on its own:
127998
+ * JSX elements (e.g. `<Table>`), MDX expressions, and ESM exports.
127747
127999
  */
127748
- function mdxJsxStringify() {
128000
+ function mdxStringifyExtensions() {
127749
128001
  const data = this.data();
127750
128002
  const extensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = []);
127751
- extensions.push({ extensions: [mdxish_mdxJsxToMarkdown()] });
128003
+ extensions.push({ extensions: [mdxish_mdxJsxToMarkdown(), mdxish_mdxExpressionToMarkdown(), mdxish_mdxjsEsmToMarkdown()] });
127752
128004
  }
128005
+ const stringifyOptions = (/* unused pure expression or super */ null && ({
128006
+ bullet: mdxish_DEFAULT_BULLET,
128007
+ emphasis: '_',
128008
+ // Escape literal braces in text so they don't parse as (often
128009
+ // unterminated) MDX expressions on the next round trip.
128010
+ unsafe: [
128011
+ { character: '{', inConstruct: 'phrasing' },
128012
+ { character: '}', inConstruct: 'phrasing' },
128013
+ ],
128014
+ }));
127753
128015
  /**
127754
128016
  * Serializes an Mdast back into a markdown string.
127755
128017
  */
127756
128018
  function mdxishMdastToMd(mdast) {
127757
128019
  const processor = mdxish_unified()
127758
128020
  .use(mdxish_remarkGfm)
128021
+ // Readme nodes with no markdown spelling go out as JSX, the same tags mdxish re-parses.
127759
128022
  .use(mdxish_mdxishCalloutToJsx)
127760
128023
  .use(mdxish_mdxishTablesToJsx)
127761
128024
  .use(mdxish_mdxishAnchorToJsx)
128025
+ // The rest only a PARSER tree carries.
128026
+ // A `sidebar: true` block parses into an `rdme-pin` wrapper the dialect can't spell.
128027
+ .use(unwrapPins)
128028
+ // Figures, image blocks, and images that picked up readme attributes while parsing.
128029
+ .use(mdxishImagesToJsx)
128030
+ // Handlers for the readme nodes that stay themselves (variables, emoji, html-blocks, lists).
127762
128031
  .use(mdxish_mdxishCompilers)
127763
- .use(mdxJsxStringify)
127764
- .use(mdxish_remarkStringify, {
127765
- bullet: mdxish_DEFAULT_BULLET,
127766
- emphasis: '_',
127767
- // Escape literal braces in text so they don't parse as (often
127768
- // unterminated) MDX expressions on the next round trip.
127769
- unsafe: [
127770
- { character: '{', inConstruct: 'phrasing' },
127771
- { character: '}', inConstruct: 'phrasing' },
127772
- ],
127773
- });
128032
+ .use(mdxStringifyExtensions)
128033
+ .use(mdxish_remarkStringify, stringifyOptions);
127774
128034
  return processor.stringify(processor.runSync(mdast));
127775
128035
  }
127776
128036
  /**
@@ -128884,7 +129144,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
128884
129144
  /******/ // startup
128885
129145
  /******/ // Load entry module and return exports
128886
129146
  /******/ // This entry module used 'module' so it can't be inlined
128887
- /******/ let __webpack_exports__ = __webpack_require__(8691);
129147
+ /******/ let __webpack_exports__ = __webpack_require__(5072);
128888
129148
  /******/ module.exports = __webpack_exports__;
128889
129149
  /******/
128890
129150
  /******/ })()