@readme/markdown 14.8.0 → 14.8.1

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.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Evaluate an expression body, transforming JSX to `React.createElement` only when the
3
+ * parsed estree actually contains a JSX node. The raw `Function()` evaluator can't parse
4
+ * JSX, so JSX-bearing expressions take the build-and-serialize path while everything else
5
+ * evaluates directly. Input acorn can't parse falls back to the plain evaluator unchanged.
6
+ */
7
+ export declare const evalExpression: (expression: string, scope: Record<string, unknown>) => any;
package/dist/main.js CHANGED
@@ -98755,26 +98755,17 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
98755
98755
  ;// ./processor/plugin/mdxish-handlers.ts
98756
98756
 
98757
98757
 
98758
-
98759
98758
  // Convert MDX expressions to text nodes (evaluation happens earlier in pipeline)
98760
98759
  const mdxExpressionHandler = (_state, node) => ({
98761
98760
  type: 'text',
98762
98761
  value: node.value || '',
98763
98762
  });
98764
- function isStructuredCloneable(value) {
98765
- try {
98766
- structuredClone(value);
98767
- return true;
98768
- }
98769
- catch {
98770
- return false;
98771
- }
98772
- }
98773
98763
  // Convert MDX JSX elements to a custom mdx-jsx hast node that bypasses rehypeRaw's
98774
98764
  // HTML serialization round-trip; downstream normalization rewrites it to `element`.
98775
98765
  const mdxJsxElementHandler = (state, node) => {
98776
98766
  const { attributes = [], name } = node;
98777
98767
  const properties = {};
98768
+ const deferredExpressions = {};
98778
98769
  attributes.forEach(attribute => {
98779
98770
  if (attribute.type !== 'mdxJsxAttribute' || !attribute.name)
98780
98771
  return;
@@ -98785,30 +98776,20 @@ const mdxJsxElementHandler = (state, node) => {
98785
98776
  properties[attribute.name] = decode_decodeHTMLStrict(attribute.value);
98786
98777
  }
98787
98778
  else {
98788
- const expressionSource = attribute.value.value;
98789
- let evaluated;
98790
- try {
98791
- evaluated = evaluate(expressionSource);
98792
- }
98793
- catch {
98794
- evaluated = expressionSource;
98795
- }
98796
- // rehypeRaw's passThrough clones our mdx-jsx node with structuredClone, which
98797
- // rejects functions and other non-serializable values. Attribute expressions
98798
- // that evaluate to such values (`onClick={() => ...}`) would crash the pipeline,
98799
- // so if we have a non-serializable value, we fall back to the raw expression source
98800
- // and not support it for now.
98801
- if (!isStructuredCloneable(evaluated)) {
98802
- evaluated = expressionSource;
98803
- }
98804
- properties[attribute.name] = evaluated;
98779
+ // Defer every attribute-expression evaluation past rehypeRaw's `structuredClone`
98780
+ // passthrough: evaluating here can yield React elements or functions that the clone
98781
+ // rejects. The source is stashed in `node.data` (clone-safe) and
98782
+ // `resolveDeferredAttributeExpressionProps` evaluates it once past the clone.
98783
+ deferredExpressions[attribute.name] = attribute.value.value;
98805
98784
  }
98806
98785
  });
98786
+ const hasDeferredExpressions = Object.keys(deferredExpressions).length > 0;
98807
98787
  const jsxNode = {
98808
98788
  type: 'mdx-jsx',
98809
98789
  tagName: name || '',
98810
- properties,
98790
+ properties: properties,
98811
98791
  children: state.all(node),
98792
+ ...(hasDeferredExpressions && { data: { deferredExpressions } }),
98812
98793
  };
98813
98794
  return jsxNode;
98814
98795
  };
@@ -102090,27 +102071,56 @@ const evaluateExports = () => (tree, file) => {
102090
102071
 
102091
102072
  // EXTERNAL MODULE: ./node_modules/react-dom/server.browser.js
102092
102073
  var server_browser = __webpack_require__(5848);
102093
- ;// ./processor/transform/mdxish/evaluate-expressions.ts
102094
-
102095
-
102096
-
102074
+ ;// ./lib/utils/mdxish/mdxish-expression.ts
102097
102075
 
102098
102076
 
102099
102077
 
102100
- const HAS_JSX = /<[A-Za-z]|<>/;
102101
- /** The raw Function() can't parse JSX, so parse & convert it to a React element first so later we can get its HTML representation */
102102
- const evalJsxExpression = (expression, scope) => {
102103
- const program = jsxAcornParser.parse(expression, { ecmaVersion: 'latest', sourceType: 'module' });
102078
+ const parseExpression = (expression) => jsxAcornParser.parse(expression, { ecmaVersion: 'latest', sourceType: 'module' });
102079
+ /**
102080
+ * Recursively report whether an estree value contains any JSX element or fragment node.
102081
+ * estree stores children across named fields (not a `children` array), so this descends
102082
+ * through every nested object/array rather than using a unist-shaped walker.
102083
+ */
102084
+ const containsJsxNode = (value) => {
102085
+ if (Array.isArray(value))
102086
+ return value.some(containsJsxNode);
102087
+ if (value === null || typeof value !== 'object')
102088
+ return false;
102089
+ const { type } = value;
102090
+ if (type === 'JSXElement' || type === 'JSXFragment')
102091
+ return true;
102092
+ return Object.values(value).some(containsJsxNode);
102093
+ };
102094
+ /** Convert a program's JSX into `React.createElement` calls and evaluate it. `scope` must provide `React`. */
102095
+ const evalJsxProgram = (program, scope) => {
102104
102096
  buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
102105
102097
  const { value: source } = toJs(program);
102106
102098
  return evaluate(`(() => { return ${source.trim().replace(/;$/, '')}; })()`, scope);
102107
102099
  };
102108
- /** Evaluate an expression body, transforming JSX to `React.createElement` only when needed. */
102100
+ /**
102101
+ * Evaluate an expression body, transforming JSX to `React.createElement` only when the
102102
+ * parsed estree actually contains a JSX node. The raw `Function()` evaluator can't parse
102103
+ * JSX, so JSX-bearing expressions take the build-and-serialize path while everything else
102104
+ * evaluates directly. Input acorn can't parse falls back to the plain evaluator unchanged.
102105
+ */
102109
102106
  const evalExpression = (expression, scope) => {
102110
- if (HAS_JSX.test(expression))
102111
- return evalJsxExpression(expression, scope);
102112
- return evaluate(expression, scope);
102107
+ let program;
102108
+ try {
102109
+ program = parseExpression(expression);
102110
+ }
102111
+ catch {
102112
+ return evaluate(expression, scope);
102113
+ }
102114
+ if (!containsJsxNode(program))
102115
+ return evaluate(expression, scope);
102116
+ return evalJsxProgram(program, scope);
102113
102117
  };
102118
+
102119
+ ;// ./processor/transform/mdxish/evaluate-expressions.ts
102120
+
102121
+
102122
+
102123
+
102114
102124
  /** Given the type of the expression result, create the corresponding mdast node. */
102115
102125
  const createEvaluatedNode = (result, position) => {
102116
102126
  if (result === null || result === undefined) {
@@ -104168,6 +104178,45 @@ function preprocessJSXExpressions(content) {
104168
104178
  return processed;
104169
104179
  }
104170
104180
 
104181
+ ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
104182
+
104183
+
104184
+
104185
+ /**
104186
+ * Resolve attribute expressions that `mdxJsxElementHandler` deferred.
104187
+ *
104188
+ * The handler stashed each attribute expression's source in `node.data.deferredExpressions`
104189
+ * (keyed by prop name) instead of evaluating eagerly, because an eager result can be a React
104190
+ * element or function that rehypeRaw's `structuredClone` passthrough rejects. Now that we're
104191
+ * past the clone, evaluate each source with a scope of `{ React, ...mdxishScope }` and write
104192
+ * the real value into `properties` (e.g. an array of objects whose fields are React elements).
104193
+ *
104194
+ * Must run after `rehypeRaw` (past the clone) but before `normalizeMdxJsxNodes` rewrites these
104195
+ * `mdx-jsx` nodes into plain elements. Skipped in safeMode, which keeps expressions literal.
104196
+ */
104197
+ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
104198
+ const scope = { ...file.data.mdxishScope, React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()) };
104199
+ visit(tree, 'mdx-jsx', (node) => {
104200
+ const deferredExpressions = node.data?.deferredExpressions;
104201
+ if (!deferredExpressions)
104202
+ return;
104203
+ const properties = node.properties;
104204
+ Object.entries(deferredExpressions).forEach(([name, source]) => {
104205
+ try {
104206
+ properties[name] = evalExpression(source, scope);
104207
+ }
104208
+ catch {
104209
+ // Evaluation failed — fall back to the raw expression source so the attribute
104210
+ // renders as readable text rather than disappearing.
104211
+ properties[name] = source;
104212
+ }
104213
+ });
104214
+ delete node.data.deferredExpressions;
104215
+ });
104216
+ return tree;
104217
+ };
104218
+ /* harmony default export */ const resolve_deferred_attribute_expression_props = (resolveDeferredAttributeExpressionProps);
104219
+
104171
104220
  ;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
104172
104221
 
104173
104222
 
@@ -105197,6 +105246,7 @@ function loadComponents() {
105197
105246
 
105198
105247
 
105199
105248
 
105249
+
105200
105250
 
105201
105251
 
105202
105252
  const defaultTransformers = [
@@ -105356,6 +105406,7 @@ function mdxish(mdContent, opts = {}) {
105356
105406
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
105357
105407
  .use(rehypeRaw, { passThrough: ['html-block', 'mdx-jsx'] }) // MDX JSX nodes bypass parse5's string-only HTML round-trip
105358
105408
  .use(restoreBooleanProperties)
105409
+ .use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
105359
105410
  .use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
105360
105411
  .use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
105361
105412
  .use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
package/dist/main.node.js CHANGED
@@ -118979,26 +118979,17 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
118979
118979
  ;// ./processor/plugin/mdxish-handlers.ts
118980
118980
 
118981
118981
 
118982
-
118983
118982
  // Convert MDX expressions to text nodes (evaluation happens earlier in pipeline)
118984
118983
  const mdxExpressionHandler = (_state, node) => ({
118985
118984
  type: 'text',
118986
118985
  value: node.value || '',
118987
118986
  });
118988
- function isStructuredCloneable(value) {
118989
- try {
118990
- structuredClone(value);
118991
- return true;
118992
- }
118993
- catch {
118994
- return false;
118995
- }
118996
- }
118997
118987
  // Convert MDX JSX elements to a custom mdx-jsx hast node that bypasses rehypeRaw's
118998
118988
  // HTML serialization round-trip; downstream normalization rewrites it to `element`.
118999
118989
  const mdxJsxElementHandler = (state, node) => {
119000
118990
  const { attributes = [], name } = node;
119001
118991
  const properties = {};
118992
+ const deferredExpressions = {};
119002
118993
  attributes.forEach(attribute => {
119003
118994
  if (attribute.type !== 'mdxJsxAttribute' || !attribute.name)
119004
118995
  return;
@@ -119009,30 +119000,20 @@ const mdxJsxElementHandler = (state, node) => {
119009
119000
  properties[attribute.name] = decode_decodeHTMLStrict(attribute.value);
119010
119001
  }
119011
119002
  else {
119012
- const expressionSource = attribute.value.value;
119013
- let evaluated;
119014
- try {
119015
- evaluated = evaluate(expressionSource);
119016
- }
119017
- catch {
119018
- evaluated = expressionSource;
119019
- }
119020
- // rehypeRaw's passThrough clones our mdx-jsx node with structuredClone, which
119021
- // rejects functions and other non-serializable values. Attribute expressions
119022
- // that evaluate to such values (`onClick={() => ...}`) would crash the pipeline,
119023
- // so if we have a non-serializable value, we fall back to the raw expression source
119024
- // and not support it for now.
119025
- if (!isStructuredCloneable(evaluated)) {
119026
- evaluated = expressionSource;
119027
- }
119028
- properties[attribute.name] = evaluated;
119003
+ // Defer every attribute-expression evaluation past rehypeRaw's `structuredClone`
119004
+ // passthrough: evaluating here can yield React elements or functions that the clone
119005
+ // rejects. The source is stashed in `node.data` (clone-safe) and
119006
+ // `resolveDeferredAttributeExpressionProps` evaluates it once past the clone.
119007
+ deferredExpressions[attribute.name] = attribute.value.value;
119029
119008
  }
119030
119009
  });
119010
+ const hasDeferredExpressions = Object.keys(deferredExpressions).length > 0;
119031
119011
  const jsxNode = {
119032
119012
  type: 'mdx-jsx',
119033
119013
  tagName: name || '',
119034
- properties,
119014
+ properties: properties,
119035
119015
  children: state.all(node),
119016
+ ...(hasDeferredExpressions && { data: { deferredExpressions } }),
119036
119017
  };
119037
119018
  return jsxNode;
119038
119019
  };
@@ -122314,27 +122295,56 @@ const evaluateExports = () => (tree, file) => {
122314
122295
 
122315
122296
  // EXTERNAL MODULE: ./node_modules/react-dom/server.node.js
122316
122297
  var server_node = __webpack_require__(4362);
122317
- ;// ./processor/transform/mdxish/evaluate-expressions.ts
122318
-
122319
-
122320
-
122298
+ ;// ./lib/utils/mdxish/mdxish-expression.ts
122321
122299
 
122322
122300
 
122323
122301
 
122324
- const HAS_JSX = /<[A-Za-z]|<>/;
122325
- /** The raw Function() can't parse JSX, so parse & convert it to a React element first so later we can get its HTML representation */
122326
- const evalJsxExpression = (expression, scope) => {
122327
- const program = jsxAcornParser.parse(expression, { ecmaVersion: 'latest', sourceType: 'module' });
122302
+ const parseExpression = (expression) => jsxAcornParser.parse(expression, { ecmaVersion: 'latest', sourceType: 'module' });
122303
+ /**
122304
+ * Recursively report whether an estree value contains any JSX element or fragment node.
122305
+ * estree stores children across named fields (not a `children` array), so this descends
122306
+ * through every nested object/array rather than using a unist-shaped walker.
122307
+ */
122308
+ const containsJsxNode = (value) => {
122309
+ if (Array.isArray(value))
122310
+ return value.some(containsJsxNode);
122311
+ if (value === null || typeof value !== 'object')
122312
+ return false;
122313
+ const { type } = value;
122314
+ if (type === 'JSXElement' || type === 'JSXFragment')
122315
+ return true;
122316
+ return Object.values(value).some(containsJsxNode);
122317
+ };
122318
+ /** Convert a program's JSX into `React.createElement` calls and evaluate it. `scope` must provide `React`. */
122319
+ const evalJsxProgram = (program, scope) => {
122328
122320
  buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
122329
122321
  const { value: source } = toJs(program);
122330
122322
  return evaluate(`(() => { return ${source.trim().replace(/;$/, '')}; })()`, scope);
122331
122323
  };
122332
- /** Evaluate an expression body, transforming JSX to `React.createElement` only when needed. */
122324
+ /**
122325
+ * Evaluate an expression body, transforming JSX to `React.createElement` only when the
122326
+ * parsed estree actually contains a JSX node. The raw `Function()` evaluator can't parse
122327
+ * JSX, so JSX-bearing expressions take the build-and-serialize path while everything else
122328
+ * evaluates directly. Input acorn can't parse falls back to the plain evaluator unchanged.
122329
+ */
122333
122330
  const evalExpression = (expression, scope) => {
122334
- if (HAS_JSX.test(expression))
122335
- return evalJsxExpression(expression, scope);
122336
- return evaluate(expression, scope);
122331
+ let program;
122332
+ try {
122333
+ program = parseExpression(expression);
122334
+ }
122335
+ catch {
122336
+ return evaluate(expression, scope);
122337
+ }
122338
+ if (!containsJsxNode(program))
122339
+ return evaluate(expression, scope);
122340
+ return evalJsxProgram(program, scope);
122337
122341
  };
122342
+
122343
+ ;// ./processor/transform/mdxish/evaluate-expressions.ts
122344
+
122345
+
122346
+
122347
+
122338
122348
  /** Given the type of the expression result, create the corresponding mdast node. */
122339
122349
  const createEvaluatedNode = (result, position) => {
122340
122350
  if (result === null || result === undefined) {
@@ -124392,6 +124402,45 @@ function preprocessJSXExpressions(content) {
124392
124402
  return processed;
124393
124403
  }
124394
124404
 
124405
+ ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
124406
+
124407
+
124408
+
124409
+ /**
124410
+ * Resolve attribute expressions that `mdxJsxElementHandler` deferred.
124411
+ *
124412
+ * The handler stashed each attribute expression's source in `node.data.deferredExpressions`
124413
+ * (keyed by prop name) instead of evaluating eagerly, because an eager result can be a React
124414
+ * element or function that rehypeRaw's `structuredClone` passthrough rejects. Now that we're
124415
+ * past the clone, evaluate each source with a scope of `{ React, ...mdxishScope }` and write
124416
+ * the real value into `properties` (e.g. an array of objects whose fields are React elements).
124417
+ *
124418
+ * Must run after `rehypeRaw` (past the clone) but before `normalizeMdxJsxNodes` rewrites these
124419
+ * `mdx-jsx` nodes into plain elements. Skipped in safeMode, which keeps expressions literal.
124420
+ */
124421
+ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
124422
+ const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
124423
+ visit(tree, 'mdx-jsx', (node) => {
124424
+ const deferredExpressions = node.data?.deferredExpressions;
124425
+ if (!deferredExpressions)
124426
+ return;
124427
+ const properties = node.properties;
124428
+ Object.entries(deferredExpressions).forEach(([name, source]) => {
124429
+ try {
124430
+ properties[name] = evalExpression(source, scope);
124431
+ }
124432
+ catch {
124433
+ // Evaluation failed — fall back to the raw expression source so the attribute
124434
+ // renders as readable text rather than disappearing.
124435
+ properties[name] = source;
124436
+ }
124437
+ });
124438
+ delete node.data.deferredExpressions;
124439
+ });
124440
+ return tree;
124441
+ };
124442
+ /* harmony default export */ const resolve_deferred_attribute_expression_props = (resolveDeferredAttributeExpressionProps);
124443
+
124395
124444
  ;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
124396
124445
 
124397
124446
 
@@ -125421,6 +125470,7 @@ function loadComponents() {
125421
125470
 
125422
125471
 
125423
125472
 
125473
+
125424
125474
 
125425
125475
 
125426
125476
  const defaultTransformers = [
@@ -125580,6 +125630,7 @@ function mdxish(mdContent, opts = {}) {
125580
125630
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
125581
125631
  .use(rehypeRaw, { passThrough: ['html-block', 'mdx-jsx'] }) // MDX JSX nodes bypass parse5's string-only HTML round-trip
125582
125632
  .use(restoreBooleanProperties)
125633
+ .use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
125583
125634
  .use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
125584
125635
  .use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
125585
125636
  .use(mdxish_mermaid) // Add mermaid-render className to pre wrappers