@readme/markdown 15.8.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.
@@ -19045,7 +19045,7 @@ module.exports = function () {
19045
19045
 
19046
19046
  /***/ },
19047
19047
 
19048
- /***/ 6829
19048
+ /***/ 1186
19049
19049
  (module, __webpack_exports__, __webpack_require__) {
19050
19050
 
19051
19051
  "use strict";
@@ -68781,18 +68781,53 @@ function evaluate(source, scope = {}) {
68781
68781
  return new Function(...names, `return (${source})`)(...values);
68782
68782
  }
68783
68783
  /**
68784
- * Advance a `Point` by the `consumed` substring that follows it, returning the
68785
- * point at the consumed string's end. Lets split-out sub-nodes carry accurate
68786
- * document positions so downstream offset shifting stays correct.
68784
+ * Width each container prefix adds back per line of `value`, aligned from the line end since a
68785
+ * tab in the prefix is expanded to spaces in `value`. None (a verbatim slice) when the source
68786
+ * is missing or doesn't line up.
68787
68787
  */
68788
- const pointAfter = (start, consumed) => {
68789
- const newlineIndex = consumed.lastIndexOf('\n');
68790
- const newlineCount = newlineIndex === -1 ? 0 : consumed.split('\n').length - 1;
68791
- return {
68792
- line: start.line + newlineCount,
68793
- // Same line → advance the base column; a later line → column is the run since its newline.
68794
- column: newlineCount === 0 ? start.column + consumed.length : consumed.length - newlineIndex,
68795
- offset: (start.offset ?? 0) + consumed.length,
68788
+ const containerPrefixWidths = (valueLines, source, position) => {
68789
+ const sourceLines = source?.slice(position.start.offset, position.end.offset).split('\n');
68790
+ const linesUp = sourceLines?.length === valueLines.length &&
68791
+ sourceLines.every((line, i) => line.endsWith(valueLines[i].trimStart()));
68792
+ return valueLines.map((line, i) => (linesUp ? sourceLines[i].length - line.length : 0));
68793
+ };
68794
+ /**
68795
+ * Maps offsets in a node's `value` to points in `source`. Containers strip a prefix from every
68796
+ * continuation line of `value`, so a plain offset shift drifts by line (CX-4028).
68797
+ */
68798
+ const createValueToSourceMapper = (position, value, source) => {
68799
+ if (position?.start.offset === undefined)
68800
+ return null;
68801
+ const { start } = position;
68802
+ const valueLines = value.split('\n');
68803
+ const prefixWidths = containerPrefixWidths(valueLines, source, position);
68804
+ const lines = [];
68805
+ let valueStart = 0;
68806
+ let sourceStart = start.offset;
68807
+ valueLines.forEach((line, i) => {
68808
+ lines.push({ prefixWidth: prefixWidths[i], sourceStart, valueStart });
68809
+ valueStart += line.length + 1;
68810
+ sourceStart += prefixWidths[i] + line.length + 1;
68811
+ });
68812
+ return valueOffset => {
68813
+ // Binary search: a large table maps one point per node.
68814
+ let low = 0;
68815
+ let high = lines.length - 1;
68816
+ while (low < high) {
68817
+ const mid = Math.ceil((low + high) / 2);
68818
+ if (lines[mid].valueStart <= valueOffset)
68819
+ low = mid;
68820
+ else
68821
+ high = mid - 1;
68822
+ }
68823
+ const { prefixWidth, sourceStart: lineSourceStart, valueStart: lineValueStart } = lines[low];
68824
+ // Clamped: an expanded tab can make a leading-whitespace offset fall before the line.
68825
+ const sourceColumn = Math.max(0, prefixWidth + valueOffset - lineValueStart);
68826
+ return {
68827
+ line: start.line + low,
68828
+ column: (low === 0 ? start.column : 1) + sourceColumn,
68829
+ offset: lineSourceStart + sourceColumn,
68830
+ };
68796
68831
  };
68797
68832
  };
68798
68833
  /**
@@ -69455,7 +69490,9 @@ const processBlockquote = (node, index, parent, isMdxish = false) => {
69455
69490
  }
69456
69491
  Object.assign(node, {
69457
69492
  type: NodeTypes.callout,
69493
+ // Keep the blockquote's data, e.g. the `reparseSource` its positions index into.
69458
69494
  data: {
69495
+ ...node.data,
69459
69496
  hName: 'Callout',
69460
69497
  hProperties: {
69461
69498
  icon,
@@ -69488,14 +69525,55 @@ const calloutTransformer = ({ isMdxish = false } = {}) => {
69488
69525
  };
69489
69526
  /* harmony default export */ const callouts = (calloutTransformer);
69490
69527
 
69528
+ ;// ./processor/transform/mdxish/reparse-source.ts
69529
+ /**
69530
+ * Mark re-parsed subtree roots with the string their positions index into, so consumers
69531
+ * slicing by offset use the right source (see `Data.reparseSource`). Only roots are
69532
+ * stamped; descendants resolve via their nearest stamped ancestor. Roots a deeper
69533
+ * re-parse already stamped keep their own string.
69534
+ */
69535
+ const stampReparseSource = (roots, reparseSource) => {
69536
+ roots.forEach(root => {
69537
+ if (!root.data?.reparseSource)
69538
+ root.data = { ...root.data, reparseSource };
69539
+ });
69540
+ };
69541
+ /**
69542
+ * Splice `replacements` over `parent.children[index]`. They take over the replaced node's
69543
+ * position, so they also take over the coordinate space that position indexes into.
69544
+ */
69545
+ const replaceInheritingReparseSource = (parent, index, replacements) => {
69546
+ const replacedSource = parent.children[index]?.data?.reparseSource;
69547
+ if (replacedSource)
69548
+ stampReparseSource(replacements, replacedSource);
69549
+ parent.children.splice(index, 1, ...replacements);
69550
+ };
69551
+ /**
69552
+ * The string `node`'s offsets index into: the nearest stamp on it or an ancestor, else the
69553
+ * document source.
69554
+ */
69555
+ const resolveReparseSource = (node, ancestors, documentSource) => {
69556
+ if (node.data?.reparseSource)
69557
+ return node.data.reparseSource;
69558
+ for (let i = ancestors.length - 1; i >= 0; i -= 1) {
69559
+ const { reparseSource } = ancestors[i].data ?? {};
69560
+ if (reparseSource)
69561
+ return reparseSource;
69562
+ }
69563
+ return documentSource;
69564
+ };
69565
+
69491
69566
  ;// ./processor/transform/code-tabs.ts
69492
69567
 
69493
69568
 
69569
+
69494
69570
  const isCode = (node) => node?.type === 'code';
69495
69571
  const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
69496
69572
  visit(tree, 'code', (node) => {
69497
69573
  const { lang, meta, value } = node;
69498
69574
  node.data = {
69575
+ // Ensure positions are passed through
69576
+ ...node.data,
69499
69577
  hProperties: { lang, meta, value, copyButtons },
69500
69578
  };
69501
69579
  });
@@ -69542,6 +69620,9 @@ const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
69542
69620
  end: children[children.length - 1].position.end,
69543
69621
  },
69544
69622
  };
69623
+ // Adjacent siblings share a coordinate space, so the wrapper takes the first block's.
69624
+ if (node.data?.reparseSource)
69625
+ stampReparseSource([codeTabs], node.data.reparseSource);
69545
69626
  parent.children.splice(index, children.length, codeTabs);
69546
69627
  });
69547
69628
  return tree;
@@ -100237,6 +100318,7 @@ const walkTags = (html, handlers) => {
100237
100318
  };
100238
100319
 
100239
100320
  ;// ./processor/transform/mdxish/tables/utils.ts
100321
+
100240
100322
  const tableTags = new Set([
100241
100323
  'thead',
100242
100324
  'tbody',
@@ -100255,6 +100337,9 @@ const tableTags = new Set([
100255
100337
  const unwrapParagraphNodes = (children) => {
100256
100338
  return children.flatMap(child => {
100257
100339
  if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
100340
+ // The unwrap drops a stamped root, so its children inherit that coordinate space.
100341
+ if (child.data?.reparseSource)
100342
+ stampReparseSource(child.children, child.data.reparseSource);
100258
100343
  return child.children;
100259
100344
  }
100260
100345
  return [child];
@@ -100850,9 +100935,10 @@ const findTableRanges = (html) => {
100850
100935
  * The surrounding raw HTML (the wrapper's open/close tags) would be re-nested
100851
100936
  * around the parsed tables by rehype-raw.
100852
100937
  *
100853
- * Returns null when there is no wrapped table to extract.
100938
+ * Returns null when there is no wrapped table to extract. `source` is the string the node's
100939
+ * positions index into, so the parts' positions survive stripped container prefixes.
100854
100940
  */
100855
- const splitHtmlWithNestedTables = (node) => {
100941
+ const splitHtmlWithNestedTables = (node, source) => {
100856
100942
  const { value } = node;
100857
100943
  // This is a top-level table, so we don't need to split it
100858
100944
  if (TOP_LEVEL_TABLE_TAG_RE.test(value))
@@ -100865,13 +100951,11 @@ const splitHtmlWithNestedTables = (node) => {
100865
100951
  const ranges = findTableRanges(value);
100866
100952
  if (ranges.length === 0)
100867
100953
  return null;
100868
- const base = node.position?.start;
100954
+ const toSourcePoint = createValueToSourceMapper(node.position, value, source);
100869
100955
  const sliceToHtml = (from, to) => ({
100870
100956
  type: 'html',
100871
100957
  value: value.slice(from, to),
100872
- ...(base && {
100873
- position: { start: pointAfter(base, value.slice(0, from)), end: pointAfter(base, value.slice(0, to)) },
100874
- }),
100958
+ ...(toSourcePoint && { position: { start: toSourcePoint(from), end: toSourcePoint(to) } }),
100875
100959
  });
100876
100960
  const parts = [];
100877
100961
  let cursor = 0;
@@ -100906,6 +100990,8 @@ const splitHtmlWithNestedTables = (node) => {
100906
100990
 
100907
100991
 
100908
100992
 
100993
+
100994
+
100909
100995
 
100910
100996
 
100911
100997
 
@@ -100958,7 +101044,7 @@ const tableRepairs = [
100958
101044
  * The plugins in the processor allows parsing markdown & special syntax inside the table cells
100959
101045
  * After parsing, we need to update the node positions
100960
101046
  */
100961
- const parseTableNode = (processor, node, repair) => {
101047
+ const parseTableNode = (processor, node, source, repair) => {
100962
101048
  let parsed;
100963
101049
  try {
100964
101050
  parsed = processor.runSync(processor.parse(node.value));
@@ -100972,19 +101058,18 @@ const parseTableNode = (processor, node, repair) => {
100972
101058
  if (repair) {
100973
101059
  remapPositionsThroughLayers(parsed, repair.originalSource, repair.layers);
100974
101060
  }
100975
- // The subparser produces positions relative to `node.value`; shift them by
100976
- // the outer node's offset/line so consumers can slice the full source.
100977
- const baseOffset = node.position?.start?.offset ?? 0;
100978
- const baseLine = (node.position?.start?.line ?? 1) - 1;
101061
+ // The subparser produces positions relative to `node.value`; map them into
101062
+ // the outer source so consumers can slice it.
101063
+ const toSourcePoint = createValueToSourceMapper(node.position, repair?.originalSource ?? node.value, source);
101064
+ if (!toSourcePoint)
101065
+ return parsed;
100979
101066
  visit(parsed, child => {
100980
- if (child.position?.start) {
100981
- child.position.start.offset = (child.position.start.offset ?? 0) + baseOffset;
100982
- child.position.start.line += baseLine;
100983
- }
100984
- if (child.position?.end) {
100985
- child.position.end.offset = (child.position.end.offset ?? 0) + baseOffset;
100986
- child.position.end.line += baseLine;
100987
- }
101067
+ if (!child.position)
101068
+ return;
101069
+ child.position = {
101070
+ start: toSourcePoint(child.position.start.offset ?? 0),
101071
+ end: toSourcePoint(child.position.end.offset ?? 0),
101072
+ };
100988
101073
  });
100989
101074
  return parsed;
100990
101075
  };
@@ -101014,12 +101099,10 @@ const hasFlowContent = (nodes) => {
101014
101099
  return nodes.some(node => !phrasing(node) && node.type !== 'paragraph');
101015
101100
  };
101016
101101
  /**
101017
- * Process a Table node: re-parse text-only cell content, then output as
101018
- * a markdown table (phrasing-only) or keep as JSX <Table> (has flow content).
101102
+ * Process a Table node: re-parse text-only cell content, then return it as
101103
+ * a markdown table (phrasing-only) or keep it as JSX <Table> (has flow content).
101019
101104
  */
101020
- const processTableNode = (node, index, parent, documentPosition) => {
101021
- if (node.name !== 'Table' && node.name !== 'table')
101022
- return;
101105
+ const processTableNode = (node, documentPosition) => {
101023
101106
  const position = documentPosition ?? node.position;
101024
101107
  const { align: alignAttr } = getAttrs(node);
101025
101108
  const align = Array.isArray(alignAttr) ? alignAttr : null;
@@ -101046,6 +101129,8 @@ const processTableNode = (node, index, parent, documentPosition) => {
101046
101129
  try {
101047
101130
  const parsed = tableNodeProcessor.runSync(tableNodeProcessor.parse(textContent));
101048
101131
  if (parsed.children.length > 0) {
101132
+ // Positions index into the extracted text rather than the table source (CX-4004).
101133
+ stampReparseSource(parsed.children, textContent);
101049
101134
  cell.children = parsed.children;
101050
101135
  if (hasFlowContent(parsed.children)) {
101051
101136
  tableHasFlowContent = true;
@@ -101088,11 +101173,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
101088
101173
  : unwrapParagraphNodes(el.children);
101089
101174
  el.children = removeWhitespaceOnlyTextNodes(unwrapped);
101090
101175
  });
101091
- parent.children[index] = {
101092
- ...node,
101093
- position,
101094
- };
101095
- return;
101176
+ return { ...node, position };
101096
101177
  }
101097
101178
  // All cells are phrasing-only — convert to markdown table
101098
101179
  const children = [];
@@ -101170,7 +101251,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
101170
101251
  const alignArray = align && columnCount > 0
101171
101252
  ? align.slice(0, columnCount).concat(new Array(Math.max(0, columnCount - align.length)).fill(null))
101172
101253
  : new Array(columnCount).fill(null);
101173
- const mdNode = {
101254
+ return {
101174
101255
  align: alignArray,
101175
101256
  type: 'table',
101176
101257
  position,
@@ -101178,14 +101259,13 @@ const processTableNode = (node, index, parent, documentPosition) => {
101178
101259
  // Remember the author's spelling so the serializer can write `<table>` back instead of `<Table>`
101179
101260
  ...(node.name === 'table' && { data: { lowercaseTable: true } }),
101180
101261
  };
101181
- parent.children[index] = mdNode;
101182
101262
  };
101183
101263
  /**
101184
101264
  * Apply `tableRepairs` cumulatively, re-parsing after every change and stopping
101185
101265
  * once the accumulated result parses. Each layer's inserts are relative to the
101186
101266
  * string that repair received, so they stay ordered for position remapping.
101187
101267
  */
101188
- const repairAndReparse = (node) => {
101268
+ const repairAndReparse = (node, source) => {
101189
101269
  let repairedValue = node.value;
101190
101270
  const layers = [];
101191
101271
  let parsed;
@@ -101195,11 +101275,45 @@ const repairAndReparse = (node) => {
101195
101275
  return false;
101196
101276
  repairedValue = value;
101197
101277
  layers.push(inserts);
101198
- parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, { layers, originalSource: node.value });
101278
+ parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, source, {
101279
+ layers,
101280
+ originalSource: node.value,
101281
+ });
101199
101282
  return Boolean(parsed);
101200
101283
  });
101201
101284
  return parsed;
101202
101285
  };
101286
+ /**
101287
+ * Re-parse a table html node and replace it with a markdown / JSX table, or the
101288
+ * fallback parse's fragments for a lowercase table mdxjs rejects.
101289
+ */
101290
+ const replaceTableHtml = (node, index, parent, source) => {
101291
+ // Because the processor uses remarkMdx, it is stricter in what it accepts
101292
+ // and only accepts valid MDX syntax in the table node. To get around that,
101293
+ // fall back to the cumulative repairs when the first parse fails.
101294
+ const parsed = parseTableNode(tableNodeProcessor, node, source) ?? repairAndReparse(node, source);
101295
+ if (parsed) {
101296
+ // If the table is parsed successfully, we can now process it further
101297
+ // to build on the markdown / JSX table
101298
+ visit(parsed, isMDXElement, (tableNode) => {
101299
+ if (tableNode.name !== 'Table' && tableNode.name !== 'table')
101300
+ return undefined;
101301
+ replaceInheritingReparseSource(parent, index, [processTableNode(tableNode, node.position)]);
101302
+ return (/* inlined export .EXIT */false);
101303
+ });
101304
+ }
101305
+ else if (node.value.startsWith('<table')) {
101306
+ // If the parsing still fails, give an opportunity to the fallback parser
101307
+ // without remarkMdx to process lowercase tables as it's likely to not
101308
+ // have needed MDX parsing anyway
101309
+ const fallback = parseTableNode(fallbackTableNodeProcessor, node, source);
101310
+ if (!fallback || fallback.children.length <= 1)
101311
+ return;
101312
+ replaceInheritingReparseSource(parent, index, fallback.children);
101313
+ }
101314
+ // Otherwise, there's no point in trying to parse the table content further
101315
+ // More repairs are needed in that case
101316
+ };
101203
101317
  /**
101204
101318
  * Converts JSX Table elements to markdown table nodes and re-parses markdown in cells.
101205
101319
  *
@@ -101211,24 +101325,26 @@ const repairAndReparse = (node) => {
101211
101325
  * When cell content contains block-level nodes (callouts, code blocks, etc.), the table
101212
101326
  * is kept as a JSX <Table> element so that remarkRehype can properly handle the flow content.
101213
101327
  */
101214
- const mdxishTables = () => tree => {
101328
+ const mdxishTables = () => (tree, file) => {
101329
+ // Positions index into the document unless a re-parse stamped another source.
101330
+ const documentSource = file?.value ? String(file.value) : undefined;
101215
101331
  // Pre-pass: lift `<table>`s wrapped in a raw HTML block out into their own
101216
101332
  // html nodes so the main pass below treats them like top-level tables.
101217
- visit(tree, 'html', (_node, index, parent) => {
101218
- const node = _node;
101219
- if (typeof index !== 'number' || !parent || !('children' in parent))
101333
+ visitParents(tree, 'html', (node, ancestors) => {
101334
+ const parent = ancestors[ancestors.length - 1];
101335
+ if (!parent)
101220
101336
  return;
101221
- const parts = splitHtmlWithNestedTables(node);
101337
+ const parts = splitHtmlWithNestedTables(node, resolveReparseSource(node, ancestors, documentSource));
101222
101338
  if (!parts)
101223
101339
  return;
101224
101340
  // The inserted parts can't re-trigger a split (table parts start with
101225
101341
  // `<table`; the wrapper slices hold no table), so plain in-place splicing
101226
101342
  // visits each once without looping.
101227
- parent.children.splice(index, 1, ...parts);
101343
+ replaceInheritingReparseSource(parent, parent.children.indexOf(node), parts);
101228
101344
  });
101229
- visit(tree, 'html', (_node, index, parent) => {
101230
- const node = _node;
101231
- if (typeof index !== 'number' || !parent || !('children' in parent))
101345
+ visitParents(tree, 'html', (node, ancestors) => {
101346
+ const parent = ancestors[ancestors.length - 1];
101347
+ if (!parent)
101232
101348
  return;
101233
101349
  if (!node.value.startsWith('<Table') && !node.value.startsWith('<table'))
101234
101350
  return;
@@ -101236,33 +101352,8 @@ const mdxishTables = () => tree => {
101236
101352
  // paragraph. Leave them untouched so rehype-raw can reassemble the table.
101237
101353
  if (parent.type === 'paragraph')
101238
101354
  return;
101239
- // Because the processor uses remarkMdx, it is stricter in what it accepts
101240
- // and only accepts valid MDX syntax in the table node. To get around that,
101241
- // fall back to the cumulative repairs when the first parse fails.
101242
- const parsed = parseTableNode(tableNodeProcessor, node) ?? repairAndReparse(node);
101243
- if (parsed) {
101244
- // If the table is parsed successfully, we can now process it further
101245
- // to build on the markdown / JSX table
101246
- visit(parsed, isMDXElement, (tableNode) => {
101247
- if (tableNode.name !== 'Table' && tableNode.name !== 'table')
101248
- return undefined;
101249
- processTableNode(tableNode, index, parent, node.position);
101250
- return (/* inlined export .EXIT */false);
101251
- });
101252
- }
101253
- else if (node.value.startsWith('<table')) {
101254
- // If the parsing still fails, give an opportunity to the fallback parser
101255
- // without remarkMdx to process lowercase tables as it's likely to not
101256
- // have needed MDX parsing anyway
101257
- const fallback = parseTableNode(fallbackTableNodeProcessor, node);
101258
- if (!fallback || fallback.children.length <= 1)
101259
- return;
101260
- parent.children.splice(index, 1, ...fallback.children);
101261
- }
101262
- // Otherwise, there's no point in trying to parse the table content further
101263
- // More repairs are needed in that case
101355
+ replaceTableHtml(node, parent.children.indexOf(node), parent, resolveReparseSource(node, ancestors, documentSource));
101264
101356
  });
101265
- return tree;
101266
101357
  };
101267
101358
  /* harmony default export */ const mdxish_tables = (mdxishTables);
101268
101359
 
@@ -122464,7 +122555,6 @@ const mdxishAnchorToJsx = () => tree => {
122464
122555
 
122465
122556
  ;// ./processor/transform/mdxish/callout-to-jsx.ts
122466
122557
  /* unused harmony import specifier */ var callout_to_jsx_visit;
122467
- /* unused harmony import specifier */ var callout_to_jsx_defaultIcons;
122468
122558
  /* unused harmony import specifier */ var callout_to_jsx_themes;
122469
122559
  /* unused harmony import specifier */ var callout_to_jsx_NodeTypes;
122470
122560
  /* unused harmony import specifier */ var callout_to_jsx_toAttributes;
@@ -122487,9 +122577,9 @@ const mdxishCalloutToJsx = () => tree => {
122487
122577
  callout_to_jsx_visit(tree, callout_to_jsx_NodeTypes.callout, (node, index, parent) => {
122488
122578
  if (!parent || index === undefined)
122489
122579
  return;
122490
- let { icon, theme } = node.data.hProperties;
122491
- if (!icon && theme)
122492
- icon = callout_to_jsx_defaultIcons[theme];
122580
+ // No default-icon fill: an empty `icon` means the author removed it
122581
+ const { icon } = node.data.hProperties;
122582
+ let { theme } = node.data.hProperties;
122493
122583
  if (!theme && icon)
122494
122584
  theme = callout_to_jsx_themes[icon] || 'default';
122495
122585
  // Mutate in place to keep the children array identity so nested callouts in
@@ -123040,18 +123130,6 @@ const getInlineMdProcessor = ({ safeMode = false } = {}) => {
123040
123130
  }
123041
123131
  return processor;
123042
123132
  };
123043
- /**
123044
- * Mark re-parsed subtree roots with the string their positions index into, so consumers
123045
- * slicing by offset use the right source (see `Data.reparseSource`). Only roots are
123046
- * stamped; descendants resolve via their nearest stamped ancestor. Roots a deeper
123047
- * re-parse already stamped keep their own string.
123048
- */
123049
- const stampReparseSource = (roots, reparseSource) => {
123050
- roots.forEach(root => {
123051
- if (!root.data?.reparseSource)
123052
- root.data = { ...root.data, reparseSource };
123053
- });
123054
- };
123055
123133
  /**
123056
123134
  * True when a tag name starts with an uppercase letter — ReadMe's marker for
123057
123135
  * a custom MDX component (vs a lowercase HTML tag).
@@ -123138,6 +123216,7 @@ function findBalancedClosingTagIndex(content, tag) {
123138
123216
 
123139
123217
 
123140
123218
 
123219
+
123141
123220
  /**
123142
123221
  * Parse the body of an inline component as phrasing content. Remark always
123143
123222
  * wraps bare text in a paragraph; flatten that single-paragraph wrapper so
@@ -123389,6 +123468,7 @@ function terminateHtmlFlowBlocks(content) {
123389
123468
 
123390
123469
 
123391
123470
 
123471
+
123392
123472
  // Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. One name
123393
123473
  // char suffices for existence — `[\w-]+` backtracked quadratically over huge attributes.
123394
123474
  const NESTED_ATTR_EXPRESSION_RE = /[\w-]\s*=\s*\{/;
@@ -123470,26 +123550,12 @@ const parseSibling = (parent, index, sibling, safeMode, promoted) => {
123470
123550
  }
123471
123551
  };
123472
123552
  // Ends the position at `consumedLength` so the component doesn't claim trailing
123473
- // content the tokenizer swallowed into the same html node. Measured against the source
123474
- // when available: each value line is its source line minus the container prefix
123475
- // (list indent, `> `) micromark stripped, so those prefixes are counted back in.
123553
+ // content the tokenizer swallowed into the same html node.
123476
123554
  const positionEndingAtConsumed = (nodePosition, value, consumedLength, source) => {
123477
- if (!nodePosition?.start)
123555
+ const toSourcePoint = createValueToSourceMapper(nodePosition, value, source);
123556
+ if (!nodePosition || !toSourcePoint)
123478
123557
  return nodePosition;
123479
- const consumedValue = value.slice(0, consumedLength);
123480
- const sourceLines = source?.slice(nodePosition.start.offset, nodePosition.end?.offset).split('\n');
123481
- const valueLines = value.split('\n');
123482
- if (!sourceLines || sourceLines.length !== valueLines.length) {
123483
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedValue) };
123484
- }
123485
- const consumedLines = consumedValue.split('\n');
123486
- const lastLineIndex = consumedLines.length - 1;
123487
- const prefixWidth = sourceLines[lastLineIndex].length - valueLines[lastLineIndex].length;
123488
- const consumedSource = [
123489
- ...sourceLines.slice(0, lastLineIndex),
123490
- sourceLines[lastLineIndex].slice(0, prefixWidth + consumedLines[lastLineIndex].length),
123491
- ].join('\n');
123492
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedSource) };
123558
+ return { start: nodePosition.start, end: toSourcePoint(consumedLength) };
123493
123559
  };
123494
123560
  const createComponentNode = ({ tag, attributes, children, startPosition, endPosition, }) => ({
123495
123561
  type: 'mdxJsxFlowElement',
@@ -123501,14 +123567,6 @@ const createComponentNode = ({ tag, attributes, children, startPosition, endPosi
123501
123567
  end: endPosition?.end ?? startPosition?.end,
123502
123568
  },
123503
123569
  });
123504
- // The promoted node takes over the html node's position, so it also takes over the
123505
- // coordinate space that position belongs to.
123506
- const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
123507
- const replacedSource = parent.children[index]?.data?.reparseSource;
123508
- if (replacedSource)
123509
- stampReparseSource([mdxNode], replacedSource);
123510
- parent.children.splice(index, 1, mdxNode);
123511
- };
123512
123570
  /**
123513
123571
  * Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
123514
123572
  *
@@ -123607,7 +123665,7 @@ function promoteComponentBlocks(tree, safeMode, source) {
123607
123665
  ? positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd, source)
123608
123666
  : node.position,
123609
123667
  });
123610
- substituteNodeWithMdxNode(parent, index, componentNode);
123668
+ replaceInheritingReparseSource(parent, index, [componentNode]);
123611
123669
  if (remainingContent) {
123612
123670
  parseSibling(parent, index, remainingContent, safeMode, promoted);
123613
123671
  }
@@ -123658,7 +123716,7 @@ function promoteComponentBlocks(tree, safeMode, source) {
123658
123716
  startPosition: node.position,
123659
123717
  endPosition,
123660
123718
  });
123661
- substituteNodeWithMdxNode(parent, index, componentNode);
123719
+ replaceInheritingReparseSource(parent, index, [componentNode]);
123662
123720
  // The unwrap reparented the children out of their paragraph, so re-walk them
123663
123721
  // since the children HTML may contain promotable syntax (e.g. `{…}`-attr tags)
123664
123722
  if (unwrappedSoleParagraph) {
@@ -126506,6 +126564,7 @@ const magicBlockTransformer = (options = {}) => tree => {
126506
126564
 
126507
126565
 
126508
126566
 
126567
+
126509
126568
  // `<HTMLBlock …>{`…`}</HTMLBlock>` embedded inside a raw HTML block (e.g. a
126510
126569
  // single-line `<div>…</div>`). CommonMark slurps the whole div as one `html`
126511
126570
  // node, so the tokenizer never sees the HTMLBlock — we recover it here.
@@ -126612,7 +126671,8 @@ const mdxishHtmlBlocks = () => tree => {
126612
126671
  return;
126613
126672
  const exprChild = element.children.find(child => child.type === 'mdxFlowExpression' || child.type === 'mdxTextExpression');
126614
126673
  const openingTagIndent = (element.position?.start.column ?? 1) - 1;
126615
- parent.children[index] = createHtmlBlockNode(formatHtmlForMdxish(extractTemplateLiteral(exprChild?.value), openingTagIndent), element.position, toRunScripts(jsxAttr(element, 'runScripts')), jsxAttr(element, 'safeMode'));
126674
+ const htmlBlock = createHtmlBlockNode(formatHtmlForMdxish(extractTemplateLiteral(exprChild?.value), openingTagIndent), element.position, toRunScripts(jsxAttr(element, 'runScripts')), jsxAttr(element, 'safeMode'));
126675
+ replaceInheritingReparseSource(parent, index, [htmlBlock]);
126616
126676
  });
126617
126677
  // Shape 2: raw HTML blob.
126618
126678
  visit(tree, 'html', (node, index, parent) => {
@@ -126620,11 +126680,85 @@ const mdxishHtmlBlocks = () => tree => {
126620
126680
  return;
126621
126681
  const replacement = splitRawHtmlBlocks(node);
126622
126682
  if (replacement)
126623
- parent.children.splice(index, 1, ...replacement);
126683
+ replaceInheritingReparseSource(parent, index, replacement);
126624
126684
  });
126625
126685
  };
126626
126686
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
126627
126687
 
126688
+ ;// ./processor/transform/mdxish/tables/cell-width.ts
126689
+
126690
+
126691
+ // Key must follow `{` or `,` so `minWidth`/`maxWidth` don't match on their suffix
126692
+ const STYLE_OBJECT_WIDTH_REGEX = /[{,]\s*["']?width["']?\s*:\s*(?:"([^"]*)"|'([^']*)'|([^,}]+))/i;
126693
+ // First colon only, so `url(http://…)` values stay intact
126694
+ const CSS_DECLARATION_REGEX = /:(.*)/s;
126695
+ const UNITLESS_NUMBER_REGEX = /^\d+(?:\.\d+)?$/;
126696
+ // HTML reads a `width` attribute as a leading number plus optional `%`, ignoring the rest
126697
+ const HTML_DIMENSION_REGEX = /^\s*(\d+(?:\.\d+)?)\s*(%?)/;
126698
+ /** Bare numbers are pixels. A value carrying declaration separators is not a single width. */
126699
+ const normalizeWidth = (value) => {
126700
+ if (typeof value === 'number')
126701
+ return `${value}px`;
126702
+ if (typeof value !== 'string' || !value.trim())
126703
+ return null;
126704
+ const trimmed = value.trim();
126705
+ if (/[;:{}]/.test(trimmed))
126706
+ return null;
126707
+ return UNITLESS_NUMBER_REGEX.test(trimmed) ? `${trimmed}px` : trimmed;
126708
+ };
126709
+ const widthFromAttribute = (value) => {
126710
+ if (typeof value === 'number')
126711
+ return `${value}px`;
126712
+ if (typeof value !== 'string')
126713
+ return null;
126714
+ const match = HTML_DIMENSION_REGEX.exec(value);
126715
+ return match ? `${match[1]}${match[2] || 'px'}` : null;
126716
+ };
126717
+ const cssPropertyNames = (style) => style
126718
+ .split(';')
126719
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX)[0].trim().toLowerCase())
126720
+ .filter(Boolean);
126721
+ /** Handles a CSS declaration list and a style object safe mode left as a string (`{ width: "30%" }`). */
126722
+ const widthFromStyleString = (style) => {
126723
+ const trimmed = style.trim();
126724
+ if (trimmed.startsWith('{')) {
126725
+ return STYLE_OBJECT_WIDTH_REGEX.exec(trimmed)?.slice(1).find(Boolean);
126726
+ }
126727
+ return trimmed
126728
+ .split(';')
126729
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX))
126730
+ .find(([property]) => property.trim().toLowerCase() === 'width')?.[1];
126731
+ };
126732
+ /** Accepts `style={{ width }}`, `style="width: …"` and the hand-authored `width="…"`. */
126733
+ const getCellWidth = (cell) => {
126734
+ const { style, width } = getAttrs(cell);
126735
+ let styleWidth;
126736
+ if (style_object_to_css_isPlainObject(style)) {
126737
+ styleWidth = style.width;
126738
+ }
126739
+ else if (typeof style === 'string') {
126740
+ styleWidth = widthFromStyleString(style);
126741
+ }
126742
+ return normalizeWidth(styleWidth) ?? widthFromAttribute(width);
126743
+ };
126744
+ /** True when the cell's attributes state nothing but its width, which mdast can carry. */
126745
+ const hasOnlyWidthAttributes = (cell) => {
126746
+ if (cell.attributes.length === 0)
126747
+ return false;
126748
+ const { style } = getAttrs(cell);
126749
+ return cell.attributes.every(attribute => {
126750
+ if (!('name' in attribute))
126751
+ return false;
126752
+ if (attribute.name === 'width')
126753
+ return true;
126754
+ if (attribute.name !== 'style')
126755
+ return false;
126756
+ if (style_object_to_css_isPlainObject(style))
126757
+ return Object.keys(style).every(key => key === 'width');
126758
+ return typeof style === 'string' && cssPropertyNames(style).every(property => property === 'width');
126759
+ });
126760
+ };
126761
+
126628
126762
  ;// ./processor/transform/mdxish/mdxish-jsx-to-mdast.ts
126629
126763
 
126630
126764
 
@@ -126632,6 +126766,8 @@ const mdxishHtmlBlocks = () => tree => {
126632
126766
 
126633
126767
 
126634
126768
 
126769
+
126770
+
126635
126771
  function toImageAlign(value) {
126636
126772
  if (value === 'left' || value === 'center' || value === 'right') {
126637
126773
  return value;
@@ -126847,6 +126983,15 @@ const transformAnchor = (jsx) => {
126847
126983
  position: jsx.position,
126848
126984
  };
126849
126985
  };
126986
+ /**
126987
+ * Parses an image caption's markdown. The caption is re-parsed on its own, so the
126988
+ * children's positions index into it rather than the document.
126989
+ */
126990
+ const parseCaptionChildren = (caption) => {
126991
+ const { children } = lib_mdast(caption);
126992
+ stampReparseSource(children, caption);
126993
+ return children;
126994
+ };
126850
126995
  /**
126851
126996
  * Transforms an `<Image />` JSX element into an image-block MDAST node.
126852
126997
  * Normalizes attributes (align, border, width→sizing) and parses caption markdown into children.
@@ -126877,7 +127022,7 @@ const transformImage = (jsx) => {
126877
127022
  alt,
126878
127023
  border: toBool(border),
126879
127024
  caption,
126880
- children: caption ? lib_mdast(caption).children : [],
127025
+ children: caption ? parseCaptionChildren(caption) : [],
126881
127026
  className,
126882
127027
  framed: toBool(framed),
126883
127028
  height: height !== undefined ? String(height) : undefined,
@@ -127073,10 +127218,40 @@ const wrapBareCellsInRow = (node) => {
127073
127218
  });
127074
127219
  };
127075
127220
  /**
127076
- * Converts a JSX <Table> element to an MDAST table node with alignment.
127077
- * Returns null for header-less tables since MDAST always promotes the first row to <thead>.
127221
+ * A lowercase <table> reaches here only because `mdxishTables` kept it as JSX for its
127222
+ * attributes. Widths on first-row cells are the one attribute mdast can carry; anything
127223
+ * else stays JSX so it still renders.
127224
+ */
127225
+ const lowercaseTableIsConvertible = (jsx) => {
127226
+ if (jsx.attributes.length > 0)
127227
+ return false;
127228
+ const headerCells = new Set();
127229
+ let headerRowSeen = false;
127230
+ let convertible = true;
127231
+ visit(jsx, isMDXElement, (child) => {
127232
+ if (child.name === 'tr' && !headerRowSeen) {
127233
+ headerRowSeen = true;
127234
+ visit(child, mdxish_jsx_to_mdast_isTableCell, cell => {
127235
+ headerCells.add(cell);
127236
+ });
127237
+ }
127238
+ if (child.name === null || !tableTags.has(child.name) || child.attributes.length === 0)
127239
+ return;
127240
+ if (!headerCells.has(child) || !hasOnlyWidthAttributes(child) || getCellWidth(child) === null) {
127241
+ convertible = false;
127242
+ }
127243
+ });
127244
+ return convertible;
127245
+ };
127246
+ /**
127247
+ * Converts a JSX <Table>, or a lowercase <table> carrying only widths, to an MDAST table
127248
+ * node with alignment and widths. Returns null for header-less tables since MDAST always
127249
+ * promotes the first row to <thead>.
127078
127250
  */
127079
127251
  const transformTable = (jsx) => {
127252
+ const isLowercase = jsx.name === 'table';
127253
+ if (isLowercase && !lowercaseTableIsConvertible(jsx))
127254
+ return null;
127080
127255
  wrapBareCellsInRow(jsx);
127081
127256
  let hasThead = false;
127082
127257
  visit(jsx, isMDXElement, (child) => {
@@ -127088,6 +127263,7 @@ const transformTable = (jsx) => {
127088
127263
  const { align: alignAttr } = getAttrs(jsx);
127089
127264
  const align = Array.isArray(alignAttr) ? alignAttr : null;
127090
127265
  const rows = [];
127266
+ const widths = [];
127091
127267
  visit(jsx, isMDXElement, (child) => {
127092
127268
  if (child.name !== 'thead' && child.name !== 'tbody')
127093
127269
  return;
@@ -127095,6 +127271,7 @@ const transformTable = (jsx) => {
127095
127271
  if (row.name !== 'tr')
127096
127272
  return;
127097
127273
  const cells = [];
127274
+ const isHeaderRow = rows.length === 0;
127098
127275
  visit(row, mdxish_jsx_to_mdast_isTableCell, (cell) => {
127099
127276
  const parsedChildren = unwrapSoleParagraph(cell.children);
127100
127277
  cells.push({
@@ -127102,6 +127279,8 @@ const transformTable = (jsx) => {
127102
127279
  children: parsedChildren,
127103
127280
  position: cell.position,
127104
127281
  });
127282
+ if (isHeaderRow)
127283
+ widths.push(getCellWidth(cell));
127105
127284
  });
127106
127285
  rows.push({
127107
127286
  type: 'tableRow',
@@ -127114,11 +127293,16 @@ const transformTable = (jsx) => {
127114
127293
  const alignArray = align && columnCount > 0
127115
127294
  ? align.slice(0, columnCount).concat(Array.from({ length: Math.max(0, columnCount - align.length) }, () => null))
127116
127295
  : Array.from({ length: columnCount }, () => null);
127296
+ const data = {
127297
+ ...(isLowercase && { lowercaseTable: true }),
127298
+ ...(widths.some(Boolean) && { widths }),
127299
+ };
127117
127300
  return {
127118
127301
  type: 'table',
127119
127302
  align: alignArray,
127120
127303
  position: jsx.position,
127121
127304
  children: rows,
127305
+ ...(Object.keys(data).length > 0 && { data }),
127122
127306
  };
127123
127307
  };
127124
127308
  /**
@@ -127148,6 +127332,7 @@ const COMPONENT_MAP = {
127148
127332
  figure: transformFigure,
127149
127333
  Recipe: transformRecipe,
127150
127334
  Table: transformTable,
127335
+ table: transformTable,
127151
127336
  };
127152
127337
  /**
127153
127338
  * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
@@ -127174,8 +127359,7 @@ const mdxishJsxToMdast = () => tree => {
127174
127359
  const newNode = transformer(node);
127175
127360
  if (!newNode)
127176
127361
  return;
127177
- // Replace the JSX node with the MDAST node
127178
- parent.children[index] = newNode;
127362
+ replaceInheritingReparseSource(parent, index, [newNode]);
127179
127363
  });
127180
127364
  // Inline JSX components (Anchor)
127181
127365
  visit(tree, 'mdxJsxTextElement', (node, index, parent) => {
@@ -127627,25 +127811,15 @@ const restoreBooleanProperties = () => tree => {
127627
127811
  /* unused harmony import specifier */ var mdxish_tables_to_jsx_phrasing;
127628
127812
  /* unused harmony import specifier */ var mdxish_tables_to_jsx_visit;
127629
127813
  /* unused harmony import specifier */ var mdxish_tables_to_jsx_NodeTypes;
127814
+ /* unused harmony import specifier */ var cellStyle;
127630
127815
  /* unused harmony import specifier */ var hasChildren;
127631
127816
  /* unused harmony import specifier */ var normalizeCellChildrenForGfm;
127632
127817
 
127633
127818
 
127634
127819
 
127635
127820
 
127821
+
127636
127822
  const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
127637
- const mdxish_tables_to_jsx_alignToStyle = (align) => {
127638
- if (!align || align === 'left')
127639
- return null;
127640
- return {
127641
- type: 'mdxJsxAttribute',
127642
- name: 'style',
127643
- value: {
127644
- type: 'mdxJsxAttributeValueExpression',
127645
- value: `{ textAlign: "${align}" }`,
127646
- },
127647
- };
127648
- };
127649
127823
  const mdxish_tables_to_jsx_isTableCell = (node) => ['tableHead', 'tableCell'].includes(node.type);
127650
127824
  const mdxish_tables_to_jsx_isLiteral = (node) => 'value' in node;
127651
127825
  /**
@@ -127701,12 +127875,17 @@ const mdxishTablesToJsx = () => tree => {
127701
127875
  gfmCells.push([cell, normalized]);
127702
127876
  return undefined;
127703
127877
  });
127704
- const stayLowercase = table.data?.lowercaseTable === true;
127878
+ const widths = table.data?.widths ?? [];
127879
+ const hasWidths = widths.some(Boolean);
127880
+ // Lowercase cells can carry a width but not an alignment, so an aligned table becomes <Table>
127881
+ const hasAlignment = table.align.some(align => align && align !== 'left');
127882
+ const stayLowercase = table.data?.lowercaseTable === true && !hasAlignment;
127705
127883
  // We transform to GFM tables if:
127706
127884
  // 1. If it doesn't contain complex elements that the syntax can't represent
127707
- // 2. The original table is not lowercase HTML <table>, because we want to
127885
+ // 2. The original table is not lowercase HTML <table>, because we want to
127708
127886
  // preserve original tables as much as possible
127709
- if (!requiresJsxTable && !stayLowercase) {
127887
+ // 3. No column has a width, which GFM can't express
127888
+ if (!requiresJsxTable && !stayLowercase && !hasWidths) {
127710
127889
  gfmCells.forEach(([cell, children]) => {
127711
127890
  cell.children = children;
127712
127891
  });
@@ -127718,7 +127897,8 @@ const mdxishTablesToJsx = () => tree => {
127718
127897
  if (!headerRow)
127719
127898
  return;
127720
127899
  mdxish_tables_to_jsx_visit(table, mdxish_tables_to_jsx_isTableCell, flattenBreaksToNewlines);
127721
- const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
127900
+ const headerStyles = table.align.map((align, i) => cellStyle(align, widths[i] ?? null, { html: stayLowercase }));
127901
+ const bodyStyles = table.align.map(align => cellStyle(align, null, { html: stayLowercase }));
127722
127902
  const head = {
127723
127903
  attributes: [],
127724
127904
  type: 'mdxJsxFlowElement',
@@ -127734,7 +127914,7 @@ const mdxishTablesToJsx = () => tree => {
127734
127914
  type: 'mdxJsxFlowElement',
127735
127915
  name: 'th',
127736
127916
  children: cell.children,
127737
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
127917
+ ...(headerStyles[cellIndex] && { attributes: [headerStyles[cellIndex]] }),
127738
127918
  };
127739
127919
  }),
127740
127920
  },
@@ -127754,7 +127934,7 @@ const mdxishTablesToJsx = () => tree => {
127754
127934
  type: 'mdxJsxFlowElement',
127755
127935
  name: 'td',
127756
127936
  children: cell.children,
127757
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
127937
+ ...(bodyStyles[cellIndex] && { attributes: [bodyStyles[cellIndex]] }),
127758
127938
  };
127759
127939
  }),
127760
127940
  };
@@ -129266,7 +129446,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
129266
129446
  /******/ // startup
129267
129447
  /******/ // Load entry module and return exports
129268
129448
  /******/ // This entry module used 'module' so it can't be inlined
129269
- /******/ let __webpack_exports__ = __webpack_require__(6829);
129449
+ /******/ let __webpack_exports__ = __webpack_require__(1186);
129270
129450
  /******/ module.exports = __webpack_exports__;
129271
129451
  /******/
129272
129452
  /******/ })()