@readme/markdown 15.9.0 → 15.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -11423,7 +11423,7 @@ module.exports = function () {
11423
11423
 
11424
11424
  /***/ },
11425
11425
 
11426
- /***/ 9171
11426
+ /***/ 8846
11427
11427
  (module, __webpack_exports__, __webpack_require__) {
11428
11428
 
11429
11429
  "use strict";
@@ -12154,11 +12154,12 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
12154
12154
  // In MDX mode, safeMode is passed in as a boolean from JSX parsing
12155
12155
  // In MDXish mode, safeMode comes in as a string from HAST props
12156
12156
  const safeMode = typeof safeModeRaw !== 'boolean' ? safeModeRaw === 'true' : safeModeRaw;
12157
- const [cleanedHtml, exec] = extractScripts(html);
12157
+ // Memoised so `exec` is stable across rerenders and the effect below only runs when the html changes.
12158
+ const [cleanedHtml, exec] = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useMemo)(() => extractScripts(html), [html]);
12158
12159
  (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
12159
- if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts && !safeMode)
12160
+ if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
12160
12161
  exec();
12161
- }, [runScripts, safeMode, exec]);
12162
+ }, [runScripts, exec]);
12162
12163
  if (nonStringChildren) {
12163
12164
  // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
12164
12165
  // raw string) should never throw, so render the child nodes directly
@@ -54965,18 +54966,53 @@ function evaluate(source, scope = {}) {
54965
54966
  return new Function(...names, `return (${source})`)(...values);
54966
54967
  }
54967
54968
  /**
54968
- * Advance a `Point` by the `consumed` substring that follows it, returning the
54969
- * point at the consumed string's end. Lets split-out sub-nodes carry accurate
54970
- * document positions so downstream offset shifting stays correct.
54969
+ * Width each container prefix adds back per line of `value`, aligned from the line end since a
54970
+ * tab in the prefix is expanded to spaces in `value`. None (a verbatim slice) when the source
54971
+ * is missing or doesn't line up.
54971
54972
  */
54972
- const pointAfter = (start, consumed) => {
54973
- const newlineIndex = consumed.lastIndexOf('\n');
54974
- const newlineCount = newlineIndex === -1 ? 0 : consumed.split('\n').length - 1;
54975
- return {
54976
- line: start.line + newlineCount,
54977
- // Same line → advance the base column; a later line → column is the run since its newline.
54978
- column: newlineCount === 0 ? start.column + consumed.length : consumed.length - newlineIndex,
54979
- offset: (start.offset ?? 0) + consumed.length,
54973
+ const containerPrefixWidths = (valueLines, source, position) => {
54974
+ const sourceLines = source?.slice(position.start.offset, position.end.offset).split('\n');
54975
+ const linesUp = sourceLines?.length === valueLines.length &&
54976
+ sourceLines.every((line, i) => line.endsWith(valueLines[i].trimStart()));
54977
+ return valueLines.map((line, i) => (linesUp ? sourceLines[i].length - line.length : 0));
54978
+ };
54979
+ /**
54980
+ * Maps offsets in a node's `value` to points in `source`. Containers strip a prefix from every
54981
+ * continuation line of `value`, so a plain offset shift drifts by line (CX-4028).
54982
+ */
54983
+ const createValueToSourceMapper = (position, value, source) => {
54984
+ if (position?.start.offset === undefined)
54985
+ return null;
54986
+ const { start } = position;
54987
+ const valueLines = value.split('\n');
54988
+ const prefixWidths = containerPrefixWidths(valueLines, source, position);
54989
+ const lines = [];
54990
+ let valueStart = 0;
54991
+ let sourceStart = start.offset;
54992
+ valueLines.forEach((line, i) => {
54993
+ lines.push({ prefixWidth: prefixWidths[i], sourceStart, valueStart });
54994
+ valueStart += line.length + 1;
54995
+ sourceStart += prefixWidths[i] + line.length + 1;
54996
+ });
54997
+ return valueOffset => {
54998
+ // Binary search: a large table maps one point per node.
54999
+ let low = 0;
55000
+ let high = lines.length - 1;
55001
+ while (low < high) {
55002
+ const mid = Math.ceil((low + high) / 2);
55003
+ if (lines[mid].valueStart <= valueOffset)
55004
+ low = mid;
55005
+ else
55006
+ high = mid - 1;
55007
+ }
55008
+ const { prefixWidth, sourceStart: lineSourceStart, valueStart: lineValueStart } = lines[low];
55009
+ // Clamped: an expanded tab can make a leading-whitespace offset fall before the line.
55010
+ const sourceColumn = Math.max(0, prefixWidth + valueOffset - lineValueStart);
55011
+ return {
55012
+ line: start.line + low,
55013
+ column: (low === 0 ? start.column : 1) + sourceColumn,
55014
+ offset: lineSourceStart + sourceColumn,
55015
+ };
54980
55016
  };
54981
55017
  };
54982
55018
  /**
@@ -55639,7 +55675,9 @@ const processBlockquote = (node, index, parent, isMdxish = false) => {
55639
55675
  }
55640
55676
  Object.assign(node, {
55641
55677
  type: NodeTypes.callout,
55678
+ // Keep the blockquote's data, e.g. the `reparseSource` its positions index into.
55642
55679
  data: {
55680
+ ...node.data,
55643
55681
  hName: 'Callout',
55644
55682
  hProperties: {
55645
55683
  icon,
@@ -55672,14 +55710,55 @@ const calloutTransformer = ({ isMdxish = false } = {}) => {
55672
55710
  };
55673
55711
  /* harmony default export */ const callouts = (calloutTransformer);
55674
55712
 
55713
+ ;// ./processor/transform/mdxish/reparse-source.ts
55714
+ /**
55715
+ * Mark re-parsed subtree roots with the string their positions index into, so consumers
55716
+ * slicing by offset use the right source (see `Data.reparseSource`). Only roots are
55717
+ * stamped; descendants resolve via their nearest stamped ancestor. Roots a deeper
55718
+ * re-parse already stamped keep their own string.
55719
+ */
55720
+ const stampReparseSource = (roots, reparseSource) => {
55721
+ roots.forEach(root => {
55722
+ if (!root.data?.reparseSource)
55723
+ root.data = { ...root.data, reparseSource };
55724
+ });
55725
+ };
55726
+ /**
55727
+ * Splice `replacements` over `parent.children[index]`. They take over the replaced node's
55728
+ * position, so they also take over the coordinate space that position indexes into.
55729
+ */
55730
+ const replaceInheritingReparseSource = (parent, index, replacements) => {
55731
+ const replacedSource = parent.children[index]?.data?.reparseSource;
55732
+ if (replacedSource)
55733
+ stampReparseSource(replacements, replacedSource);
55734
+ parent.children.splice(index, 1, ...replacements);
55735
+ };
55736
+ /**
55737
+ * The string `node`'s offsets index into: the nearest stamp on it or an ancestor, else the
55738
+ * document source.
55739
+ */
55740
+ const resolveReparseSource = (node, ancestors, documentSource) => {
55741
+ if (node.data?.reparseSource)
55742
+ return node.data.reparseSource;
55743
+ for (let i = ancestors.length - 1; i >= 0; i -= 1) {
55744
+ const { reparseSource } = ancestors[i].data ?? {};
55745
+ if (reparseSource)
55746
+ return reparseSource;
55747
+ }
55748
+ return documentSource;
55749
+ };
55750
+
55675
55751
  ;// ./processor/transform/code-tabs.ts
55676
55752
 
55677
55753
 
55754
+
55678
55755
  const isCode = (node) => node?.type === 'code';
55679
55756
  const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
55680
55757
  visit(tree, 'code', (node) => {
55681
55758
  const { lang, meta, value } = node;
55682
55759
  node.data = {
55760
+ // Ensure positions are passed through
55761
+ ...node.data,
55683
55762
  hProperties: { lang, meta, value, copyButtons },
55684
55763
  };
55685
55764
  });
@@ -55726,6 +55805,9 @@ const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
55726
55805
  end: children[children.length - 1].position.end,
55727
55806
  },
55728
55807
  };
55808
+ // Adjacent siblings share a coordinate space, so the wrapper takes the first block's.
55809
+ if (node.data?.reparseSource)
55810
+ stampReparseSource([codeTabs], node.data.reparseSource);
55729
55811
  parent.children.splice(index, children.length, codeTabs);
55730
55812
  });
55731
55813
  return tree;
@@ -80108,6 +80190,7 @@ const walkTags = (html, handlers) => {
80108
80190
  };
80109
80191
 
80110
80192
  ;// ./processor/transform/mdxish/tables/utils.ts
80193
+
80111
80194
  const tableTags = new Set([
80112
80195
  'thead',
80113
80196
  'tbody',
@@ -80126,6 +80209,9 @@ const tableTags = new Set([
80126
80209
  const unwrapParagraphNodes = (children) => {
80127
80210
  return children.flatMap(child => {
80128
80211
  if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
80212
+ // The unwrap drops a stamped root, so its children inherit that coordinate space.
80213
+ if (child.data?.reparseSource)
80214
+ stampReparseSource(child.children, child.data.reparseSource);
80129
80215
  return child.children;
80130
80216
  }
80131
80217
  return [child];
@@ -80721,9 +80807,10 @@ const findTableRanges = (html) => {
80721
80807
  * The surrounding raw HTML (the wrapper's open/close tags) would be re-nested
80722
80808
  * around the parsed tables by rehype-raw.
80723
80809
  *
80724
- * Returns null when there is no wrapped table to extract.
80810
+ * Returns null when there is no wrapped table to extract. `source` is the string the node's
80811
+ * positions index into, so the parts' positions survive stripped container prefixes.
80725
80812
  */
80726
- const splitHtmlWithNestedTables = (node) => {
80813
+ const splitHtmlWithNestedTables = (node, source) => {
80727
80814
  const { value } = node;
80728
80815
  // This is a top-level table, so we don't need to split it
80729
80816
  if (TOP_LEVEL_TABLE_TAG_RE.test(value))
@@ -80736,13 +80823,11 @@ const splitHtmlWithNestedTables = (node) => {
80736
80823
  const ranges = findTableRanges(value);
80737
80824
  if (ranges.length === 0)
80738
80825
  return null;
80739
- const base = node.position?.start;
80826
+ const toSourcePoint = createValueToSourceMapper(node.position, value, source);
80740
80827
  const sliceToHtml = (from, to) => ({
80741
80828
  type: 'html',
80742
80829
  value: value.slice(from, to),
80743
- ...(base && {
80744
- position: { start: pointAfter(base, value.slice(0, from)), end: pointAfter(base, value.slice(0, to)) },
80745
- }),
80830
+ ...(toSourcePoint && { position: { start: toSourcePoint(from), end: toSourcePoint(to) } }),
80746
80831
  });
80747
80832
  const parts = [];
80748
80833
  let cursor = 0;
@@ -80777,6 +80862,8 @@ const splitHtmlWithNestedTables = (node) => {
80777
80862
 
80778
80863
 
80779
80864
 
80865
+
80866
+
80780
80867
 
80781
80868
 
80782
80869
 
@@ -80829,7 +80916,7 @@ const tableRepairs = [
80829
80916
  * The plugins in the processor allows parsing markdown & special syntax inside the table cells
80830
80917
  * After parsing, we need to update the node positions
80831
80918
  */
80832
- const parseTableNode = (processor, node, repair) => {
80919
+ const parseTableNode = (processor, node, source, repair) => {
80833
80920
  let parsed;
80834
80921
  try {
80835
80922
  parsed = processor.runSync(processor.parse(node.value));
@@ -80843,19 +80930,18 @@ const parseTableNode = (processor, node, repair) => {
80843
80930
  if (repair) {
80844
80931
  remapPositionsThroughLayers(parsed, repair.originalSource, repair.layers);
80845
80932
  }
80846
- // The subparser produces positions relative to `node.value`; shift them by
80847
- // the outer node's offset/line so consumers can slice the full source.
80848
- const baseOffset = node.position?.start?.offset ?? 0;
80849
- const baseLine = (node.position?.start?.line ?? 1) - 1;
80933
+ // The subparser produces positions relative to `node.value`; map them into
80934
+ // the outer source so consumers can slice it.
80935
+ const toSourcePoint = createValueToSourceMapper(node.position, repair?.originalSource ?? node.value, source);
80936
+ if (!toSourcePoint)
80937
+ return parsed;
80850
80938
  visit(parsed, child => {
80851
- if (child.position?.start) {
80852
- child.position.start.offset = (child.position.start.offset ?? 0) + baseOffset;
80853
- child.position.start.line += baseLine;
80854
- }
80855
- if (child.position?.end) {
80856
- child.position.end.offset = (child.position.end.offset ?? 0) + baseOffset;
80857
- child.position.end.line += baseLine;
80858
- }
80939
+ if (!child.position)
80940
+ return;
80941
+ child.position = {
80942
+ start: toSourcePoint(child.position.start.offset ?? 0),
80943
+ end: toSourcePoint(child.position.end.offset ?? 0),
80944
+ };
80859
80945
  });
80860
80946
  return parsed;
80861
80947
  };
@@ -80885,12 +80971,10 @@ const hasFlowContent = (nodes) => {
80885
80971
  return nodes.some(node => !phrasing(node) && node.type !== 'paragraph');
80886
80972
  };
80887
80973
  /**
80888
- * Process a Table node: re-parse text-only cell content, then output as
80889
- * a markdown table (phrasing-only) or keep as JSX <Table> (has flow content).
80974
+ * Process a Table node: re-parse text-only cell content, then return it as
80975
+ * a markdown table (phrasing-only) or keep it as JSX <Table> (has flow content).
80890
80976
  */
80891
- const processTableNode = (node, index, parent, documentPosition) => {
80892
- if (node.name !== 'Table' && node.name !== 'table')
80893
- return;
80977
+ const processTableNode = (node, documentPosition) => {
80894
80978
  const position = documentPosition ?? node.position;
80895
80979
  const { align: alignAttr } = getAttrs(node);
80896
80980
  const align = Array.isArray(alignAttr) ? alignAttr : null;
@@ -80917,6 +81001,8 @@ const processTableNode = (node, index, parent, documentPosition) => {
80917
81001
  try {
80918
81002
  const parsed = tableNodeProcessor.runSync(tableNodeProcessor.parse(textContent));
80919
81003
  if (parsed.children.length > 0) {
81004
+ // Positions index into the extracted text rather than the table source (CX-4004).
81005
+ stampReparseSource(parsed.children, textContent);
80920
81006
  cell.children = parsed.children;
80921
81007
  if (hasFlowContent(parsed.children)) {
80922
81008
  tableHasFlowContent = true;
@@ -80959,11 +81045,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
80959
81045
  : unwrapParagraphNodes(el.children);
80960
81046
  el.children = removeWhitespaceOnlyTextNodes(unwrapped);
80961
81047
  });
80962
- parent.children[index] = {
80963
- ...node,
80964
- position,
80965
- };
80966
- return;
81048
+ return { ...node, position };
80967
81049
  }
80968
81050
  // All cells are phrasing-only — convert to markdown table
80969
81051
  const children = [];
@@ -81041,7 +81123,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
81041
81123
  const alignArray = align && columnCount > 0
81042
81124
  ? align.slice(0, columnCount).concat(new Array(Math.max(0, columnCount - align.length)).fill(null))
81043
81125
  : new Array(columnCount).fill(null);
81044
- const mdNode = {
81126
+ return {
81045
81127
  align: alignArray,
81046
81128
  type: 'table',
81047
81129
  position,
@@ -81049,14 +81131,13 @@ const processTableNode = (node, index, parent, documentPosition) => {
81049
81131
  // Remember the author's spelling so the serializer can write `<table>` back instead of `<Table>`
81050
81132
  ...(node.name === 'table' && { data: { lowercaseTable: true } }),
81051
81133
  };
81052
- parent.children[index] = mdNode;
81053
81134
  };
81054
81135
  /**
81055
81136
  * Apply `tableRepairs` cumulatively, re-parsing after every change and stopping
81056
81137
  * once the accumulated result parses. Each layer's inserts are relative to the
81057
81138
  * string that repair received, so they stay ordered for position remapping.
81058
81139
  */
81059
- const repairAndReparse = (node) => {
81140
+ const repairAndReparse = (node, source) => {
81060
81141
  let repairedValue = node.value;
81061
81142
  const layers = [];
81062
81143
  let parsed;
@@ -81066,11 +81147,45 @@ const repairAndReparse = (node) => {
81066
81147
  return false;
81067
81148
  repairedValue = value;
81068
81149
  layers.push(inserts);
81069
- parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, { layers, originalSource: node.value });
81150
+ parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, source, {
81151
+ layers,
81152
+ originalSource: node.value,
81153
+ });
81070
81154
  return Boolean(parsed);
81071
81155
  });
81072
81156
  return parsed;
81073
81157
  };
81158
+ /**
81159
+ * Re-parse a table html node and replace it with a markdown / JSX table, or the
81160
+ * fallback parse's fragments for a lowercase table mdxjs rejects.
81161
+ */
81162
+ const replaceTableHtml = (node, index, parent, source) => {
81163
+ // Because the processor uses remarkMdx, it is stricter in what it accepts
81164
+ // and only accepts valid MDX syntax in the table node. To get around that,
81165
+ // fall back to the cumulative repairs when the first parse fails.
81166
+ const parsed = parseTableNode(tableNodeProcessor, node, source) ?? repairAndReparse(node, source);
81167
+ if (parsed) {
81168
+ // If the table is parsed successfully, we can now process it further
81169
+ // to build on the markdown / JSX table
81170
+ visit(parsed, isMDXElement, (tableNode) => {
81171
+ if (tableNode.name !== 'Table' && tableNode.name !== 'table')
81172
+ return undefined;
81173
+ replaceInheritingReparseSource(parent, index, [processTableNode(tableNode, node.position)]);
81174
+ return (/* inlined export .EXIT */false);
81175
+ });
81176
+ }
81177
+ else if (node.value.startsWith('<table')) {
81178
+ // If the parsing still fails, give an opportunity to the fallback parser
81179
+ // without remarkMdx to process lowercase tables as it's likely to not
81180
+ // have needed MDX parsing anyway
81181
+ const fallback = parseTableNode(fallbackTableNodeProcessor, node, source);
81182
+ if (!fallback || fallback.children.length <= 1)
81183
+ return;
81184
+ replaceInheritingReparseSource(parent, index, fallback.children);
81185
+ }
81186
+ // Otherwise, there's no point in trying to parse the table content further
81187
+ // More repairs are needed in that case
81188
+ };
81074
81189
  /**
81075
81190
  * Converts JSX Table elements to markdown table nodes and re-parses markdown in cells.
81076
81191
  *
@@ -81082,24 +81197,26 @@ const repairAndReparse = (node) => {
81082
81197
  * When cell content contains block-level nodes (callouts, code blocks, etc.), the table
81083
81198
  * is kept as a JSX <Table> element so that remarkRehype can properly handle the flow content.
81084
81199
  */
81085
- const mdxishTables = () => tree => {
81200
+ const mdxishTables = () => (tree, file) => {
81201
+ // Positions index into the document unless a re-parse stamped another source.
81202
+ const documentSource = file?.value ? String(file.value) : undefined;
81086
81203
  // Pre-pass: lift `<table>`s wrapped in a raw HTML block out into their own
81087
81204
  // html nodes so the main pass below treats them like top-level tables.
81088
- visit(tree, 'html', (_node, index, parent) => {
81089
- const node = _node;
81090
- if (typeof index !== 'number' || !parent || !('children' in parent))
81205
+ visitParents(tree, 'html', (node, ancestors) => {
81206
+ const parent = ancestors[ancestors.length - 1];
81207
+ if (!parent)
81091
81208
  return;
81092
- const parts = splitHtmlWithNestedTables(node);
81209
+ const parts = splitHtmlWithNestedTables(node, resolveReparseSource(node, ancestors, documentSource));
81093
81210
  if (!parts)
81094
81211
  return;
81095
81212
  // The inserted parts can't re-trigger a split (table parts start with
81096
81213
  // `<table`; the wrapper slices hold no table), so plain in-place splicing
81097
81214
  // visits each once without looping.
81098
- parent.children.splice(index, 1, ...parts);
81215
+ replaceInheritingReparseSource(parent, parent.children.indexOf(node), parts);
81099
81216
  });
81100
- visit(tree, 'html', (_node, index, parent) => {
81101
- const node = _node;
81102
- if (typeof index !== 'number' || !parent || !('children' in parent))
81217
+ visitParents(tree, 'html', (node, ancestors) => {
81218
+ const parent = ancestors[ancestors.length - 1];
81219
+ if (!parent)
81103
81220
  return;
81104
81221
  if (!node.value.startsWith('<Table') && !node.value.startsWith('<table'))
81105
81222
  return;
@@ -81107,33 +81224,8 @@ const mdxishTables = () => tree => {
81107
81224
  // paragraph. Leave them untouched so rehype-raw can reassemble the table.
81108
81225
  if (parent.type === 'paragraph')
81109
81226
  return;
81110
- // Because the processor uses remarkMdx, it is stricter in what it accepts
81111
- // and only accepts valid MDX syntax in the table node. To get around that,
81112
- // fall back to the cumulative repairs when the first parse fails.
81113
- const parsed = parseTableNode(tableNodeProcessor, node) ?? repairAndReparse(node);
81114
- if (parsed) {
81115
- // If the table is parsed successfully, we can now process it further
81116
- // to build on the markdown / JSX table
81117
- visit(parsed, isMDXElement, (tableNode) => {
81118
- if (tableNode.name !== 'Table' && tableNode.name !== 'table')
81119
- return undefined;
81120
- processTableNode(tableNode, index, parent, node.position);
81121
- return (/* inlined export .EXIT */false);
81122
- });
81123
- }
81124
- else if (node.value.startsWith('<table')) {
81125
- // If the parsing still fails, give an opportunity to the fallback parser
81126
- // without remarkMdx to process lowercase tables as it's likely to not
81127
- // have needed MDX parsing anyway
81128
- const fallback = parseTableNode(fallbackTableNodeProcessor, node);
81129
- if (!fallback || fallback.children.length <= 1)
81130
- return;
81131
- parent.children.splice(index, 1, ...fallback.children);
81132
- }
81133
- // Otherwise, there's no point in trying to parse the table content further
81134
- // More repairs are needed in that case
81227
+ replaceTableHtml(node, parent.children.indexOf(node), parent, resolveReparseSource(node, ancestors, documentSource));
81135
81228
  });
81136
- return tree;
81137
81229
  };
81138
81230
  /* harmony default export */ const mdxish_tables = (mdxishTables);
81139
81231
 
@@ -103888,32 +103980,6 @@ const mdxComponentHandlers = {
103888
103980
  [NodeTypes.htmlBlock]: htmlBlockHandler,
103889
103981
  };
103890
103982
 
103891
- ;// ./processor/plugin/safe-mode-html-blocks.ts
103892
-
103893
-
103894
- /**
103895
- * Whether a tag name renders through the `HTMLBlock` component. Mirrors the
103896
- * separator-agnostic, case-insensitive lookup in `getComponentName` and the
103897
- * rehype-react component map, so `html-block`, `HTMLBlock`, `HtmlBlock` and
103898
- * `htmlblock` all match.
103899
- */
103900
- const isHtmlBlockTag = (tagName) => toPascalCase(tagName).toLowerCase() === 'htmlblock';
103901
- /**
103902
- * Forces `safeMode` on every element that renders through `HTMLBlock` so it is
103903
- * shown as escaped text instead of injected.
103904
- *
103905
- * Runs last, so it sees every producer of the element — `[block:html]`,
103906
- * `<HTMLBlock>` with a template body or an `html` attribute, and a literal
103907
- * `<html-block>` — and it is unconditional so an author-supplied
103908
- * `safeMode="false"` can't opt out.
103909
- */
103910
- const enforceSafeModeHtmlBlocks = () => tree => {
103911
- visit(tree, 'element', node => {
103912
- if (isHtmlBlockTag(node.tagName))
103913
- node.properties.safeMode = 'true';
103914
- });
103915
- };
103916
-
103917
103983
  ;// ./processor/transform/mdxish/anchor-to-jsx.ts
103918
103984
 
103919
103985
 
@@ -103967,9 +104033,9 @@ const mdxishCalloutToJsx = () => tree => {
103967
104033
  visit(tree, NodeTypes.callout, (node, index, parent) => {
103968
104034
  if (!parent || index === undefined)
103969
104035
  return;
103970
- let { icon, theme } = node.data.hProperties;
103971
- if (!icon && theme)
103972
- icon = defaultIcons[theme];
104036
+ // No default-icon fill: an empty `icon` means the author removed it
104037
+ const { icon } = node.data.hProperties;
104038
+ let { theme } = node.data.hProperties;
103973
104039
  if (!theme && icon)
103974
104040
  theme = themes[icon] || 'default';
103975
104041
  // Mutate in place to keep the children array identity so nested callouts in
@@ -104520,18 +104586,6 @@ const getInlineMdProcessor = ({ safeMode = false } = {}) => {
104520
104586
  }
104521
104587
  return processor;
104522
104588
  };
104523
- /**
104524
- * Mark re-parsed subtree roots with the string their positions index into, so consumers
104525
- * slicing by offset use the right source (see `Data.reparseSource`). Only roots are
104526
- * stamped; descendants resolve via their nearest stamped ancestor. Roots a deeper
104527
- * re-parse already stamped keep their own string.
104528
- */
104529
- const stampReparseSource = (roots, reparseSource) => {
104530
- roots.forEach(root => {
104531
- if (!root.data?.reparseSource)
104532
- root.data = { ...root.data, reparseSource };
104533
- });
104534
- };
104535
104589
  /**
104536
104590
  * True when a tag name starts with an uppercase letter — ReadMe's marker for
104537
104591
  * a custom MDX component (vs a lowercase HTML tag).
@@ -104618,6 +104672,7 @@ function findBalancedClosingTagIndex(content, tag) {
104618
104672
 
104619
104673
 
104620
104674
 
104675
+
104621
104676
  /**
104622
104677
  * Parse the body of an inline component as phrasing content. Remark always
104623
104678
  * wraps bare text in a paragraph; flatten that single-paragraph wrapper so
@@ -104869,6 +104924,7 @@ function terminateHtmlFlowBlocks(content) {
104869
104924
 
104870
104925
 
104871
104926
 
104927
+
104872
104928
  // Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. One name
104873
104929
  // char suffices for existence — `[\w-]+` backtracked quadratically over huge attributes.
104874
104930
  const NESTED_ATTR_EXPRESSION_RE = /[\w-]\s*=\s*\{/;
@@ -104950,26 +105006,12 @@ const parseSibling = (parent, index, sibling, safeMode, promoted) => {
104950
105006
  }
104951
105007
  };
104952
105008
  // Ends the position at `consumedLength` so the component doesn't claim trailing
104953
- // content the tokenizer swallowed into the same html node. Measured against the source
104954
- // when available: each value line is its source line minus the container prefix
104955
- // (list indent, `> `) micromark stripped, so those prefixes are counted back in.
105009
+ // content the tokenizer swallowed into the same html node.
104956
105010
  const positionEndingAtConsumed = (nodePosition, value, consumedLength, source) => {
104957
- if (!nodePosition?.start)
105011
+ const toSourcePoint = createValueToSourceMapper(nodePosition, value, source);
105012
+ if (!nodePosition || !toSourcePoint)
104958
105013
  return nodePosition;
104959
- const consumedValue = value.slice(0, consumedLength);
104960
- const sourceLines = source?.slice(nodePosition.start.offset, nodePosition.end?.offset).split('\n');
104961
- const valueLines = value.split('\n');
104962
- if (!sourceLines || sourceLines.length !== valueLines.length) {
104963
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedValue) };
104964
- }
104965
- const consumedLines = consumedValue.split('\n');
104966
- const lastLineIndex = consumedLines.length - 1;
104967
- const prefixWidth = sourceLines[lastLineIndex].length - valueLines[lastLineIndex].length;
104968
- const consumedSource = [
104969
- ...sourceLines.slice(0, lastLineIndex),
104970
- sourceLines[lastLineIndex].slice(0, prefixWidth + consumedLines[lastLineIndex].length),
104971
- ].join('\n');
104972
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedSource) };
105014
+ return { start: nodePosition.start, end: toSourcePoint(consumedLength) };
104973
105015
  };
104974
105016
  const createComponentNode = ({ tag, attributes, children, startPosition, endPosition, }) => ({
104975
105017
  type: 'mdxJsxFlowElement',
@@ -104981,14 +105023,6 @@ const createComponentNode = ({ tag, attributes, children, startPosition, endPosi
104981
105023
  end: endPosition?.end ?? startPosition?.end,
104982
105024
  },
104983
105025
  });
104984
- // The promoted node takes over the html node's position, so it also takes over the
104985
- // coordinate space that position belongs to.
104986
- const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
104987
- const replacedSource = parent.children[index]?.data?.reparseSource;
104988
- if (replacedSource)
104989
- stampReparseSource([mdxNode], replacedSource);
104990
- parent.children.splice(index, 1, mdxNode);
104991
- };
104992
105026
  /**
104993
105027
  * Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
104994
105028
  *
@@ -105087,7 +105121,7 @@ function promoteComponentBlocks(tree, safeMode, source) {
105087
105121
  ? positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd, source)
105088
105122
  : node.position,
105089
105123
  });
105090
- substituteNodeWithMdxNode(parent, index, componentNode);
105124
+ replaceInheritingReparseSource(parent, index, [componentNode]);
105091
105125
  if (remainingContent) {
105092
105126
  parseSibling(parent, index, remainingContent, safeMode, promoted);
105093
105127
  }
@@ -105138,7 +105172,7 @@ function promoteComponentBlocks(tree, safeMode, source) {
105138
105172
  startPosition: node.position,
105139
105173
  endPosition,
105140
105174
  });
105141
- substituteNodeWithMdxNode(parent, index, componentNode);
105175
+ replaceInheritingReparseSource(parent, index, [componentNode]);
105142
105176
  // The unwrap reparented the children out of their paragraph, so re-walk them
105143
105177
  // since the children HTML may contain promotable syntax (e.g. `{…}`-attr tags)
105144
105178
  if (unwrappedSoleParagraph) {
@@ -106221,7 +106255,7 @@ const parseApiHeaderTitle = (text) => {
106221
106255
  * Transform a magicBlock node into final MDAST nodes.
106222
106256
  */
106223
106257
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
106224
- const { compatibilityMode = false, hardBreaks = true } = options;
106258
+ const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
106225
106259
  // Handle empty data by returning placeholder nodes for known block types
106226
106260
  // This allows the editor to show appropriate placeholder UI instead of nothing
106227
106261
  if (Object.keys(data).length < 1) {
@@ -106439,7 +106473,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
106439
106473
  wrapPinnedBlocks({
106440
106474
  data: {
106441
106475
  hName: 'html-block',
106442
- hProperties: { html: htmlJson.html, runScripts: compatibilityMode },
106476
+ hProperties: { html: htmlJson.html, runScripts: compatibilityMode, safeMode },
106443
106477
  },
106444
106478
  type: 'html-block',
106445
106479
  }, data),
@@ -106580,6 +106614,7 @@ const magicBlockTransformer = (options = {}) => tree => {
106580
106614
 
106581
106615
 
106582
106616
 
106617
+
106583
106618
  // `<HTMLBlock …>{`…`}</HTMLBlock>` embedded inside a raw HTML block (e.g. a
106584
106619
  // single-line `<div>…</div>`). CommonMark slurps the whole div as one `html`
106585
106620
  // node, so the tokenizer never sees the HTMLBlock — we recover it here.
@@ -106686,7 +106721,8 @@ const mdxishHtmlBlocks = () => tree => {
106686
106721
  return;
106687
106722
  const exprChild = element.children.find(child => child.type === 'mdxFlowExpression' || child.type === 'mdxTextExpression');
106688
106723
  const openingTagIndent = (element.position?.start.column ?? 1) - 1;
106689
- parent.children[index] = createHtmlBlockNode(formatHtmlForMdxish(extractTemplateLiteral(exprChild?.value), openingTagIndent), element.position, toRunScripts(jsxAttr(element, 'runScripts')), jsxAttr(element, 'safeMode'));
106724
+ const htmlBlock = createHtmlBlockNode(formatHtmlForMdxish(extractTemplateLiteral(exprChild?.value), openingTagIndent), element.position, toRunScripts(jsxAttr(element, 'runScripts')), jsxAttr(element, 'safeMode'));
106725
+ replaceInheritingReparseSource(parent, index, [htmlBlock]);
106690
106726
  });
106691
106727
  // Shape 2: raw HTML blob.
106692
106728
  visit(tree, 'html', (node, index, parent) => {
@@ -106694,7 +106730,7 @@ const mdxishHtmlBlocks = () => tree => {
106694
106730
  return;
106695
106731
  const replacement = splitRawHtmlBlocks(node);
106696
106732
  if (replacement)
106697
- parent.children.splice(index, 1, ...replacement);
106733
+ replaceInheritingReparseSource(parent, index, replacement);
106698
106734
  });
106699
106735
  };
106700
106736
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
@@ -106781,6 +106817,7 @@ const hasOnlyWidthAttributes = (cell) => {
106781
106817
 
106782
106818
 
106783
106819
 
106820
+
106784
106821
  function toImageAlign(value) {
106785
106822
  if (value === 'left' || value === 'center' || value === 'right') {
106786
106823
  return value;
@@ -106996,6 +107033,15 @@ const transformAnchor = (jsx) => {
106996
107033
  position: jsx.position,
106997
107034
  };
106998
107035
  };
107036
+ /**
107037
+ * Parses an image caption's markdown. The caption is re-parsed on its own, so the
107038
+ * children's positions index into it rather than the document.
107039
+ */
107040
+ const parseCaptionChildren = (caption) => {
107041
+ const { children } = lib_mdast(caption);
107042
+ stampReparseSource(children, caption);
107043
+ return children;
107044
+ };
106999
107045
  /**
107000
107046
  * Transforms an `<Image />` JSX element into an image-block MDAST node.
107001
107047
  * Normalizes attributes (align, border, width→sizing) and parses caption markdown into children.
@@ -107026,7 +107072,7 @@ const transformImage = (jsx) => {
107026
107072
  alt,
107027
107073
  border: toBool(border),
107028
107074
  caption,
107029
- children: caption ? lib_mdast(caption).children : [],
107075
+ children: caption ? parseCaptionChildren(caption) : [],
107030
107076
  className,
107031
107077
  framed: toBool(framed),
107032
107078
  height: height !== undefined ? String(height) : undefined,
@@ -107363,8 +107409,7 @@ const mdxishJsxToMdast = () => tree => {
107363
107409
  const newNode = transformer(node);
107364
107410
  if (!newNode)
107365
107411
  return;
107366
- // Replace the JSX node with the MDAST node
107367
- parent.children[index] = newNode;
107412
+ replaceInheritingReparseSource(parent, index, [newNode]);
107368
107413
  });
107369
107414
  // Inline JSX components (Anchor)
107370
107415
  visit(tree, 'mdxJsxTextElement', (node, index, parent) => {
@@ -108274,7 +108319,6 @@ function loadComponents() {
108274
108319
 
108275
108320
 
108276
108321
 
108277
-
108278
108322
 
108279
108323
 
108280
108324
  const defaultTransformers = [
@@ -108430,8 +108474,7 @@ function mdxish(mdContent, opts = {}) {
108430
108474
  .use(rehypeMdxishComponents, {
108431
108475
  components,
108432
108476
  processMarkdown: (markdown) => mdxish(markdown, opts),
108433
- })
108434
- .use(safeMode ? enforceSafeModeHtmlBlocks : undefined); // Force safeMode on every HTMLBlock; runs last so every producer is covered
108477
+ });
108435
108478
  const vfile = new VFile({ value: parserReadyContent });
108436
108479
  const mdast = processor.parse(parserReadyContent);
108437
108480
  const hast = processor.runSync(mdast, vfile);
@@ -109403,7 +109446,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
109403
109446
  /******/ // startup
109404
109447
  /******/ // Load entry module and return exports
109405
109448
  /******/ // This entry module used 'module' so it can't be inlined
109406
- /******/ let __webpack_exports__ = __webpack_require__(9171);
109449
+ /******/ let __webpack_exports__ = __webpack_require__(8846);
109407
109450
  /******/
109408
109451
  /******/ return __webpack_exports__;
109409
109452
  /******/ })()