@readme/markdown 12.1.1 → 12.2.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.
@@ -1,8 +1,9 @@
1
1
  interface Opts {
2
2
  mdx?: boolean;
3
+ mdxish?: boolean;
3
4
  }
4
5
  /**
5
6
  * Removes Markdown and MDX comments.
6
7
  */
7
- declare function stripComments(doc: string, { mdx }?: Opts): Promise<string>;
8
+ declare function stripComments(doc: string, { mdx, mdxish }?: Opts): Promise<string>;
8
9
  export default stripComments;
package/dist/main.js CHANGED
@@ -52923,6 +52923,37 @@ const stripCommentsTransformer = () => {
52923
52923
 
52924
52924
 
52925
52925
  const STRIP_TAGS = ['script', 'style'];
52926
+ /**
52927
+ * Extract variable key from MDX expression AST (e.g., {user.name} → 'name')
52928
+ * Uses ESTree AST inspection, matching the approach in processor/transform/variables.ts
52929
+ *
52930
+ * @see https://github.com/syntax-tree/mdast-util-mdx-expression - MdxTextExpressionHast type
52931
+ * @see https://github.com/estree/estree/blob/master/es5.md - ESTree spec for expression types
52932
+ */
52933
+ function extractMdxVariableKey(node) {
52934
+ const estree = node.data?.estree;
52935
+ if (!estree || estree.type !== 'Program' || estree.body.length === 0)
52936
+ return undefined;
52937
+ const statement = estree.body[0];
52938
+ if (statement.type !== 'ExpressionStatement')
52939
+ return undefined;
52940
+ const expr = statement.expression;
52941
+ if (expr.type !== 'MemberExpression')
52942
+ return undefined;
52943
+ const memberExpr = expr;
52944
+ const obj = memberExpr.object;
52945
+ if (obj.type !== 'Identifier' || obj.name !== 'user')
52946
+ return undefined;
52947
+ const prop = memberExpr.property;
52948
+ if (prop.type === 'Identifier') {
52949
+ return prop.name;
52950
+ }
52951
+ if (prop.type === 'Literal') {
52952
+ const val = prop.value;
52953
+ return typeof val === 'string' ? val : undefined;
52954
+ }
52955
+ return undefined;
52956
+ }
52926
52957
  function plain_one(node, opts) {
52927
52958
  if (node.type === 'comment')
52928
52959
  return '';
@@ -52946,6 +52977,8 @@ function plain_one(node, opts) {
52946
52977
  const body = children ? plain_all({ type: 'root', children }, opts) : '';
52947
52978
  return [icon, ' ', title, title && body && ': ', body].filter(Boolean).join('');
52948
52979
  }
52980
+ // 'variable' (lowercase) comes from mdxish() after rehypeRaw normalizes HTML tag names
52981
+ case 'variable':
52949
52982
  case 'Variable': {
52950
52983
  const key = node.properties.name.toString();
52951
52984
  const val = 'variables' in opts && opts.variables[key];
@@ -52967,6 +53000,13 @@ function plain_one(node, opts) {
52967
53000
  break;
52968
53001
  }
52969
53002
  }
53003
+ // Handle MDX expressions like {user.name}
53004
+ if (node.type === 'mdxTextExpression') {
53005
+ const key = extractMdxVariableKey(node);
53006
+ if (key) {
53007
+ return ('variables' in opts && opts.variables[key]) || key;
53008
+ }
53009
+ }
52970
53010
  if ('value' in node) {
52971
53011
  return node.value;
52972
53012
  }
@@ -86628,11 +86668,27 @@ const getDepth = (el) => {
86628
86668
  return Infinity;
86629
86669
  return parseInt(el.tagName?.match(/^h(\d)/)[1], 10);
86630
86670
  };
86671
+ /**
86672
+ * Flatten Variables into a simple key-value map for static resolution.
86673
+ * Merges user values with defaults (user values take precedence).
86674
+ */
86675
+ const flattenVariables = (variables) => {
86676
+ if (!variables)
86677
+ return {};
86678
+ return {
86679
+ ...variables.user,
86680
+ ...Object.fromEntries((variables.defaults || []).filter(d => !(d.name in variables.user)).map(d => [d.name, d.default])),
86681
+ };
86682
+ };
86631
86683
  /*
86632
86684
  * `tocToHast` consumes the list generated by `rehypeToc` and produces a hast
86633
86685
  * of nested lists to be rendered as a table of contents.
86686
+ *
86687
+ * @param headings - The list of heading elements to render
86688
+ * @param variables - Optional user variables for resolving Variable nodes in headings
86634
86689
  */
86635
- const tocToHast = (headings = []) => {
86690
+ const tocToHast = (headings = [], variables) => {
86691
+ const flatVars = flattenVariables(variables);
86636
86692
  const headingDepths = headings.map(getDepth);
86637
86693
  const min = Math.min(...headingDepths);
86638
86694
  const ast = hastscript_lib_h('ul');
@@ -86650,7 +86706,7 @@ const tocToHast = (headings = []) => {
86650
86706
  stack.pop();
86651
86707
  }
86652
86708
  if (heading.properties) {
86653
- const content = lib_plain({ type: 'root', children: heading.children });
86709
+ const content = lib_plain({ type: 'root', children: heading.children }, { variables: flatVars });
86654
86710
  stack[stack.length - 1].children.push(hastscript_lib_h('li', null, hastscript_lib_h('a', { href: `#${heading.properties.id}` }, content)));
86655
86711
  }
86656
86712
  });
@@ -86660,8 +86716,12 @@ const tocToHast = (headings = []) => {
86660
86716
  * `tocHastToMdx` is a utility for combining `TocList`s of a root document and
86661
86717
  * any child components it may have. Once combined it will generate a markdown
86662
86718
  * doc representing a table of contents.
86719
+ *
86720
+ * @param toc - The list of TOC elements
86721
+ * @param components - Custom components that may contain headings
86722
+ * @param variables - Optional user variables for resolving Variable nodes in headings
86663
86723
  */
86664
- const tocHastToMdx = (toc, components) => {
86724
+ const tocHastToMdx = (toc, components, variables) => {
86665
86725
  if (typeof toc === 'undefined')
86666
86726
  return '';
86667
86727
  const injected = toc.flatMap(node => {
@@ -86670,7 +86730,7 @@ const tocHastToMdx = (toc, components) => {
86670
86730
  }
86671
86731
  return node;
86672
86732
  });
86673
- const tocHast = tocToHast(injected);
86733
+ const tocHast = tocToHast(injected, variables);
86674
86734
  return lib_mdx({ type: 'root', children: [tocHast] }, { hast: true });
86675
86735
  };
86676
86736
 
@@ -95497,7 +95557,7 @@ function buildRMDXModule(content, headings, tocHast, opts) {
95497
95557
  * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
95498
95558
  */
95499
95559
  const renderMdxish = (tree, opts = {}) => {
95500
- const { components: userComponents = {}, ...contextOpts } = opts;
95560
+ const { components: userComponents = {}, variables, ...contextOpts } = opts;
95501
95561
  const components = {
95502
95562
  ...loadComponents(),
95503
95563
  ...userComponents,
@@ -95506,8 +95566,8 @@ const renderMdxish = (tree, opts = {}) => {
95506
95566
  const componentsForRehype = exportComponentsForRehype(components);
95507
95567
  const processor = createRehypeReactProcessor(componentsForRehype);
95508
95568
  const content = processor.stringify(tree);
95509
- const tocHast = headings.length > 0 ? tocToHast(headings) : null;
95510
- return buildRMDXModule(content, headings, tocHast, contextOpts);
95569
+ const tocHast = headings.length > 0 ? tocToHast(headings, variables) : null;
95570
+ return buildRMDXModule(content, headings, tocHast, { ...contextOpts, variables });
95511
95571
  };
95512
95572
  /* harmony default export */ const lib_renderMdxish = (renderMdxish);
95513
95573
 
@@ -95617,7 +95677,7 @@ const run_run = (string, _opts = {}) => {
95617
95677
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
95618
95678
  const { Toc: _Toc, toc, default: Content, stylesheet, ...exports } = exec(string);
95619
95679
  let Toc;
95620
- const tocMdx = tocHastToMdx(toc, tocsByTag);
95680
+ const tocMdx = tocHastToMdx(toc, tocsByTag, variables);
95621
95681
  if (tocMdx) {
95622
95682
  const compiledToc = lib_compile(tocMdx);
95623
95683
  const tocModule = exec(compiledToc, { useMDXComponents: () => ({ p: Fragment }) });
@@ -95679,12 +95739,23 @@ const mdxishTags_tags = (doc) => {
95679
95739
 
95680
95740
 
95681
95741
 
95742
+
95743
+
95682
95744
  /**
95683
95745
  * Removes Markdown and MDX comments.
95684
95746
  */
95685
- async function stripComments(doc, { mdx } = {}) {
95747
+ async function stripComments(doc, { mdx, mdxish } = {}) {
95686
95748
  const { replaced, blocks } = extractMagicBlocks(doc);
95687
- const processor = unified()
95749
+ const processor = unified();
95750
+ // we still require these two extensions because:
95751
+ // 1. we can rely on remarkMdx to parse MDXish
95752
+ // 2. we need to parse JSX comments into mdxTextExpression nodes so that the transformers can pick them up
95753
+ if (mdxish) {
95754
+ processor
95755
+ .data('micromarkExtensions', [mdxExpression({ allowEmpty: true })])
95756
+ .data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()]);
95757
+ }
95758
+ processor
95688
95759
  .use(remarkParse)
95689
95760
  .use(normalize_malformed_md_syntax)
95690
95761
  .use(mdx ? remarkMdx : undefined)
@@ -95706,8 +95777,14 @@ async function stripComments(doc, { mdx } = {}) {
95706
95777
  // Preserve tight sibling code blocks without adding extra newlines between them.
95707
95778
  // Our markdown renderer uses this to group these code blocks into a tabbed interface.
95708
95779
  (left, right) => {
95709
- // 0 = no newline between blocks
95710
- return left.type === 'code' && right.type === 'code' ? 0 : undefined;
95780
+ if (left.type === 'code' && right.type === 'code') {
95781
+ const isTight = left.position &&
95782
+ right.position &&
95783
+ right.position.start.line - left.position.end.line === 1; // Are the blocks on adjacent lines?
95784
+ // 0 = no newline between blocks
95785
+ return isTight ? 0 : undefined;
95786
+ }
95787
+ return undefined;
95711
95788
  },
95712
95789
  ],
95713
95790
  });
package/dist/main.node.js CHANGED
@@ -73127,6 +73127,37 @@ const stripCommentsTransformer = () => {
73127
73127
 
73128
73128
 
73129
73129
  const STRIP_TAGS = ['script', 'style'];
73130
+ /**
73131
+ * Extract variable key from MDX expression AST (e.g., {user.name} → 'name')
73132
+ * Uses ESTree AST inspection, matching the approach in processor/transform/variables.ts
73133
+ *
73134
+ * @see https://github.com/syntax-tree/mdast-util-mdx-expression - MdxTextExpressionHast type
73135
+ * @see https://github.com/estree/estree/blob/master/es5.md - ESTree spec for expression types
73136
+ */
73137
+ function extractMdxVariableKey(node) {
73138
+ const estree = node.data?.estree;
73139
+ if (!estree || estree.type !== 'Program' || estree.body.length === 0)
73140
+ return undefined;
73141
+ const statement = estree.body[0];
73142
+ if (statement.type !== 'ExpressionStatement')
73143
+ return undefined;
73144
+ const expr = statement.expression;
73145
+ if (expr.type !== 'MemberExpression')
73146
+ return undefined;
73147
+ const memberExpr = expr;
73148
+ const obj = memberExpr.object;
73149
+ if (obj.type !== 'Identifier' || obj.name !== 'user')
73150
+ return undefined;
73151
+ const prop = memberExpr.property;
73152
+ if (prop.type === 'Identifier') {
73153
+ return prop.name;
73154
+ }
73155
+ if (prop.type === 'Literal') {
73156
+ const val = prop.value;
73157
+ return typeof val === 'string' ? val : undefined;
73158
+ }
73159
+ return undefined;
73160
+ }
73130
73161
  function plain_one(node, opts) {
73131
73162
  if (node.type === 'comment')
73132
73163
  return '';
@@ -73150,6 +73181,8 @@ function plain_one(node, opts) {
73150
73181
  const body = children ? plain_all({ type: 'root', children }, opts) : '';
73151
73182
  return [icon, ' ', title, title && body && ': ', body].filter(Boolean).join('');
73152
73183
  }
73184
+ // 'variable' (lowercase) comes from mdxish() after rehypeRaw normalizes HTML tag names
73185
+ case 'variable':
73153
73186
  case 'Variable': {
73154
73187
  const key = node.properties.name.toString();
73155
73188
  const val = 'variables' in opts && opts.variables[key];
@@ -73171,6 +73204,13 @@ function plain_one(node, opts) {
73171
73204
  break;
73172
73205
  }
73173
73206
  }
73207
+ // Handle MDX expressions like {user.name}
73208
+ if (node.type === 'mdxTextExpression') {
73209
+ const key = extractMdxVariableKey(node);
73210
+ if (key) {
73211
+ return ('variables' in opts && opts.variables[key]) || key;
73212
+ }
73213
+ }
73174
73214
  if ('value' in node) {
73175
73215
  return node.value;
73176
73216
  }
@@ -106832,11 +106872,27 @@ const getDepth = (el) => {
106832
106872
  return Infinity;
106833
106873
  return parseInt(el.tagName?.match(/^h(\d)/)[1], 10);
106834
106874
  };
106875
+ /**
106876
+ * Flatten Variables into a simple key-value map for static resolution.
106877
+ * Merges user values with defaults (user values take precedence).
106878
+ */
106879
+ const flattenVariables = (variables) => {
106880
+ if (!variables)
106881
+ return {};
106882
+ return {
106883
+ ...variables.user,
106884
+ ...Object.fromEntries((variables.defaults || []).filter(d => !(d.name in variables.user)).map(d => [d.name, d.default])),
106885
+ };
106886
+ };
106835
106887
  /*
106836
106888
  * `tocToHast` consumes the list generated by `rehypeToc` and produces a hast
106837
106889
  * of nested lists to be rendered as a table of contents.
106890
+ *
106891
+ * @param headings - The list of heading elements to render
106892
+ * @param variables - Optional user variables for resolving Variable nodes in headings
106838
106893
  */
106839
- const tocToHast = (headings = []) => {
106894
+ const tocToHast = (headings = [], variables) => {
106895
+ const flatVars = flattenVariables(variables);
106840
106896
  const headingDepths = headings.map(getDepth);
106841
106897
  const min = Math.min(...headingDepths);
106842
106898
  const ast = hastscript_lib_h('ul');
@@ -106854,7 +106910,7 @@ const tocToHast = (headings = []) => {
106854
106910
  stack.pop();
106855
106911
  }
106856
106912
  if (heading.properties) {
106857
- const content = lib_plain({ type: 'root', children: heading.children });
106913
+ const content = lib_plain({ type: 'root', children: heading.children }, { variables: flatVars });
106858
106914
  stack[stack.length - 1].children.push(hastscript_lib_h('li', null, hastscript_lib_h('a', { href: `#${heading.properties.id}` }, content)));
106859
106915
  }
106860
106916
  });
@@ -106864,8 +106920,12 @@ const tocToHast = (headings = []) => {
106864
106920
  * `tocHastToMdx` is a utility for combining `TocList`s of a root document and
106865
106921
  * any child components it may have. Once combined it will generate a markdown
106866
106922
  * doc representing a table of contents.
106923
+ *
106924
+ * @param toc - The list of TOC elements
106925
+ * @param components - Custom components that may contain headings
106926
+ * @param variables - Optional user variables for resolving Variable nodes in headings
106867
106927
  */
106868
- const tocHastToMdx = (toc, components) => {
106928
+ const tocHastToMdx = (toc, components, variables) => {
106869
106929
  if (typeof toc === 'undefined')
106870
106930
  return '';
106871
106931
  const injected = toc.flatMap(node => {
@@ -106874,7 +106934,7 @@ const tocHastToMdx = (toc, components) => {
106874
106934
  }
106875
106935
  return node;
106876
106936
  });
106877
- const tocHast = tocToHast(injected);
106937
+ const tocHast = tocToHast(injected, variables);
106878
106938
  return lib_mdx({ type: 'root', children: [tocHast] }, { hast: true });
106879
106939
  };
106880
106940
 
@@ -115701,7 +115761,7 @@ function buildRMDXModule(content, headings, tocHast, opts) {
115701
115761
  * @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
115702
115762
  */
115703
115763
  const renderMdxish = (tree, opts = {}) => {
115704
- const { components: userComponents = {}, ...contextOpts } = opts;
115764
+ const { components: userComponents = {}, variables, ...contextOpts } = opts;
115705
115765
  const components = {
115706
115766
  ...loadComponents(),
115707
115767
  ...userComponents,
@@ -115710,8 +115770,8 @@ const renderMdxish = (tree, opts = {}) => {
115710
115770
  const componentsForRehype = exportComponentsForRehype(components);
115711
115771
  const processor = createRehypeReactProcessor(componentsForRehype);
115712
115772
  const content = processor.stringify(tree);
115713
- const tocHast = headings.length > 0 ? tocToHast(headings) : null;
115714
- return buildRMDXModule(content, headings, tocHast, contextOpts);
115773
+ const tocHast = headings.length > 0 ? tocToHast(headings, variables) : null;
115774
+ return buildRMDXModule(content, headings, tocHast, { ...contextOpts, variables });
115715
115775
  };
115716
115776
  /* harmony default export */ const lib_renderMdxish = (renderMdxish);
115717
115777
 
@@ -115821,7 +115881,7 @@ const run_run = (string, _opts = {}) => {
115821
115881
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
115822
115882
  const { Toc: _Toc, toc, default: Content, stylesheet, ...exports } = exec(string);
115823
115883
  let Toc;
115824
- const tocMdx = tocHastToMdx(toc, tocsByTag);
115884
+ const tocMdx = tocHastToMdx(toc, tocsByTag, variables);
115825
115885
  if (tocMdx) {
115826
115886
  const compiledToc = lib_compile(tocMdx);
115827
115887
  const tocModule = exec(compiledToc, { useMDXComponents: () => ({ p: Fragment }) });
@@ -115883,12 +115943,23 @@ const mdxishTags_tags = (doc) => {
115883
115943
 
115884
115944
 
115885
115945
 
115946
+
115947
+
115886
115948
  /**
115887
115949
  * Removes Markdown and MDX comments.
115888
115950
  */
115889
- async function stripComments(doc, { mdx } = {}) {
115951
+ async function stripComments(doc, { mdx, mdxish } = {}) {
115890
115952
  const { replaced, blocks } = extractMagicBlocks(doc);
115891
- const processor = unified()
115953
+ const processor = unified();
115954
+ // we still require these two extensions because:
115955
+ // 1. we can rely on remarkMdx to parse MDXish
115956
+ // 2. we need to parse JSX comments into mdxTextExpression nodes so that the transformers can pick them up
115957
+ if (mdxish) {
115958
+ processor
115959
+ .data('micromarkExtensions', [mdxExpression({ allowEmpty: true })])
115960
+ .data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()]);
115961
+ }
115962
+ processor
115892
115963
  .use(remarkParse)
115893
115964
  .use(normalize_malformed_md_syntax)
115894
115965
  .use(mdx ? remarkMdx : undefined)
@@ -115910,8 +115981,14 @@ async function stripComments(doc, { mdx } = {}) {
115910
115981
  // Preserve tight sibling code blocks without adding extra newlines between them.
115911
115982
  // Our markdown renderer uses this to group these code blocks into a tabbed interface.
115912
115983
  (left, right) => {
115913
- // 0 = no newline between blocks
115914
- return left.type === 'code' && right.type === 'code' ? 0 : undefined;
115984
+ if (left.type === 'code' && right.type === 'code') {
115985
+ const isTight = left.position &&
115986
+ right.position &&
115987
+ right.position.start.line - left.position.end.line === 1; // Are the blocks on adjacent lines?
115988
+ // 0 = no newline between blocks
115989
+ return isTight ? 0 : undefined;
115990
+ }
115991
+ return undefined;
115915
115992
  },
115916
115993
  ],
115917
115994
  });