@readme/markdown 13.3.0 → 13.4.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/dist/main.js CHANGED
@@ -52928,6 +52928,12 @@ const stripCommentsTransformer = () => {
52928
52928
 
52929
52929
 
52930
52930
  const STRIP_TAGS = ['script', 'style'];
52931
+ /** Valid JS identifier: starts with $, _, or a letter; followed by $, _, letters, digits, etc. */
52932
+ const JS_IDENTIFIER_RE = /^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\u200C\u200D]*$/u;
52933
+ /** Format a variable key as MDX syntax, using bracket notation for non-identifier keys (e.g. hyphens). */
52934
+ function toMdxVariableSyntax(key) {
52935
+ return JS_IDENTIFIER_RE.test(key) ? `{user.${key}}` : `{user["${key}"]}`;
52936
+ }
52931
52937
  /**
52932
52938
  * Extract variable key from MDX expression AST (e.g., {user.name} → 'name')
52933
52939
  * Uses ESTree AST inspection, matching the approach in processor/transform/variables.ts
@@ -52986,8 +52992,9 @@ function plain_one(node, opts) {
52986
52992
  case 'variable':
52987
52993
  case 'Variable': {
52988
52994
  const key = node.properties.name.toString();
52989
- if (opts.preserveVariableSyntax)
52990
- return `{user.${key}}`;
52995
+ if (opts.preserveVariableSyntax) {
52996
+ return node.properties.isLegacy ? `<<${key}>>` : toMdxVariableSyntax(key);
52997
+ }
52991
52998
  const val = 'variables' in opts && opts.variables[key];
52992
52999
  return val || key;
52993
53000
  }
@@ -53012,7 +53019,7 @@ function plain_one(node, opts) {
53012
53019
  const key = extractMdxVariableKey(node);
53013
53020
  if (key) {
53014
53021
  if (opts.preserveVariableSyntax)
53015
- return `{user.${key}}`;
53022
+ return toMdxVariableSyntax(key);
53016
53023
  return ('variables' in opts && opts.variables[key]) || key;
53017
53024
  }
53018
53025
  }
@@ -94297,15 +94304,13 @@ function preprocessJSXExpressions(content, context = {}) {
94297
94304
  let processed = protectHTMLBlockContent(content);
94298
94305
  // Step 1: Protect code blocks and inline code
94299
94306
  const { protectedCode, protectedContent } = protectCodeBlocks(processed);
94300
- // Step 2: Remove JSX comments
94301
- processed = removeJSXComments(protectedContent);
94302
- // Step 3: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
94307
+ // Step 2: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
94303
94308
  // For inline expressions, we use a library to parse the expression & evaluate it later
94304
94309
  // For attribute expressions, it was difficult to use a library to parse them, so do it manually
94305
- processed = evaluateAttributeExpressions(processed, context, protectedCode);
94306
- // Step 4: Escape unbalanced braces to prevent MDX expression parsing errors
94310
+ processed = evaluateAttributeExpressions(protectedContent, context, protectedCode);
94311
+ // Step 3: Escape unbalanced braces to prevent MDX expression parsing errors
94307
94312
  processed = escapeUnbalancedBraces(processed);
94308
- // Step 5: Restore protected code blocks
94313
+ // Step 4: Restore protected code blocks
94309
94314
  processed = restoreCodeBlocks(processed, protectedCode);
94310
94315
  return processed;
94311
94316
  }
@@ -96351,13 +96356,38 @@ const variablesCodeResolver = ({ variables } = {}) => tree => {
96351
96356
  * Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
96352
96357
  */
96353
96358
  const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
96359
+ function makeVariableNode(varName, rawValue) {
96360
+ return {
96361
+ type: NodeTypes.variable,
96362
+ data: {
96363
+ hName: 'Variable',
96364
+ hProperties: { name: varName },
96365
+ },
96366
+ value: rawValue,
96367
+ };
96368
+ }
96354
96369
  /**
96355
- * A remark plugin that parses {user.<field>} patterns from text nodes
96356
- * without requiring remarkMdx. Creates Variable nodes for runtime resolution.
96370
+ * A remark plugin that parses {user.<field>} patterns from text nodes and
96371
+ * mdxTextExpression nodes, creating Variable nodes for runtime resolution.
96372
+ *
96373
+ * Handles both:
96374
+ * - `text` nodes: when safeMode is true or after expression evaluation
96375
+ * - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
96357
96376
  *
96358
96377
  * Supports any user field: name, email, email_verified, exp, iat, etc.
96359
96378
  */
96360
96379
  const variablesTextTransformer = () => tree => {
96380
+ // Handle mdxTextExpression nodes (e.g. {user.name} parsed by mdxExpression)
96381
+ visit(tree, 'mdxTextExpression', (node, index, parent) => {
96382
+ if (index === undefined || !parent)
96383
+ return;
96384
+ const wrapped = `{${(node.value ?? '').trim()}}`; // Wrap the expression value in {} to match the USER_VAR_REGEX pattern
96385
+ const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
96386
+ if (matches.length !== 1)
96387
+ return;
96388
+ const varName = matches[0][1] || matches[0][2];
96389
+ parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
96390
+ });
96361
96391
  visit(tree, 'text', (node, index, parent) => {
96362
96392
  if (index === undefined || !parent)
96363
96393
  return;
@@ -96382,15 +96412,7 @@ const variablesTextTransformer = () => tree => {
96382
96412
  }
96383
96413
  // Extract variable name from either capture group (dot or bracket notation)
96384
96414
  const varName = match[1] || match[2];
96385
- // Create Variable node
96386
- parts.push({
96387
- type: NodeTypes.variable,
96388
- data: {
96389
- hName: 'Variable',
96390
- hProperties: { name: varName },
96391
- },
96392
- value: match[0],
96393
- });
96415
+ parts.push(makeVariableNode(varName, match[0]));
96394
96416
  lastIndex = matchIndex + match[0].length;
96395
96417
  });
96396
96418
  // Add remaining text after last match
@@ -97486,6 +97508,7 @@ function loadComponents() {
97486
97508
 
97487
97509
 
97488
97510
 
97511
+
97489
97512
 
97490
97513
 
97491
97514
  const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
@@ -97546,8 +97569,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
97546
97569
  .use(mdxish_tables)
97547
97570
  .use(mdxish_html_blocks)
97548
97571
  .use(newEditorTypes ? mdxish_jsx_to_mdast : undefined) // Convert JSX elements to MDAST types
97549
- .use(safeMode ? undefined : evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
97550
- .use(variables_text) // Parse {user.*} patterns from text
97572
+ .use(variables_text) // Parse {user.*} patterns from text nodes
97551
97573
  .use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
97552
97574
  .use(remarkGfm);
97553
97575
  return {
@@ -97581,13 +97603,18 @@ function mdxishMdastToMd(mdast) {
97581
97603
  * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
97582
97604
  */
97583
97605
  function mdxish(mdContent, opts = {}) {
97584
- const { components: userComponents = {}, variables } = opts;
97606
+ const { components: userComponents = {}, jsxContext = {}, safeMode = false, variables } = opts;
97585
97607
  const components = {
97586
97608
  ...loadComponents(),
97587
97609
  ...userComponents,
97588
97610
  };
97589
- const { processor, parserReadyContent } = mdxishAstProcessor(mdContent, opts);
97611
+ // Remove JSX comments before processing (protect code blocks first)
97612
+ const { protectedCode, protectedContent } = protectCodeBlocks(mdContent);
97613
+ const withoutComments = removeJSXComments(protectedContent);
97614
+ const contentWithoutComments = restoreCodeBlocks(withoutComments, protectedCode);
97615
+ const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
97590
97616
  processor
97617
+ .use(safeMode ? undefined : evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
97591
97618
  .use(remarkBreaks)
97592
97619
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
97593
97620
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
@@ -98146,6 +98173,7 @@ function restoreMagicBlocks(replaced, blocks) {
98146
98173
 
98147
98174
 
98148
98175
 
98176
+
98149
98177
  /**
98150
98178
  * Removes Markdown and MDX comments.
98151
98179
  */
@@ -98166,6 +98194,7 @@ async function stripComments(doc, { mdx, mdxish } = {}) {
98166
98194
  .use(normalize_malformed_md_syntax)
98167
98195
  .use(mdx ? remarkMdx : undefined)
98168
98196
  .use(stripCommentsTransformer)
98197
+ .use(remarkGfm)
98169
98198
  .use(remarkStringify, mdx
98170
98199
  ? {}
98171
98200
  : {
package/dist/main.node.js CHANGED
@@ -73132,6 +73132,12 @@ const stripCommentsTransformer = () => {
73132
73132
 
73133
73133
 
73134
73134
  const STRIP_TAGS = ['script', 'style'];
73135
+ /** Valid JS identifier: starts with $, _, or a letter; followed by $, _, letters, digits, etc. */
73136
+ const JS_IDENTIFIER_RE = /^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\u200C\u200D]*$/u;
73137
+ /** Format a variable key as MDX syntax, using bracket notation for non-identifier keys (e.g. hyphens). */
73138
+ function toMdxVariableSyntax(key) {
73139
+ return JS_IDENTIFIER_RE.test(key) ? `{user.${key}}` : `{user["${key}"]}`;
73140
+ }
73135
73141
  /**
73136
73142
  * Extract variable key from MDX expression AST (e.g., {user.name} → 'name')
73137
73143
  * Uses ESTree AST inspection, matching the approach in processor/transform/variables.ts
@@ -73190,8 +73196,9 @@ function plain_one(node, opts) {
73190
73196
  case 'variable':
73191
73197
  case 'Variable': {
73192
73198
  const key = node.properties.name.toString();
73193
- if (opts.preserveVariableSyntax)
73194
- return `{user.${key}}`;
73199
+ if (opts.preserveVariableSyntax) {
73200
+ return node.properties.isLegacy ? `<<${key}>>` : toMdxVariableSyntax(key);
73201
+ }
73195
73202
  const val = 'variables' in opts && opts.variables[key];
73196
73203
  return val || key;
73197
73204
  }
@@ -73216,7 +73223,7 @@ function plain_one(node, opts) {
73216
73223
  const key = extractMdxVariableKey(node);
73217
73224
  if (key) {
73218
73225
  if (opts.preserveVariableSyntax)
73219
- return `{user.${key}}`;
73226
+ return toMdxVariableSyntax(key);
73220
73227
  return ('variables' in opts && opts.variables[key]) || key;
73221
73228
  }
73222
73229
  }
@@ -114501,15 +114508,13 @@ function preprocessJSXExpressions(content, context = {}) {
114501
114508
  let processed = protectHTMLBlockContent(content);
114502
114509
  // Step 1: Protect code blocks and inline code
114503
114510
  const { protectedCode, protectedContent } = protectCodeBlocks(processed);
114504
- // Step 2: Remove JSX comments
114505
- processed = removeJSXComments(protectedContent);
114506
- // Step 3: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
114511
+ // Step 2: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
114507
114512
  // For inline expressions, we use a library to parse the expression & evaluate it later
114508
114513
  // For attribute expressions, it was difficult to use a library to parse them, so do it manually
114509
- processed = evaluateAttributeExpressions(processed, context, protectedCode);
114510
- // Step 4: Escape unbalanced braces to prevent MDX expression parsing errors
114514
+ processed = evaluateAttributeExpressions(protectedContent, context, protectedCode);
114515
+ // Step 3: Escape unbalanced braces to prevent MDX expression parsing errors
114511
114516
  processed = escapeUnbalancedBraces(processed);
114512
- // Step 5: Restore protected code blocks
114517
+ // Step 4: Restore protected code blocks
114513
114518
  processed = restoreCodeBlocks(processed, protectedCode);
114514
114519
  return processed;
114515
114520
  }
@@ -116555,13 +116560,38 @@ const variablesCodeResolver = ({ variables } = {}) => tree => {
116555
116560
  * Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
116556
116561
  */
116557
116562
  const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
116563
+ function makeVariableNode(varName, rawValue) {
116564
+ return {
116565
+ type: NodeTypes.variable,
116566
+ data: {
116567
+ hName: 'Variable',
116568
+ hProperties: { name: varName },
116569
+ },
116570
+ value: rawValue,
116571
+ };
116572
+ }
116558
116573
  /**
116559
- * A remark plugin that parses {user.<field>} patterns from text nodes
116560
- * without requiring remarkMdx. Creates Variable nodes for runtime resolution.
116574
+ * A remark plugin that parses {user.<field>} patterns from text nodes and
116575
+ * mdxTextExpression nodes, creating Variable nodes for runtime resolution.
116576
+ *
116577
+ * Handles both:
116578
+ * - `text` nodes: when safeMode is true or after expression evaluation
116579
+ * - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
116561
116580
  *
116562
116581
  * Supports any user field: name, email, email_verified, exp, iat, etc.
116563
116582
  */
116564
116583
  const variablesTextTransformer = () => tree => {
116584
+ // Handle mdxTextExpression nodes (e.g. {user.name} parsed by mdxExpression)
116585
+ visit(tree, 'mdxTextExpression', (node, index, parent) => {
116586
+ if (index === undefined || !parent)
116587
+ return;
116588
+ const wrapped = `{${(node.value ?? '').trim()}}`; // Wrap the expression value in {} to match the USER_VAR_REGEX pattern
116589
+ const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
116590
+ if (matches.length !== 1)
116591
+ return;
116592
+ const varName = matches[0][1] || matches[0][2];
116593
+ parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
116594
+ });
116565
116595
  visit(tree, 'text', (node, index, parent) => {
116566
116596
  if (index === undefined || !parent)
116567
116597
  return;
@@ -116586,15 +116616,7 @@ const variablesTextTransformer = () => tree => {
116586
116616
  }
116587
116617
  // Extract variable name from either capture group (dot or bracket notation)
116588
116618
  const varName = match[1] || match[2];
116589
- // Create Variable node
116590
- parts.push({
116591
- type: NodeTypes.variable,
116592
- data: {
116593
- hName: 'Variable',
116594
- hProperties: { name: varName },
116595
- },
116596
- value: match[0],
116597
- });
116619
+ parts.push(makeVariableNode(varName, match[0]));
116598
116620
  lastIndex = matchIndex + match[0].length;
116599
116621
  });
116600
116622
  // Add remaining text after last match
@@ -117690,6 +117712,7 @@ function loadComponents() {
117690
117712
 
117691
117713
 
117692
117714
 
117715
+
117693
117716
 
117694
117717
 
117695
117718
  const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
@@ -117750,8 +117773,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
117750
117773
  .use(mdxish_tables)
117751
117774
  .use(mdxish_html_blocks)
117752
117775
  .use(newEditorTypes ? mdxish_jsx_to_mdast : undefined) // Convert JSX elements to MDAST types
117753
- .use(safeMode ? undefined : evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
117754
- .use(variables_text) // Parse {user.*} patterns from text
117776
+ .use(variables_text) // Parse {user.*} patterns from text nodes
117755
117777
  .use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
117756
117778
  .use(remarkGfm);
117757
117779
  return {
@@ -117785,13 +117807,18 @@ function mdxishMdastToMd(mdast) {
117785
117807
  * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
117786
117808
  */
117787
117809
  function mdxish(mdContent, opts = {}) {
117788
- const { components: userComponents = {}, variables } = opts;
117810
+ const { components: userComponents = {}, jsxContext = {}, safeMode = false, variables } = opts;
117789
117811
  const components = {
117790
117812
  ...loadComponents(),
117791
117813
  ...userComponents,
117792
117814
  };
117793
- const { processor, parserReadyContent } = mdxishAstProcessor(mdContent, opts);
117815
+ // Remove JSX comments before processing (protect code blocks first)
117816
+ const { protectedCode, protectedContent } = protectCodeBlocks(mdContent);
117817
+ const withoutComments = removeJSXComments(protectedContent);
117818
+ const contentWithoutComments = restoreCodeBlocks(withoutComments, protectedCode);
117819
+ const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
117794
117820
  processor
117821
+ .use(safeMode ? undefined : evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
117795
117822
  .use(remarkBreaks)
117796
117823
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
117797
117824
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
@@ -118350,6 +118377,7 @@ function restoreMagicBlocks(replaced, blocks) {
118350
118377
 
118351
118378
 
118352
118379
 
118380
+
118353
118381
  /**
118354
118382
  * Removes Markdown and MDX comments.
118355
118383
  */
@@ -118370,6 +118398,7 @@ async function stripComments(doc, { mdx, mdxish } = {}) {
118370
118398
  .use(normalize_malformed_md_syntax)
118371
118399
  .use(mdx ? remarkMdx : undefined)
118372
118400
  .use(stripCommentsTransformer)
118401
+ .use(remarkGfm)
118373
118402
  .use(remarkStringify, mdx
118374
118403
  ? {}
118375
118404
  : {