@readme/markdown 15.9.0 → 15.9.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.
package/dist/main.node.js CHANGED
@@ -19045,7 +19045,7 @@ module.exports = function () {
19045
19045
 
19046
19046
  /***/ },
19047
19047
 
19048
- /***/ 5789
19048
+ /***/ 6831
19049
19049
  (module, __webpack_exports__, __webpack_require__) {
19050
19050
 
19051
19051
  "use strict";
@@ -24743,9 +24743,9 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
24743
24743
  const safeMode = typeof safeModeRaw !== 'boolean' ? safeModeRaw === 'true' : safeModeRaw;
24744
24744
  const [cleanedHtml, exec] = extractScripts(html);
24745
24745
  (0,external_react_.useEffect)(() => {
24746
- if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts && !safeMode)
24746
+ if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
24747
24747
  exec();
24748
- }, [runScripts, safeMode, exec]);
24748
+ }, [runScripts, exec]);
24749
24749
  if (nonStringChildren) {
24750
24750
  // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
24751
24751
  // raw string) should never throw, so render the child nodes directly
@@ -75148,18 +75148,53 @@ function evaluate(source, scope = {}) {
75148
75148
  return new Function(...names, `return (${source})`)(...values);
75149
75149
  }
75150
75150
  /**
75151
- * Advance a `Point` by the `consumed` substring that follows it, returning the
75152
- * point at the consumed string's end. Lets split-out sub-nodes carry accurate
75153
- * document positions so downstream offset shifting stays correct.
75151
+ * Width each container prefix adds back per line of `value`, aligned from the line end since a
75152
+ * tab in the prefix is expanded to spaces in `value`. None (a verbatim slice) when the source
75153
+ * is missing or doesn't line up.
75154
75154
  */
75155
- const pointAfter = (start, consumed) => {
75156
- const newlineIndex = consumed.lastIndexOf('\n');
75157
- const newlineCount = newlineIndex === -1 ? 0 : consumed.split('\n').length - 1;
75158
- return {
75159
- line: start.line + newlineCount,
75160
- // Same line → advance the base column; a later line → column is the run since its newline.
75161
- column: newlineCount === 0 ? start.column + consumed.length : consumed.length - newlineIndex,
75162
- offset: (start.offset ?? 0) + consumed.length,
75155
+ const containerPrefixWidths = (valueLines, source, position) => {
75156
+ const sourceLines = source?.slice(position.start.offset, position.end.offset).split('\n');
75157
+ const linesUp = sourceLines?.length === valueLines.length &&
75158
+ sourceLines.every((line, i) => line.endsWith(valueLines[i].trimStart()));
75159
+ return valueLines.map((line, i) => (linesUp ? sourceLines[i].length - line.length : 0));
75160
+ };
75161
+ /**
75162
+ * Maps offsets in a node's `value` to points in `source`. Containers strip a prefix from every
75163
+ * continuation line of `value`, so a plain offset shift drifts by line (CX-4028).
75164
+ */
75165
+ const createValueToSourceMapper = (position, value, source) => {
75166
+ if (position?.start.offset === undefined)
75167
+ return null;
75168
+ const { start } = position;
75169
+ const valueLines = value.split('\n');
75170
+ const prefixWidths = containerPrefixWidths(valueLines, source, position);
75171
+ const lines = [];
75172
+ let valueStart = 0;
75173
+ let sourceStart = start.offset;
75174
+ valueLines.forEach((line, i) => {
75175
+ lines.push({ prefixWidth: prefixWidths[i], sourceStart, valueStart });
75176
+ valueStart += line.length + 1;
75177
+ sourceStart += prefixWidths[i] + line.length + 1;
75178
+ });
75179
+ return valueOffset => {
75180
+ // Binary search: a large table maps one point per node.
75181
+ let low = 0;
75182
+ let high = lines.length - 1;
75183
+ while (low < high) {
75184
+ const mid = Math.ceil((low + high) / 2);
75185
+ if (lines[mid].valueStart <= valueOffset)
75186
+ low = mid;
75187
+ else
75188
+ high = mid - 1;
75189
+ }
75190
+ const { prefixWidth, sourceStart: lineSourceStart, valueStart: lineValueStart } = lines[low];
75191
+ // Clamped: an expanded tab can make a leading-whitespace offset fall before the line.
75192
+ const sourceColumn = Math.max(0, prefixWidth + valueOffset - lineValueStart);
75193
+ return {
75194
+ line: start.line + low,
75195
+ column: (low === 0 ? start.column : 1) + sourceColumn,
75196
+ offset: lineSourceStart + sourceColumn,
75197
+ };
75163
75198
  };
75164
75199
  };
75165
75200
  /**
@@ -75822,7 +75857,9 @@ const processBlockquote = (node, index, parent, isMdxish = false) => {
75822
75857
  }
75823
75858
  Object.assign(node, {
75824
75859
  type: NodeTypes.callout,
75860
+ // Keep the blockquote's data, e.g. the `reparseSource` its positions index into.
75825
75861
  data: {
75862
+ ...node.data,
75826
75863
  hName: 'Callout',
75827
75864
  hProperties: {
75828
75865
  icon,
@@ -75855,14 +75892,55 @@ const calloutTransformer = ({ isMdxish = false } = {}) => {
75855
75892
  };
75856
75893
  /* harmony default export */ const callouts = (calloutTransformer);
75857
75894
 
75895
+ ;// ./processor/transform/mdxish/reparse-source.ts
75896
+ /**
75897
+ * Mark re-parsed subtree roots with the string their positions index into, so consumers
75898
+ * slicing by offset use the right source (see `Data.reparseSource`). Only roots are
75899
+ * stamped; descendants resolve via their nearest stamped ancestor. Roots a deeper
75900
+ * re-parse already stamped keep their own string.
75901
+ */
75902
+ const stampReparseSource = (roots, reparseSource) => {
75903
+ roots.forEach(root => {
75904
+ if (!root.data?.reparseSource)
75905
+ root.data = { ...root.data, reparseSource };
75906
+ });
75907
+ };
75908
+ /**
75909
+ * Splice `replacements` over `parent.children[index]`. They take over the replaced node's
75910
+ * position, so they also take over the coordinate space that position indexes into.
75911
+ */
75912
+ const replaceInheritingReparseSource = (parent, index, replacements) => {
75913
+ const replacedSource = parent.children[index]?.data?.reparseSource;
75914
+ if (replacedSource)
75915
+ stampReparseSource(replacements, replacedSource);
75916
+ parent.children.splice(index, 1, ...replacements);
75917
+ };
75918
+ /**
75919
+ * The string `node`'s offsets index into: the nearest stamp on it or an ancestor, else the
75920
+ * document source.
75921
+ */
75922
+ const resolveReparseSource = (node, ancestors, documentSource) => {
75923
+ if (node.data?.reparseSource)
75924
+ return node.data.reparseSource;
75925
+ for (let i = ancestors.length - 1; i >= 0; i -= 1) {
75926
+ const { reparseSource } = ancestors[i].data ?? {};
75927
+ if (reparseSource)
75928
+ return reparseSource;
75929
+ }
75930
+ return documentSource;
75931
+ };
75932
+
75858
75933
  ;// ./processor/transform/code-tabs.ts
75859
75934
 
75860
75935
 
75936
+
75861
75937
  const isCode = (node) => node?.type === 'code';
75862
75938
  const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
75863
75939
  visit(tree, 'code', (node) => {
75864
75940
  const { lang, meta, value } = node;
75865
75941
  node.data = {
75942
+ // Ensure positions are passed through
75943
+ ...node.data,
75866
75944
  hProperties: { lang, meta, value, copyButtons },
75867
75945
  };
75868
75946
  });
@@ -75909,6 +75987,9 @@ const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
75909
75987
  end: children[children.length - 1].position.end,
75910
75988
  },
75911
75989
  };
75990
+ // Adjacent siblings share a coordinate space, so the wrapper takes the first block's.
75991
+ if (node.data?.reparseSource)
75992
+ stampReparseSource([codeTabs], node.data.reparseSource);
75912
75993
  parent.children.splice(index, children.length, codeTabs);
75913
75994
  });
75914
75995
  return tree;
@@ -100291,6 +100372,7 @@ const walkTags = (html, handlers) => {
100291
100372
  };
100292
100373
 
100293
100374
  ;// ./processor/transform/mdxish/tables/utils.ts
100375
+
100294
100376
  const tableTags = new Set([
100295
100377
  'thead',
100296
100378
  'tbody',
@@ -100309,6 +100391,9 @@ const tableTags = new Set([
100309
100391
  const unwrapParagraphNodes = (children) => {
100310
100392
  return children.flatMap(child => {
100311
100393
  if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
100394
+ // The unwrap drops a stamped root, so its children inherit that coordinate space.
100395
+ if (child.data?.reparseSource)
100396
+ stampReparseSource(child.children, child.data.reparseSource);
100312
100397
  return child.children;
100313
100398
  }
100314
100399
  return [child];
@@ -100904,9 +100989,10 @@ const findTableRanges = (html) => {
100904
100989
  * The surrounding raw HTML (the wrapper's open/close tags) would be re-nested
100905
100990
  * around the parsed tables by rehype-raw.
100906
100991
  *
100907
- * Returns null when there is no wrapped table to extract.
100992
+ * Returns null when there is no wrapped table to extract. `source` is the string the node's
100993
+ * positions index into, so the parts' positions survive stripped container prefixes.
100908
100994
  */
100909
- const splitHtmlWithNestedTables = (node) => {
100995
+ const splitHtmlWithNestedTables = (node, source) => {
100910
100996
  const { value } = node;
100911
100997
  // This is a top-level table, so we don't need to split it
100912
100998
  if (TOP_LEVEL_TABLE_TAG_RE.test(value))
@@ -100919,13 +101005,11 @@ const splitHtmlWithNestedTables = (node) => {
100919
101005
  const ranges = findTableRanges(value);
100920
101006
  if (ranges.length === 0)
100921
101007
  return null;
100922
- const base = node.position?.start;
101008
+ const toSourcePoint = createValueToSourceMapper(node.position, value, source);
100923
101009
  const sliceToHtml = (from, to) => ({
100924
101010
  type: 'html',
100925
101011
  value: value.slice(from, to),
100926
- ...(base && {
100927
- position: { start: pointAfter(base, value.slice(0, from)), end: pointAfter(base, value.slice(0, to)) },
100928
- }),
101012
+ ...(toSourcePoint && { position: { start: toSourcePoint(from), end: toSourcePoint(to) } }),
100929
101013
  });
100930
101014
  const parts = [];
100931
101015
  let cursor = 0;
@@ -100960,6 +101044,8 @@ const splitHtmlWithNestedTables = (node) => {
100960
101044
 
100961
101045
 
100962
101046
 
101047
+
101048
+
100963
101049
 
100964
101050
 
100965
101051
 
@@ -101012,7 +101098,7 @@ const tableRepairs = [
101012
101098
  * The plugins in the processor allows parsing markdown & special syntax inside the table cells
101013
101099
  * After parsing, we need to update the node positions
101014
101100
  */
101015
- const parseTableNode = (processor, node, repair) => {
101101
+ const parseTableNode = (processor, node, source, repair) => {
101016
101102
  let parsed;
101017
101103
  try {
101018
101104
  parsed = processor.runSync(processor.parse(node.value));
@@ -101026,19 +101112,18 @@ const parseTableNode = (processor, node, repair) => {
101026
101112
  if (repair) {
101027
101113
  remapPositionsThroughLayers(parsed, repair.originalSource, repair.layers);
101028
101114
  }
101029
- // The subparser produces positions relative to `node.value`; shift them by
101030
- // the outer node's offset/line so consumers can slice the full source.
101031
- const baseOffset = node.position?.start?.offset ?? 0;
101032
- const baseLine = (node.position?.start?.line ?? 1) - 1;
101115
+ // The subparser produces positions relative to `node.value`; map them into
101116
+ // the outer source so consumers can slice it.
101117
+ const toSourcePoint = createValueToSourceMapper(node.position, repair?.originalSource ?? node.value, source);
101118
+ if (!toSourcePoint)
101119
+ return parsed;
101033
101120
  visit(parsed, child => {
101034
- if (child.position?.start) {
101035
- child.position.start.offset = (child.position.start.offset ?? 0) + baseOffset;
101036
- child.position.start.line += baseLine;
101037
- }
101038
- if (child.position?.end) {
101039
- child.position.end.offset = (child.position.end.offset ?? 0) + baseOffset;
101040
- child.position.end.line += baseLine;
101041
- }
101121
+ if (!child.position)
101122
+ return;
101123
+ child.position = {
101124
+ start: toSourcePoint(child.position.start.offset ?? 0),
101125
+ end: toSourcePoint(child.position.end.offset ?? 0),
101126
+ };
101042
101127
  });
101043
101128
  return parsed;
101044
101129
  };
@@ -101068,12 +101153,10 @@ const hasFlowContent = (nodes) => {
101068
101153
  return nodes.some(node => !phrasing(node) && node.type !== 'paragraph');
101069
101154
  };
101070
101155
  /**
101071
- * Process a Table node: re-parse text-only cell content, then output as
101072
- * a markdown table (phrasing-only) or keep as JSX <Table> (has flow content).
101156
+ * Process a Table node: re-parse text-only cell content, then return it as
101157
+ * a markdown table (phrasing-only) or keep it as JSX <Table> (has flow content).
101073
101158
  */
101074
- const processTableNode = (node, index, parent, documentPosition) => {
101075
- if (node.name !== 'Table' && node.name !== 'table')
101076
- return;
101159
+ const processTableNode = (node, documentPosition) => {
101077
101160
  const position = documentPosition ?? node.position;
101078
101161
  const { align: alignAttr } = getAttrs(node);
101079
101162
  const align = Array.isArray(alignAttr) ? alignAttr : null;
@@ -101100,6 +101183,8 @@ const processTableNode = (node, index, parent, documentPosition) => {
101100
101183
  try {
101101
101184
  const parsed = tableNodeProcessor.runSync(tableNodeProcessor.parse(textContent));
101102
101185
  if (parsed.children.length > 0) {
101186
+ // Positions index into the extracted text rather than the table source (CX-4004).
101187
+ stampReparseSource(parsed.children, textContent);
101103
101188
  cell.children = parsed.children;
101104
101189
  if (hasFlowContent(parsed.children)) {
101105
101190
  tableHasFlowContent = true;
@@ -101142,11 +101227,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
101142
101227
  : unwrapParagraphNodes(el.children);
101143
101228
  el.children = removeWhitespaceOnlyTextNodes(unwrapped);
101144
101229
  });
101145
- parent.children[index] = {
101146
- ...node,
101147
- position,
101148
- };
101149
- return;
101230
+ return { ...node, position };
101150
101231
  }
101151
101232
  // All cells are phrasing-only — convert to markdown table
101152
101233
  const children = [];
@@ -101224,7 +101305,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
101224
101305
  const alignArray = align && columnCount > 0
101225
101306
  ? align.slice(0, columnCount).concat(new Array(Math.max(0, columnCount - align.length)).fill(null))
101226
101307
  : new Array(columnCount).fill(null);
101227
- const mdNode = {
101308
+ return {
101228
101309
  align: alignArray,
101229
101310
  type: 'table',
101230
101311
  position,
@@ -101232,14 +101313,13 @@ const processTableNode = (node, index, parent, documentPosition) => {
101232
101313
  // Remember the author's spelling so the serializer can write `<table>` back instead of `<Table>`
101233
101314
  ...(node.name === 'table' && { data: { lowercaseTable: true } }),
101234
101315
  };
101235
- parent.children[index] = mdNode;
101236
101316
  };
101237
101317
  /**
101238
101318
  * Apply `tableRepairs` cumulatively, re-parsing after every change and stopping
101239
101319
  * once the accumulated result parses. Each layer's inserts are relative to the
101240
101320
  * string that repair received, so they stay ordered for position remapping.
101241
101321
  */
101242
- const repairAndReparse = (node) => {
101322
+ const repairAndReparse = (node, source) => {
101243
101323
  let repairedValue = node.value;
101244
101324
  const layers = [];
101245
101325
  let parsed;
@@ -101249,11 +101329,45 @@ const repairAndReparse = (node) => {
101249
101329
  return false;
101250
101330
  repairedValue = value;
101251
101331
  layers.push(inserts);
101252
- parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, { layers, originalSource: node.value });
101332
+ parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, source, {
101333
+ layers,
101334
+ originalSource: node.value,
101335
+ });
101253
101336
  return Boolean(parsed);
101254
101337
  });
101255
101338
  return parsed;
101256
101339
  };
101340
+ /**
101341
+ * Re-parse a table html node and replace it with a markdown / JSX table, or the
101342
+ * fallback parse's fragments for a lowercase table mdxjs rejects.
101343
+ */
101344
+ const replaceTableHtml = (node, index, parent, source) => {
101345
+ // Because the processor uses remarkMdx, it is stricter in what it accepts
101346
+ // and only accepts valid MDX syntax in the table node. To get around that,
101347
+ // fall back to the cumulative repairs when the first parse fails.
101348
+ const parsed = parseTableNode(tableNodeProcessor, node, source) ?? repairAndReparse(node, source);
101349
+ if (parsed) {
101350
+ // If the table is parsed successfully, we can now process it further
101351
+ // to build on the markdown / JSX table
101352
+ visit(parsed, isMDXElement, (tableNode) => {
101353
+ if (tableNode.name !== 'Table' && tableNode.name !== 'table')
101354
+ return undefined;
101355
+ replaceInheritingReparseSource(parent, index, [processTableNode(tableNode, node.position)]);
101356
+ return (/* inlined export .EXIT */false);
101357
+ });
101358
+ }
101359
+ else if (node.value.startsWith('<table')) {
101360
+ // If the parsing still fails, give an opportunity to the fallback parser
101361
+ // without remarkMdx to process lowercase tables as it's likely to not
101362
+ // have needed MDX parsing anyway
101363
+ const fallback = parseTableNode(fallbackTableNodeProcessor, node, source);
101364
+ if (!fallback || fallback.children.length <= 1)
101365
+ return;
101366
+ replaceInheritingReparseSource(parent, index, fallback.children);
101367
+ }
101368
+ // Otherwise, there's no point in trying to parse the table content further
101369
+ // More repairs are needed in that case
101370
+ };
101257
101371
  /**
101258
101372
  * Converts JSX Table elements to markdown table nodes and re-parses markdown in cells.
101259
101373
  *
@@ -101265,24 +101379,26 @@ const repairAndReparse = (node) => {
101265
101379
  * When cell content contains block-level nodes (callouts, code blocks, etc.), the table
101266
101380
  * is kept as a JSX <Table> element so that remarkRehype can properly handle the flow content.
101267
101381
  */
101268
- const mdxishTables = () => tree => {
101382
+ const mdxishTables = () => (tree, file) => {
101383
+ // Positions index into the document unless a re-parse stamped another source.
101384
+ const documentSource = file?.value ? String(file.value) : undefined;
101269
101385
  // Pre-pass: lift `<table>`s wrapped in a raw HTML block out into their own
101270
101386
  // html nodes so the main pass below treats them like top-level tables.
101271
- visit(tree, 'html', (_node, index, parent) => {
101272
- const node = _node;
101273
- if (typeof index !== 'number' || !parent || !('children' in parent))
101387
+ visitParents(tree, 'html', (node, ancestors) => {
101388
+ const parent = ancestors[ancestors.length - 1];
101389
+ if (!parent)
101274
101390
  return;
101275
- const parts = splitHtmlWithNestedTables(node);
101391
+ const parts = splitHtmlWithNestedTables(node, resolveReparseSource(node, ancestors, documentSource));
101276
101392
  if (!parts)
101277
101393
  return;
101278
101394
  // The inserted parts can't re-trigger a split (table parts start with
101279
101395
  // `<table`; the wrapper slices hold no table), so plain in-place splicing
101280
101396
  // visits each once without looping.
101281
- parent.children.splice(index, 1, ...parts);
101397
+ replaceInheritingReparseSource(parent, parent.children.indexOf(node), parts);
101282
101398
  });
101283
- visit(tree, 'html', (_node, index, parent) => {
101284
- const node = _node;
101285
- if (typeof index !== 'number' || !parent || !('children' in parent))
101399
+ visitParents(tree, 'html', (node, ancestors) => {
101400
+ const parent = ancestors[ancestors.length - 1];
101401
+ if (!parent)
101286
101402
  return;
101287
101403
  if (!node.value.startsWith('<Table') && !node.value.startsWith('<table'))
101288
101404
  return;
@@ -101290,33 +101406,8 @@ const mdxishTables = () => tree => {
101290
101406
  // paragraph. Leave them untouched so rehype-raw can reassemble the table.
101291
101407
  if (parent.type === 'paragraph')
101292
101408
  return;
101293
- // Because the processor uses remarkMdx, it is stricter in what it accepts
101294
- // and only accepts valid MDX syntax in the table node. To get around that,
101295
- // fall back to the cumulative repairs when the first parse fails.
101296
- const parsed = parseTableNode(tableNodeProcessor, node) ?? repairAndReparse(node);
101297
- if (parsed) {
101298
- // If the table is parsed successfully, we can now process it further
101299
- // to build on the markdown / JSX table
101300
- visit(parsed, isMDXElement, (tableNode) => {
101301
- if (tableNode.name !== 'Table' && tableNode.name !== 'table')
101302
- return undefined;
101303
- processTableNode(tableNode, index, parent, node.position);
101304
- return (/* inlined export .EXIT */false);
101305
- });
101306
- }
101307
- else if (node.value.startsWith('<table')) {
101308
- // If the parsing still fails, give an opportunity to the fallback parser
101309
- // without remarkMdx to process lowercase tables as it's likely to not
101310
- // have needed MDX parsing anyway
101311
- const fallback = parseTableNode(fallbackTableNodeProcessor, node);
101312
- if (!fallback || fallback.children.length <= 1)
101313
- return;
101314
- parent.children.splice(index, 1, ...fallback.children);
101315
- }
101316
- // Otherwise, there's no point in trying to parse the table content further
101317
- // More repairs are needed in that case
101409
+ replaceTableHtml(node, parent.children.indexOf(node), parent, resolveReparseSource(node, ancestors, documentSource));
101318
101410
  });
101319
- return tree;
101320
101411
  };
101321
101412
  /* harmony default export */ const mdxish_tables = (mdxishTables);
101322
101413
 
@@ -124071,32 +124162,6 @@ const mdxComponentHandlers = {
124071
124162
  [NodeTypes.htmlBlock]: htmlBlockHandler,
124072
124163
  };
124073
124164
 
124074
- ;// ./processor/plugin/safe-mode-html-blocks.ts
124075
-
124076
-
124077
- /**
124078
- * Whether a tag name renders through the `HTMLBlock` component. Mirrors the
124079
- * separator-agnostic, case-insensitive lookup in `getComponentName` and the
124080
- * rehype-react component map, so `html-block`, `HTMLBlock`, `HtmlBlock` and
124081
- * `htmlblock` all match.
124082
- */
124083
- const isHtmlBlockTag = (tagName) => toPascalCase(tagName).toLowerCase() === 'htmlblock';
124084
- /**
124085
- * Forces `safeMode` on every element that renders through `HTMLBlock` so it is
124086
- * shown as escaped text instead of injected.
124087
- *
124088
- * Runs last, so it sees every producer of the element — `[block:html]`,
124089
- * `<HTMLBlock>` with a template body or an `html` attribute, and a literal
124090
- * `<html-block>` — and it is unconditional so an author-supplied
124091
- * `safeMode="false"` can't opt out.
124092
- */
124093
- const enforceSafeModeHtmlBlocks = () => tree => {
124094
- visit(tree, 'element', node => {
124095
- if (isHtmlBlockTag(node.tagName))
124096
- node.properties.safeMode = 'true';
124097
- });
124098
- };
124099
-
124100
124165
  ;// ./processor/transform/mdxish/anchor-to-jsx.ts
124101
124166
 
124102
124167
 
@@ -124150,9 +124215,9 @@ const mdxishCalloutToJsx = () => tree => {
124150
124215
  visit(tree, NodeTypes.callout, (node, index, parent) => {
124151
124216
  if (!parent || index === undefined)
124152
124217
  return;
124153
- let { icon, theme } = node.data.hProperties;
124154
- if (!icon && theme)
124155
- icon = defaultIcons[theme];
124218
+ // No default-icon fill: an empty `icon` means the author removed it
124219
+ const { icon } = node.data.hProperties;
124220
+ let { theme } = node.data.hProperties;
124156
124221
  if (!theme && icon)
124157
124222
  theme = themes[icon] || 'default';
124158
124223
  // Mutate in place to keep the children array identity so nested callouts in
@@ -124703,18 +124768,6 @@ const getInlineMdProcessor = ({ safeMode = false } = {}) => {
124703
124768
  }
124704
124769
  return processor;
124705
124770
  };
124706
- /**
124707
- * Mark re-parsed subtree roots with the string their positions index into, so consumers
124708
- * slicing by offset use the right source (see `Data.reparseSource`). Only roots are
124709
- * stamped; descendants resolve via their nearest stamped ancestor. Roots a deeper
124710
- * re-parse already stamped keep their own string.
124711
- */
124712
- const stampReparseSource = (roots, reparseSource) => {
124713
- roots.forEach(root => {
124714
- if (!root.data?.reparseSource)
124715
- root.data = { ...root.data, reparseSource };
124716
- });
124717
- };
124718
124771
  /**
124719
124772
  * True when a tag name starts with an uppercase letter — ReadMe's marker for
124720
124773
  * a custom MDX component (vs a lowercase HTML tag).
@@ -124801,6 +124854,7 @@ function findBalancedClosingTagIndex(content, tag) {
124801
124854
 
124802
124855
 
124803
124856
 
124857
+
124804
124858
  /**
124805
124859
  * Parse the body of an inline component as phrasing content. Remark always
124806
124860
  * wraps bare text in a paragraph; flatten that single-paragraph wrapper so
@@ -125052,6 +125106,7 @@ function terminateHtmlFlowBlocks(content) {
125052
125106
 
125053
125107
 
125054
125108
 
125109
+
125055
125110
  // Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. One name
125056
125111
  // char suffices for existence — `[\w-]+` backtracked quadratically over huge attributes.
125057
125112
  const NESTED_ATTR_EXPRESSION_RE = /[\w-]\s*=\s*\{/;
@@ -125133,26 +125188,12 @@ const parseSibling = (parent, index, sibling, safeMode, promoted) => {
125133
125188
  }
125134
125189
  };
125135
125190
  // Ends the position at `consumedLength` so the component doesn't claim trailing
125136
- // content the tokenizer swallowed into the same html node. Measured against the source
125137
- // when available: each value line is its source line minus the container prefix
125138
- // (list indent, `> `) micromark stripped, so those prefixes are counted back in.
125191
+ // content the tokenizer swallowed into the same html node.
125139
125192
  const positionEndingAtConsumed = (nodePosition, value, consumedLength, source) => {
125140
- if (!nodePosition?.start)
125193
+ const toSourcePoint = createValueToSourceMapper(nodePosition, value, source);
125194
+ if (!nodePosition || !toSourcePoint)
125141
125195
  return nodePosition;
125142
- const consumedValue = value.slice(0, consumedLength);
125143
- const sourceLines = source?.slice(nodePosition.start.offset, nodePosition.end?.offset).split('\n');
125144
- const valueLines = value.split('\n');
125145
- if (!sourceLines || sourceLines.length !== valueLines.length) {
125146
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedValue) };
125147
- }
125148
- const consumedLines = consumedValue.split('\n');
125149
- const lastLineIndex = consumedLines.length - 1;
125150
- const prefixWidth = sourceLines[lastLineIndex].length - valueLines[lastLineIndex].length;
125151
- const consumedSource = [
125152
- ...sourceLines.slice(0, lastLineIndex),
125153
- sourceLines[lastLineIndex].slice(0, prefixWidth + consumedLines[lastLineIndex].length),
125154
- ].join('\n');
125155
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedSource) };
125196
+ return { start: nodePosition.start, end: toSourcePoint(consumedLength) };
125156
125197
  };
125157
125198
  const createComponentNode = ({ tag, attributes, children, startPosition, endPosition, }) => ({
125158
125199
  type: 'mdxJsxFlowElement',
@@ -125164,14 +125205,6 @@ const createComponentNode = ({ tag, attributes, children, startPosition, endPosi
125164
125205
  end: endPosition?.end ?? startPosition?.end,
125165
125206
  },
125166
125207
  });
125167
- // The promoted node takes over the html node's position, so it also takes over the
125168
- // coordinate space that position belongs to.
125169
- const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
125170
- const replacedSource = parent.children[index]?.data?.reparseSource;
125171
- if (replacedSource)
125172
- stampReparseSource([mdxNode], replacedSource);
125173
- parent.children.splice(index, 1, mdxNode);
125174
- };
125175
125208
  /**
125176
125209
  * Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
125177
125210
  *
@@ -125270,7 +125303,7 @@ function promoteComponentBlocks(tree, safeMode, source) {
125270
125303
  ? positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd, source)
125271
125304
  : node.position,
125272
125305
  });
125273
- substituteNodeWithMdxNode(parent, index, componentNode);
125306
+ replaceInheritingReparseSource(parent, index, [componentNode]);
125274
125307
  if (remainingContent) {
125275
125308
  parseSibling(parent, index, remainingContent, safeMode, promoted);
125276
125309
  }
@@ -125321,7 +125354,7 @@ function promoteComponentBlocks(tree, safeMode, source) {
125321
125354
  startPosition: node.position,
125322
125355
  endPosition,
125323
125356
  });
125324
- substituteNodeWithMdxNode(parent, index, componentNode);
125357
+ replaceInheritingReparseSource(parent, index, [componentNode]);
125325
125358
  // The unwrap reparented the children out of their paragraph, so re-walk them
125326
125359
  // since the children HTML may contain promotable syntax (e.g. `{…}`-attr tags)
125327
125360
  if (unwrappedSoleParagraph) {
@@ -126404,7 +126437,7 @@ const parseApiHeaderTitle = (text) => {
126404
126437
  * Transform a magicBlock node into final MDAST nodes.
126405
126438
  */
126406
126439
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
126407
- const { compatibilityMode = false, hardBreaks = true } = options;
126440
+ const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
126408
126441
  // Handle empty data by returning placeholder nodes for known block types
126409
126442
  // This allows the editor to show appropriate placeholder UI instead of nothing
126410
126443
  if (Object.keys(data).length < 1) {
@@ -126622,7 +126655,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
126622
126655
  wrapPinnedBlocks({
126623
126656
  data: {
126624
126657
  hName: 'html-block',
126625
- hProperties: { html: htmlJson.html, runScripts: compatibilityMode },
126658
+ hProperties: { html: htmlJson.html, runScripts: compatibilityMode, safeMode },
126626
126659
  },
126627
126660
  type: 'html-block',
126628
126661
  }, data),
@@ -126763,6 +126796,7 @@ const magicBlockTransformer = (options = {}) => tree => {
126763
126796
 
126764
126797
 
126765
126798
 
126799
+
126766
126800
  // `<HTMLBlock …>{`…`}</HTMLBlock>` embedded inside a raw HTML block (e.g. a
126767
126801
  // single-line `<div>…</div>`). CommonMark slurps the whole div as one `html`
126768
126802
  // node, so the tokenizer never sees the HTMLBlock — we recover it here.
@@ -126869,7 +126903,8 @@ const mdxishHtmlBlocks = () => tree => {
126869
126903
  return;
126870
126904
  const exprChild = element.children.find(child => child.type === 'mdxFlowExpression' || child.type === 'mdxTextExpression');
126871
126905
  const openingTagIndent = (element.position?.start.column ?? 1) - 1;
126872
- parent.children[index] = createHtmlBlockNode(formatHtmlForMdxish(extractTemplateLiteral(exprChild?.value), openingTagIndent), element.position, toRunScripts(jsxAttr(element, 'runScripts')), jsxAttr(element, 'safeMode'));
126906
+ const htmlBlock = createHtmlBlockNode(formatHtmlForMdxish(extractTemplateLiteral(exprChild?.value), openingTagIndent), element.position, toRunScripts(jsxAttr(element, 'runScripts')), jsxAttr(element, 'safeMode'));
126907
+ replaceInheritingReparseSource(parent, index, [htmlBlock]);
126873
126908
  });
126874
126909
  // Shape 2: raw HTML blob.
126875
126910
  visit(tree, 'html', (node, index, parent) => {
@@ -126877,7 +126912,7 @@ const mdxishHtmlBlocks = () => tree => {
126877
126912
  return;
126878
126913
  const replacement = splitRawHtmlBlocks(node);
126879
126914
  if (replacement)
126880
- parent.children.splice(index, 1, ...replacement);
126915
+ replaceInheritingReparseSource(parent, index, replacement);
126881
126916
  });
126882
126917
  };
126883
126918
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
@@ -126964,6 +126999,7 @@ const hasOnlyWidthAttributes = (cell) => {
126964
126999
 
126965
127000
 
126966
127001
 
127002
+
126967
127003
  function toImageAlign(value) {
126968
127004
  if (value === 'left' || value === 'center' || value === 'right') {
126969
127005
  return value;
@@ -127179,6 +127215,15 @@ const transformAnchor = (jsx) => {
127179
127215
  position: jsx.position,
127180
127216
  };
127181
127217
  };
127218
+ /**
127219
+ * Parses an image caption's markdown. The caption is re-parsed on its own, so the
127220
+ * children's positions index into it rather than the document.
127221
+ */
127222
+ const parseCaptionChildren = (caption) => {
127223
+ const { children } = lib_mdast(caption);
127224
+ stampReparseSource(children, caption);
127225
+ return children;
127226
+ };
127182
127227
  /**
127183
127228
  * Transforms an `<Image />` JSX element into an image-block MDAST node.
127184
127229
  * Normalizes attributes (align, border, width→sizing) and parses caption markdown into children.
@@ -127209,7 +127254,7 @@ const transformImage = (jsx) => {
127209
127254
  alt,
127210
127255
  border: toBool(border),
127211
127256
  caption,
127212
- children: caption ? lib_mdast(caption).children : [],
127257
+ children: caption ? parseCaptionChildren(caption) : [],
127213
127258
  className,
127214
127259
  framed: toBool(framed),
127215
127260
  height: height !== undefined ? String(height) : undefined,
@@ -127546,8 +127591,7 @@ const mdxishJsxToMdast = () => tree => {
127546
127591
  const newNode = transformer(node);
127547
127592
  if (!newNode)
127548
127593
  return;
127549
- // Replace the JSX node with the MDAST node
127550
- parent.children[index] = newNode;
127594
+ replaceInheritingReparseSource(parent, index, [newNode]);
127551
127595
  });
127552
127596
  // Inline JSX components (Anchor)
127553
127597
  visit(tree, 'mdxJsxTextElement', (node, index, parent) => {
@@ -128457,7 +128501,6 @@ function loadComponents() {
128457
128501
 
128458
128502
 
128459
128503
 
128460
-
128461
128504
 
128462
128505
 
128463
128506
  const defaultTransformers = [
@@ -128613,8 +128656,7 @@ function mdxish(mdContent, opts = {}) {
128613
128656
  .use(rehypeMdxishComponents, {
128614
128657
  components,
128615
128658
  processMarkdown: (markdown) => mdxish(markdown, opts),
128616
- })
128617
- .use(safeMode ? enforceSafeModeHtmlBlocks : undefined); // Force safeMode on every HTMLBlock; runs last so every producer is covered
128659
+ });
128618
128660
  const vfile = new VFile({ value: parserReadyContent });
128619
128661
  const mdast = processor.parse(parserReadyContent);
128620
128662
  const hast = processor.runSync(mdast, vfile);
@@ -129645,7 +129687,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
129645
129687
  /******/ // startup
129646
129688
  /******/ // Load entry module and return exports
129647
129689
  /******/ // This entry module used 'module' so it can't be inlined
129648
- /******/ let __webpack_exports__ = __webpack_require__(5789);
129690
+ /******/ let __webpack_exports__ = __webpack_require__(6831);
129649
129691
  /******/ module.exports = __webpack_exports__;
129650
129692
  /******/
129651
129693
  /******/ })()