@readme/markdown 15.9.1 → 15.9.3

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.node.js CHANGED
@@ -16243,6 +16243,15 @@ function cloneSort(comparator) {
16243
16243
  return templateFn(comparator);
16244
16244
  }
16245
16245
 
16246
+ let isEvalAllowed = (function () {
16247
+ try {
16248
+ new Function('return 0')();
16249
+ return true;
16250
+ } catch {
16251
+ return false;
16252
+ }
16253
+ })();
16254
+
16246
16255
  /**
16247
16256
  * Sort the given array in-place with the given comparator function.
16248
16257
  *
@@ -16254,7 +16263,7 @@ function cloneSort(comparator) {
16254
16263
 
16255
16264
  let sortCache = new WeakMap();
16256
16265
  exports.g = function (ary, comparator, start = 0) {
16257
- let doQuickSort = sortCache.get(comparator);
16266
+ let doQuickSort = isEvalAllowed ? sortCache.get(comparator) : SortTemplate(comparator);
16258
16267
  if (doQuickSort === void 0) {
16259
16268
  doQuickSort = cloneSort(comparator);
16260
16269
  sortCache.set(comparator, doQuickSort);
@@ -16282,6 +16291,14 @@ var ArraySet = (__webpack_require__(4361)/* .ArraySet */ .C);
16282
16291
  var base64VLQ = __webpack_require__(582);
16283
16292
  var quickSort = (__webpack_require__(4951)/* .quickSort */ .g);
16284
16293
 
16294
+ // Upper bound for a section's `offset.line` in an indexed source map. A flat
16295
+ // map spends one ';' per generated line, so a tiny indexed map with a huge
16296
+ // offset.line turns into a huge amount of work and memory once its mappings
16297
+ // are copied into a SourceMapGenerator (CVE-2026-93749). Ten million lines is
16298
+ // far beyond any real generated file. Columns are VLQ-encoded as deltas and
16299
+ // don't amplify, so they only need to be valid integers.
16300
+ var MAX_SECTION_OFFSET_LINE = 1e7;
16301
+
16285
16302
  function SourceMapConsumer(aSourceMap, aSourceMapURL) {
16286
16303
  var sourceMap = aSourceMap;
16287
16304
  if (typeof aSourceMap === 'string') {
@@ -17206,6 +17223,7 @@ function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) {
17206
17223
  line: -1,
17207
17224
  column: 0
17208
17225
  };
17226
+ var maxOffsetLine = 0;
17209
17227
  this._sections = sections.map(function (s) {
17210
17228
  if (s.url) {
17211
17229
  // The url field will require support for asynchronicity.
@@ -17216,12 +17234,32 @@ function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) {
17216
17234
  var offsetLine = util.getArg(offset, 'line');
17217
17235
  var offsetColumn = util.getArg(offset, 'column');
17218
17236
 
17237
+ if (!isValidOffset(offsetLine) || !isValidOffset(offsetColumn)) {
17238
+ throw new Error('Section offset line and column must be non-negative integers.');
17239
+ }
17240
+ if (offsetLine > MAX_SECTION_OFFSET_LINE) {
17241
+ throw new Error('Section offset line must not exceed ' + MAX_SECTION_OFFSET_LINE + '.');
17242
+ }
17243
+
17219
17244
  if (offsetLine < lastOffset.line ||
17220
17245
  (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) {
17221
17246
  throw new Error('Section offsets must be ordered and non-overlapping.');
17222
17247
  }
17223
17248
  lastOffset = offset;
17224
17249
 
17250
+ var consumer = new SourceMapConsumer(util.getArg(s, 'map'), aSourceMapURL);
17251
+
17252
+ // Offsets of a nested indexed map add up with this one, so apply the
17253
+ // bound to the total.
17254
+ var totalOffsetLine = offsetLine + (consumer._maxOffsetLine || 0);
17255
+ if (totalOffsetLine > MAX_SECTION_OFFSET_LINE) {
17256
+ throw new Error('Section offset line must not exceed ' + MAX_SECTION_OFFSET_LINE +
17257
+ ', including offsets of nested sections.');
17258
+ }
17259
+ if (totalOffsetLine > maxOffsetLine) {
17260
+ maxOffsetLine = totalOffsetLine;
17261
+ }
17262
+
17225
17263
  return {
17226
17264
  generatedOffset: {
17227
17265
  // The offset fields are 0-based, but we use 1-based indices when
@@ -17229,9 +17267,24 @@ function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) {
17229
17267
  generatedLine: offsetLine + 1,
17230
17268
  generatedColumn: offsetColumn + 1
17231
17269
  },
17232
- consumer: new SourceMapConsumer(util.getArg(s, 'map'), aSourceMapURL)
17270
+ consumer: consumer
17233
17271
  }
17234
17272
  });
17273
+
17274
+ // The largest offset.line of any section, including nested sections.
17275
+ this._maxOffsetLine = maxOffsetLine;
17276
+ }
17277
+
17278
+ /**
17279
+ * Section offsets come from untrusted input and are used as line/column
17280
+ * numbers, so only accept non-negative safe integers (rejects NaN, Infinity,
17281
+ * strings, fractions, etc).
17282
+ */
17283
+ function isValidOffset(aValue) {
17284
+ return typeof aValue === 'number' &&
17285
+ aValue >= 0 &&
17286
+ aValue <= 9007199254740991 && // Number.MAX_SAFE_INTEGER
17287
+ Math.floor(aValue) === aValue;
17235
17288
  }
17236
17289
 
17237
17290
  IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
@@ -17249,8 +17302,12 @@ Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', {
17249
17302
  get: function () {
17250
17303
  var sources = [];
17251
17304
  for (var i = 0; i < this._sections.length; i++) {
17252
- for (var j = 0; j < this._sections[i].consumer.sources.length; j++) {
17253
- sources.push(this._sections[i].consumer.sources[j]);
17305
+ // Read the getter once per section: for a nested indexed map it is
17306
+ // itself this getter, and re-reading it per item is exponential in the
17307
+ // nesting depth (CVE-2026-93749).
17308
+ var sectionSources = this._sections[i].consumer.sources;
17309
+ for (var j = 0; j < sectionSources.length; j++) {
17310
+ sources.push(sectionSources[j]);
17254
17311
  }
17255
17312
  }
17256
17313
  return sources;
@@ -17814,10 +17871,12 @@ SourceMapGenerator.prototype._serializeMappings =
17814
17871
 
17815
17872
  if (mapping.generatedLine !== previousGeneratedLine) {
17816
17873
  previousGeneratedColumn = 0;
17817
- while (mapping.generatedLine !== previousGeneratedLine) {
17818
- next += ';';
17819
- previousGeneratedLine++;
17820
- }
17874
+ // One ';' per skipped line. Build large gaps with a single flat
17875
+ // string: appending ';' one by one creates a rope node per line, which
17876
+ // can exhaust the heap for a big gap (CVE-2026-93749).
17877
+ var lineDelta = mapping.generatedLine - previousGeneratedLine;
17878
+ next += lineDelta === 1 ? ';' : ';'.repeat(lineDelta);
17879
+ previousGeneratedLine = mapping.generatedLine;
17821
17880
  }
17822
17881
  else {
17823
17882
  if (i > 0) {
@@ -18031,6 +18090,13 @@ SourceNode.fromStringWithSourceMap =
18031
18090
  // to the SourceNode without any mapping.
18032
18091
  // Each line is added as separate string.
18033
18092
  while (lastGeneratedLine < mapping.generatedLine) {
18093
+ if (remainingLinesIndex >= remainingLines.length) {
18094
+ // The generated code is exhausted. Skip the rest instead of adding
18095
+ // empty lines one by one: a mapping may point far past the end of
18096
+ // the code (e.g. an indexed map section with a huge offset.line).
18097
+ lastGeneratedLine = mapping.generatedLine;
18098
+ break;
18099
+ }
18034
18100
  node.add(shiftNextLine());
18035
18101
  lastGeneratedLine++;
18036
18102
  }
@@ -24741,7 +24807,8 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
24741
24807
  // In MDX mode, safeMode is passed in as a boolean from JSX parsing
24742
24808
  // In MDXish mode, safeMode comes in as a string from HAST props
24743
24809
  const safeMode = typeof safeModeRaw !== 'boolean' ? safeModeRaw === 'true' : safeModeRaw;
24744
- const [cleanedHtml, exec] = extractScripts(html);
24810
+ // Memoised so `exec` is stable across rerenders and the effect below only runs when the html changes.
24811
+ const [cleanedHtml, exec] = (0,external_react_.useMemo)(() => extractScripts(html), [html]);
24745
24812
  (0,external_react_.useEffect)(() => {
24746
24813
  if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
24747
24814
  exec();
@@ -25722,6 +25789,8 @@ const TOKENIZER_MDX_COMPONENT_EXCLUDED_TAGS = new Set([
25722
25789
  * run after rehype (where hast `tagName` is normalized to lowercase).
25723
25790
  */
25724
25791
  const INLINE_COMPONENT_TAGS_LOWER = new Set([...INLINE_COMPONENT_TAGS].map(t => t.toLowerCase()));
25792
+ /** Raw markup props injected with `dangerouslySetInnerHTML` by HTMLBlock and Embed; never interpolate reader values. */
25793
+ const RAW_HTML_PROP_NAMES = new Set(['html']);
25725
25794
 
25726
25795
  ;// ./node_modules/github-slugger/regex.js
25727
25796
  // This module is generated by `script/`.
@@ -127957,33 +128026,75 @@ function repairMistakenTableClosers(content) {
127957
128026
  return applyInserts(content, edits).value;
127958
128027
  }
127959
128028
 
128029
+ ;// ./lib/utils/mdxish/mdxish-variables.ts
128030
+
128031
+
128032
+ // The `$` guard skips template-literal interpolation: `${user.name}` embeds `{user.name}`, and
128033
+ // substituting it would leave a mangled `` `Hi $Name` `` behind. Those belong to an expression,
128034
+ // which either evaluated already or is meant to stay literal.
128035
+ const MDX_VARIABLE_REGEX = new RegExp(`(?<!\\$)${variable_dist.MDX_VARIABLE_REGEXP}`, 'gu');
128036
+ // A whole attribute expression that is one `user.*` reference, e.g. the `user.name` in `title={user.name}`.
128037
+ const BARE_VARIABLE_REGEX = new RegExp(`^${variable_dist.MDX_VARIABLE_REGEXP}$`, 'u');
128038
+ // Bracket notation names the same variable as dot notation, so normalize it before substituting.
128039
+ // Escaped and `$`-prefixed forms are left alone so a reference that stays literal keeps its source.
128040
+ // A closing escape needs no lookahead: requiring a literal `]}` already rules out `]\}`.
128041
+ const BRACKET_NOTATION_REGEX = /(?<![$\\])\{user\[['"](\w+)['"]\]\}/gu;
128042
+ /**
128043
+ * Resolve `{user.*}` in a JSX attribute value against the same `user` binding the rmdx engine gets,
128044
+ * so both engines agree. Body text differs on empty values: `Variable` falls back to the default.
128045
+ *
128046
+ * Legacy `<<...>>` is valid inside a quoted attribute but deliberately left literal — attributes are
128047
+ * an MDX surface, and `{user.*}` is the syntax authors use there.
128048
+ */
128049
+ function resolveAttributeVariables(value, user) {
128050
+ if (!value.includes('{user'))
128051
+ return value;
128052
+ return value
128053
+ .replace(BRACKET_NOTATION_REGEX, '{user.$1}')
128054
+ .replace(MDX_VARIABLE_REGEX, (source, escapePrefix, name, escapeSuffix) => {
128055
+ if (escapePrefix || escapeSuffix)
128056
+ return source;
128057
+ return stringifyVariableValue(user[name]);
128058
+ });
128059
+ }
128060
+ /** Whether an attribute expression's source is a bare `user.*` reference, left for render-time substitution. */
128061
+ const isBareVariableReference = (source) => BARE_VARIABLE_REGEX.test(`{${source.trim()}}`.replace(BRACKET_NOTATION_REGEX, '{user.$1}'));
128062
+
127960
128063
  ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
127961
128064
 
127962
128065
 
127963
128066
 
127964
128067
 
128068
+
128069
+
128070
+
127965
128071
  /**
127966
128072
  * Resolve attribute expressions that `mdxJsxElementHandler` deferred.
127967
128073
  *
127968
128074
  * The handler stashed each attribute expression's source in `node.data.deferredExpressions`
127969
128075
  * (keyed by prop name) instead of evaluating eagerly, because an eager result can be a React
127970
128076
  * element or function that rehypeRaw's `structuredClone` passthrough rejects. Now that we're
127971
- * past the clone, evaluate each source with a scope of `{ React, ...mdxishScope }` and write
128077
+ * past the clone, evaluate each source with a scope of `{ user, React, ...mdxishScope }` and write
127972
128078
  * the real value into `properties` (e.g. an array of objects whose fields are React elements).
127973
128079
  *
127974
128080
  * Must run after `rehypeRaw` (past the clone) but before `normalizeMdxJsxNodes` rewrites these
127975
128081
  * `mdx-jsx` nodes into plain elements. Skipped in safeMode, which keeps expressions literal.
127976
128082
  */
127977
- const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
128083
+ const resolveDeferredAttributeExpressionProps = ({ variables } = {}) => (tree, file) => {
127978
128084
  const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
128085
+ // `user` only when variables were supplied, as in `evaluateExpressions`.
128086
+ const userScope = variables ? { user: user(variables), ...scope } : scope;
127979
128087
  visit(tree, 'mdx-jsx', (node) => {
127980
128088
  const deferredExpressions = node.data?.deferredExpressions;
127981
128089
  if (!deferredExpressions)
127982
128090
  return;
127983
128091
  const properties = node.properties;
127984
128092
  Object.entries(deferredExpressions).forEach(([name, source]) => {
128093
+ // Raw markup never gets `user`: a reader's values reaching `dangerouslySetInnerHTML` is an injection
128094
+ // vector. A bare `{user.x}` keeps render-time substitution, which stringifies structured values.
128095
+ const canReadUser = !RAW_HTML_PROP_NAMES.has(name) && !isBareVariableReference(source);
127985
128096
  try {
127986
- const result = evalExpression(source, scope);
128097
+ const result = evalExpression(source, canReadUser ? userScope : scope);
127987
128098
  // hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
127988
128099
  // a JS object, which must be serialized or it renders as the literal "[object Object]".
127989
128100
  properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
@@ -128647,7 +128758,7 @@ function mdxish(mdContent, opts = {}) {
128647
128758
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
128648
128759
  .use(rehypeRaw, { passThrough: ['html-block', 'mdx-jsx'] }) // MDX JSX nodes bypass parse5's string-only HTML round-trip
128649
128760
  .use(restoreBooleanProperties)
128650
- .use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
128761
+ .use(safeMode ? undefined : resolve_deferred_attribute_expression_props, { variables }) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
128651
128762
  .use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
128652
128763
  .use(sanitize ? rehypeStripTags : undefined) // Strip STRIPPED_TAG_NAMES elements; this pipeline has no sanitization step
128653
128764
  .use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
@@ -128853,36 +128964,6 @@ const makeUseMDXComponents = (more = {}) => {
128853
128964
  };
128854
128965
  /* harmony default export */ const makeUseMdxComponents = (makeUseMDXComponents);
128855
128966
 
128856
- ;// ./lib/utils/mdxish/mdxish-variables.ts
128857
-
128858
-
128859
- // The `$` guard skips template-literal interpolation: `${user.name}` embeds `{user.name}`, and
128860
- // substituting it would leave a mangled `` `Hi $Name` `` behind. Those belong to an expression,
128861
- // which either evaluated already or is meant to stay literal.
128862
- const MDX_VARIABLE_REGEX = new RegExp(`(?<!\\$)${variable_dist.MDX_VARIABLE_REGEXP}`, 'gu');
128863
- // Bracket notation names the same variable as dot notation, so normalize it before substituting.
128864
- // Escaped and `$`-prefixed forms are left alone so a reference that stays literal keeps its source.
128865
- // A closing escape needs no lookahead: requiring a literal `]}` already rules out `]\}`.
128866
- const BRACKET_NOTATION_REGEX = /(?<![$\\])\{user\[['"](\w+)['"]\]\}/gu;
128867
- /**
128868
- * Resolve `{user.*}` in a JSX attribute value against the same `user` binding the rmdx engine gets,
128869
- * so both engines agree. Body text differs on empty values: `Variable` falls back to the default.
128870
- *
128871
- * Legacy `<<...>>` is valid inside a quoted attribute but deliberately left literal — attributes are
128872
- * an MDX surface, and `{user.*}` is the syntax authors use there.
128873
- */
128874
- function resolveAttributeVariables(value, user) {
128875
- if (!value.includes('{user'))
128876
- return value;
128877
- return value
128878
- .replace(BRACKET_NOTATION_REGEX, '{user.$1}')
128879
- .replace(MDX_VARIABLE_REGEX, (source, escapePrefix, name, escapeSuffix) => {
128880
- if (escapePrefix || escapeSuffix)
128881
- return source;
128882
- return stringifyVariableValue(user[name]);
128883
- });
128884
- }
128885
-
128886
128967
  ;// ./lib/utils/mdxish/mdxish-render-utils.tsx
128887
128968
 
128888
128969
 
@@ -128893,6 +128974,7 @@ function resolveAttributeVariables(value, user) {
128893
128974
 
128894
128975
 
128895
128976
 
128977
+
128896
128978
  /** Flatten CustomComponents into a component map for rehype-react */
128897
128979
  function exportComponentsForRehype(components) {
128898
128980
  const exported = Object.entries(components).reduce((memo, [tag, mod]) => {
@@ -128925,8 +129007,6 @@ function exportComponentsForRehype(components) {
128925
129007
  * deliberately leaves mermaid alone; resolving it again here would override that.
128926
129008
  */
128927
129009
  const CODE_TAG_NAMES = new Set(['code']);
128928
- /** Raw markup injected with `dangerouslySetInnerHTML` by HTMLBlock and Embed — never interpolate. */
128929
- const RAW_HTML_PROP_NAMES = new Set(['html']);
128930
129010
  /**
128931
129011
  * Resolve `{user.*}` in string-valued props. Body text is handled by the `Variable` component, but
128932
129012
  * attributes are plain strings, so they are substituted here — at render time, so that a