@readme/markdown 15.7.3 → 15.9.0

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
- /***/ 5072
19048
+ /***/ 8900
19049
19049
  (module, __webpack_exports__, __webpack_require__) {
19050
19050
 
19051
19051
  "use strict";
@@ -92178,9 +92178,9 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
92178
92178
  const safeMode = typeof safeModeRaw !== 'boolean' ? safeModeRaw === 'true' : safeModeRaw;
92179
92179
  const [cleanedHtml, exec] = extractScripts(html);
92180
92180
  (0,external_react_.useEffect)(() => {
92181
- if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
92181
+ if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts && !safeMode)
92182
92182
  exec();
92183
- }, [runScripts, exec]);
92183
+ }, [runScripts, safeMode, exec]);
92184
92184
  if (nonStringChildren) {
92185
92185
  // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
92186
92186
  // raw string) should never throw, so render the child nodes directly
@@ -114138,6 +114138,133 @@ const hardBreaks = () => tree => {
114138
114138
  };
114139
114139
  /* harmony default export */ const hard_breaks = (hardBreaks);
114140
114140
 
114141
+ ;// ./processor/plugin/strip-tags.ts
114142
+
114143
+ /**
114144
+ * Tags removed from user-provided content because rendering them executes in the
114145
+ * page. Add an entry to cover another vector; nothing else needs to change.
114146
+ *
114147
+ * Deliberately narrow for now — `<script>` is the only vector this plugin claims
114148
+ * to close. Broader parity with the `md` sanitization schema (`javascript:` URLs,
114149
+ * `on*` handlers, `<iframe>`, `<object>`, …) is tracked in readmeio/markdown#1526.
114150
+ */
114151
+ const STRIPPED_TAG_NAMES = new Set(['script']);
114152
+ /** JSX names starting with a capital are component references, not literal tags. */
114153
+ const LITERAL_TAG_NAME = /^[a-z]/;
114154
+ /**
114155
+ * Whether a node would render as one of the stripped literal DOM elements.
114156
+ * Browsers match tag names case-insensitively, so `<sCrIpT>` executes too.
114157
+ *
114158
+ * `<Script />` and friends are component references and are left alone.
114159
+ */
114160
+ const isStrippedTag = (node) => {
114161
+ if (node.type === 'element')
114162
+ return STRIPPED_TAG_NAMES.has(node.tagName.toLowerCase());
114163
+ if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
114164
+ const name = node.name ?? '';
114165
+ return LITERAL_TAG_NAME.test(name) && STRIPPED_TAG_NAMES.has(name.toLowerCase());
114166
+ }
114167
+ return false;
114168
+ };
114169
+ /**
114170
+ * Removes matching elements and their subtrees when `sanitize` is enabled.
114171
+ *
114172
+ * Explicit `HTMLBlock`s are an intentional exception, matching legacy: their
114173
+ * scripts live in a string prop rather than as elements, so they never appear
114174
+ * in SSR HTML, and they only execute client-side when the author opts in via
114175
+ * `runScripts`.
114176
+ */
114177
+ const rehypeStripTags = () => {
114178
+ return (tree) => {
114179
+ visit(tree, isStrippedTag, (_node, index, parent) => {
114180
+ parent.children.splice(index, 1);
114181
+ return [(/* inlined export .SKIP */"skip"), index];
114182
+ });
114183
+ };
114184
+ };
114185
+ /** The automatic-runtime factories MDX compiles JSX into. */
114186
+ const JSX_FACTORIES = new Set(['_jsx', '_jsxs', '_jsxDEV']);
114187
+ /**
114188
+ * Matches raw JSX and compiled `_jsx('tag', …)` calls. MDX may rewrite literal
114189
+ * tags as `_components.<tag>` so a `components` prop can override them.
114190
+ */
114191
+ const isStrippedJsxElement = (node) => {
114192
+ if (node.type === 'JSXElement') {
114193
+ const { name } = node.openingElement;
114194
+ if (name.type === 'JSXIdentifier') {
114195
+ return LITERAL_TAG_NAME.test(name.name) && STRIPPED_TAG_NAMES.has(name.name.toLowerCase());
114196
+ }
114197
+ return (name.type === 'JSXMemberExpression' &&
114198
+ name.object.type === 'JSXIdentifier' &&
114199
+ name.object.name === '_components' &&
114200
+ STRIPPED_TAG_NAMES.has(name.property.name.toLowerCase()));
114201
+ }
114202
+ if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && JSX_FACTORIES.has(node.callee.name)) {
114203
+ const [tag] = node.arguments;
114204
+ if (!tag)
114205
+ return false;
114206
+ if (tag.type === 'Literal')
114207
+ return typeof tag.value === 'string' && STRIPPED_TAG_NAMES.has(tag.value.toLowerCase());
114208
+ return (tag.type === 'MemberExpression' &&
114209
+ tag.object.type === 'Identifier' &&
114210
+ tag.object.name === '_components' &&
114211
+ tag.property.type === 'Identifier' &&
114212
+ STRIPPED_TAG_NAMES.has(tag.property.name.toLowerCase()));
114213
+ }
114214
+ return false;
114215
+ };
114216
+ const isEstreeNode = (value) => typeof value === 'object' && value !== null && typeof value.type === 'string';
114217
+ const nullLiteral = () => ({ type: 'Literal', value: null });
114218
+ /**
114219
+ * JSX inside expressions and exports stays in ESTree, outside the HAST pass.
114220
+ * Strip it before evaluation in mdxish or after JSX compilation in MDX.
114221
+ *
114222
+ * Elements are spliced out of JSX children and replaced with `null` anywhere
114223
+ * else, which React renders as nothing.
114224
+ */
114225
+ const stripJsxTags = (program) => {
114226
+ const walk = (node) => {
114227
+ const record = node;
114228
+ Object.keys(record).forEach(key => {
114229
+ if (key === 'loc' || key === 'range' || key === 'position')
114230
+ return;
114231
+ const value = record[key];
114232
+ if (Array.isArray(value)) {
114233
+ for (let i = value.length - 1; i >= 0; i -= 1) {
114234
+ const child = value[i];
114235
+ if (isEstreeNode(child)) {
114236
+ if (isStrippedJsxElement(child)) {
114237
+ if (key === 'children')
114238
+ value.splice(i, 1);
114239
+ else
114240
+ value[i] = nullLiteral();
114241
+ }
114242
+ else {
114243
+ walk(child);
114244
+ }
114245
+ }
114246
+ }
114247
+ return;
114248
+ }
114249
+ if (!isEstreeNode(value))
114250
+ return;
114251
+ if (isStrippedJsxElement(value)) {
114252
+ record[key] =
114253
+ node.type === 'JSXAttribute' ? { type: 'JSXExpressionContainer', expression: nullLiteral() } : nullLiteral();
114254
+ }
114255
+ else {
114256
+ walk(value);
114257
+ }
114258
+ });
114259
+ };
114260
+ walk(program);
114261
+ return program;
114262
+ };
114263
+ /** `stripJsxTags` as a recma plugin, for the `mdx` compile pipeline. */
114264
+ const recmaStripTags = () => tree => {
114265
+ stripJsxTags(tree);
114266
+ };
114267
+
114141
114268
  ;// ./node_modules/estree-util-value-to-estree/dist/estree-util-value-to-estree.js
114142
114269
  /**
114143
114270
  * Create an ESTree identifier node for a given name.
@@ -116875,6 +117002,7 @@ const tocHastToMdx = (toc, components, variables) => {
116875
117002
 
116876
117003
 
116877
117004
 
117005
+
116878
117006
  const sanitizeSchema = cjs_default()(defaultSchema, {
116879
117007
  attributes: {
116880
117008
  a: ['target'],
@@ -116883,7 +117011,10 @@ const sanitizeSchema = cjs_default()(defaultSchema, {
116883
117011
  href: ['doc', 'ref', 'blog', 'changelog', 'page'],
116884
117012
  },
116885
117013
  });
116886
- const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, hardBreaks, ...opts } = {}) => {
117014
+ const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, hardBreaks, sanitize = false,
117015
+ // Pulled out of `...opts` so a caller's plugins extend the pipeline instead of
117016
+ // replacing it — otherwise the spread below would drop `rehypeStripTags`.
117017
+ remarkPlugins: userRemarkPlugins, rehypePlugins: userRehypePlugins, recmaPlugins: userRecmaPlugins, ...opts } = {}) => {
116887
117018
  // Destructure at runtime to avoid circular dependency issues
116888
117019
  const { codeTabsTransformer, ...transforms } = defaultTransforms;
116889
117020
  const remarkPlugins = [
@@ -116901,7 +117032,12 @@ const compile_compile = (text, { components = {}, missingComponents, copyButtons
116901
117032
  if (useTailwind) {
116902
117033
  remarkPlugins.push([transform_tailwind, { components }]);
116903
117034
  }
116904
- const rehypePlugins = [...ast_processor_rehypePlugins, [rehypeToc, { components }]];
117035
+ remarkPlugins.push(...(userRemarkPlugins ?? []));
117036
+ const rehypePlugins = [
117037
+ ...ast_processor_rehypePlugins,
117038
+ [rehypeToc, { components }],
117039
+ ...(userRehypePlugins ?? []),
117040
+ ];
116905
117041
  if (opts.format === 'md') {
116906
117042
  /**
116907
117043
  * When running in `md` format we need to sanitize the content for security reasons.
@@ -116919,12 +117055,23 @@ const compile_compile = (text, { components = {}, missingComponents, copyButtons
116919
117055
  ]);
116920
117056
  rehypePlugins.push([rehypeSanitize, sanitizeSchema]);
116921
117057
  }
117058
+ const recmaPlugins = [...(userRecmaPlugins ?? [])];
117059
+ // In `mdx` format a literal <script> parses as JSX rather than raw HTML, so it
117060
+ // bypasses sanitization entirely — strip it in every format. Must stay last:
117061
+ // in `md` format raw HTML isn't an element until `rehypeRaw` has run. A tag
117062
+ // inside an expression or export is code, not an element, so the recma pass
117063
+ // catches it in the compiled program instead.
117064
+ if (sanitize) {
117065
+ rehypePlugins.push(rehypeStripTags);
117066
+ recmaPlugins.push(recmaStripTags);
117067
+ }
116922
117068
  try {
116923
117069
  const vfile = compileSync(text, {
116924
117070
  outputFormat: 'function-body',
116925
117071
  providerImportSource: '#',
116926
117072
  remarkPlugins,
116927
117073
  rehypePlugins,
117074
+ recmaPlugins,
116928
117075
  ...opts,
116929
117076
  });
116930
117077
  const string = String(vfile)
@@ -122278,6 +122425,32 @@ const mdxComponentHandlers = {
122278
122425
  [NodeTypes.htmlBlock]: htmlBlockHandler,
122279
122426
  };
122280
122427
 
122428
+ ;// ./processor/plugin/safe-mode-html-blocks.ts
122429
+
122430
+
122431
+ /**
122432
+ * Whether a tag name renders through the `HTMLBlock` component. Mirrors the
122433
+ * separator-agnostic, case-insensitive lookup in `getComponentName` and the
122434
+ * rehype-react component map, so `html-block`, `HTMLBlock`, `HtmlBlock` and
122435
+ * `htmlblock` all match.
122436
+ */
122437
+ const isHtmlBlockTag = (tagName) => toPascalCase(tagName).toLowerCase() === 'htmlblock';
122438
+ /**
122439
+ * Forces `safeMode` on every element that renders through `HTMLBlock` so it is
122440
+ * shown as escaped text instead of injected.
122441
+ *
122442
+ * Runs last, so it sees every producer of the element — `[block:html]`,
122443
+ * `<HTMLBlock>` with a template body or an `html` attribute, and a literal
122444
+ * `<html-block>` — and it is unconditional so an author-supplied
122445
+ * `safeMode="false"` can't opt out.
122446
+ */
122447
+ const enforceSafeModeHtmlBlocks = () => tree => {
122448
+ visit(tree, 'element', node => {
122449
+ if (isHtmlBlockTag(node.tagName))
122450
+ node.properties.safeMode = 'true';
122451
+ });
122452
+ };
122453
+
122281
122454
  ;// ./processor/transform/mdxish/anchor-to-jsx.ts
122282
122455
  /* unused harmony import specifier */ var anchor_to_jsx_visit;
122283
122456
  /* unused harmony import specifier */ var anchor_to_jsx_NodeTypes;
@@ -123598,6 +123771,7 @@ const collectImportValues = (importDeclarations, registry = defaultModuleRegistr
123598
123771
 
123599
123772
 
123600
123773
 
123774
+
123601
123775
  /**
123602
123776
  * Recursively extract all identifier names introduced by a binding pattern.
123603
123777
  * Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
@@ -123642,7 +123816,7 @@ const collectExportNames = (declaration) => {
123642
123816
  * Any evaluation error is consumed and logged. We don't throw because it's
123643
123817
  * against the spirit of this engine to be less permissive than MDX needs.
123644
123818
  */
123645
- const evaluateExports = () => (tree, file) => {
123819
+ const evaluateExports = (opts) => (tree, file) => {
123646
123820
  const programBody = [];
123647
123821
  const exportNames = [];
123648
123822
  const importDeclarations = [];
@@ -123688,6 +123862,8 @@ const evaluateExports = () => (tree, file) => {
123688
123862
  // Evaluate the declarations together at once in a single sandboxed Function
123689
123863
  try {
123690
123864
  const program = { type: 'Program', sourceType: 'module', body: programBody };
123865
+ if (opts?.sanitize)
123866
+ stripJsxTags(program);
123691
123867
  buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
123692
123868
  const { value: source } = toJs(program);
123693
123869
  // Make sure import values are available in the scope
@@ -125997,7 +126173,7 @@ const parseApiHeaderTitle = (text) => {
125997
126173
  * Transform a magicBlock node into final MDAST nodes.
125998
126174
  */
125999
126175
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
126000
- const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
126176
+ const { compatibilityMode = false, hardBreaks = true } = options;
126001
126177
  // Handle empty data by returning placeholder nodes for known block types
126002
126178
  // This allows the editor to show appropriate placeholder UI instead of nothing
126003
126179
  if (Object.keys(data).length < 1) {
@@ -126215,7 +126391,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
126215
126391
  wrapPinnedBlocks({
126216
126392
  data: {
126217
126393
  hName: 'html-block',
126218
- hProperties: { html: htmlJson.html, runScripts: compatibilityMode, safeMode },
126394
+ hProperties: { html: htmlJson.html, runScripts: compatibilityMode },
126219
126395
  },
126220
126396
  type: 'html-block',
126221
126397
  }, data),
@@ -126475,6 +126651,80 @@ const mdxishHtmlBlocks = () => tree => {
126475
126651
  };
126476
126652
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
126477
126653
 
126654
+ ;// ./processor/transform/mdxish/tables/cell-width.ts
126655
+
126656
+
126657
+ // Key must follow `{` or `,` so `minWidth`/`maxWidth` don't match on their suffix
126658
+ const STYLE_OBJECT_WIDTH_REGEX = /[{,]\s*["']?width["']?\s*:\s*(?:"([^"]*)"|'([^']*)'|([^,}]+))/i;
126659
+ // First colon only, so `url(http://…)` values stay intact
126660
+ const CSS_DECLARATION_REGEX = /:(.*)/s;
126661
+ const UNITLESS_NUMBER_REGEX = /^\d+(?:\.\d+)?$/;
126662
+ // HTML reads a `width` attribute as a leading number plus optional `%`, ignoring the rest
126663
+ const HTML_DIMENSION_REGEX = /^\s*(\d+(?:\.\d+)?)\s*(%?)/;
126664
+ /** Bare numbers are pixels. A value carrying declaration separators is not a single width. */
126665
+ const normalizeWidth = (value) => {
126666
+ if (typeof value === 'number')
126667
+ return `${value}px`;
126668
+ if (typeof value !== 'string' || !value.trim())
126669
+ return null;
126670
+ const trimmed = value.trim();
126671
+ if (/[;:{}]/.test(trimmed))
126672
+ return null;
126673
+ return UNITLESS_NUMBER_REGEX.test(trimmed) ? `${trimmed}px` : trimmed;
126674
+ };
126675
+ const widthFromAttribute = (value) => {
126676
+ if (typeof value === 'number')
126677
+ return `${value}px`;
126678
+ if (typeof value !== 'string')
126679
+ return null;
126680
+ const match = HTML_DIMENSION_REGEX.exec(value);
126681
+ return match ? `${match[1]}${match[2] || 'px'}` : null;
126682
+ };
126683
+ const cssPropertyNames = (style) => style
126684
+ .split(';')
126685
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX)[0].trim().toLowerCase())
126686
+ .filter(Boolean);
126687
+ /** Handles a CSS declaration list and a style object safe mode left as a string (`{ width: "30%" }`). */
126688
+ const widthFromStyleString = (style) => {
126689
+ const trimmed = style.trim();
126690
+ if (trimmed.startsWith('{')) {
126691
+ return STYLE_OBJECT_WIDTH_REGEX.exec(trimmed)?.slice(1).find(Boolean);
126692
+ }
126693
+ return trimmed
126694
+ .split(';')
126695
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX))
126696
+ .find(([property]) => property.trim().toLowerCase() === 'width')?.[1];
126697
+ };
126698
+ /** Accepts `style={{ width }}`, `style="width: …"` and the hand-authored `width="…"`. */
126699
+ const getCellWidth = (cell) => {
126700
+ const { style, width } = getAttrs(cell);
126701
+ let styleWidth;
126702
+ if (style_object_to_css_isPlainObject(style)) {
126703
+ styleWidth = style.width;
126704
+ }
126705
+ else if (typeof style === 'string') {
126706
+ styleWidth = widthFromStyleString(style);
126707
+ }
126708
+ return normalizeWidth(styleWidth) ?? widthFromAttribute(width);
126709
+ };
126710
+ /** True when the cell's attributes state nothing but its width, which mdast can carry. */
126711
+ const hasOnlyWidthAttributes = (cell) => {
126712
+ if (cell.attributes.length === 0)
126713
+ return false;
126714
+ const { style } = getAttrs(cell);
126715
+ return cell.attributes.every(attribute => {
126716
+ if (!('name' in attribute))
126717
+ return false;
126718
+ if (attribute.name === 'width')
126719
+ return true;
126720
+ if (attribute.name !== 'style')
126721
+ return false;
126722
+ if (style_object_to_css_isPlainObject(style))
126723
+ return Object.keys(style).every(key => key === 'width');
126724
+ return typeof style === 'string' && cssPropertyNames(style).every(property => property === 'width');
126725
+ });
126726
+ };
126727
+
126478
126728
  ;// ./processor/transform/mdxish/mdxish-jsx-to-mdast.ts
126479
126729
 
126480
126730
 
@@ -126482,6 +126732,7 @@ const mdxishHtmlBlocks = () => tree => {
126482
126732
 
126483
126733
 
126484
126734
 
126735
+
126485
126736
  function toImageAlign(value) {
126486
126737
  if (value === 'left' || value === 'center' || value === 'right') {
126487
126738
  return value;
@@ -126923,10 +127174,40 @@ const wrapBareCellsInRow = (node) => {
126923
127174
  });
126924
127175
  };
126925
127176
  /**
126926
- * Converts a JSX <Table> element to an MDAST table node with alignment.
126927
- * Returns null for header-less tables since MDAST always promotes the first row to <thead>.
127177
+ * A lowercase <table> reaches here only because `mdxishTables` kept it as JSX for its
127178
+ * attributes. Widths on first-row cells are the one attribute mdast can carry; anything
127179
+ * else stays JSX so it still renders.
127180
+ */
127181
+ const lowercaseTableIsConvertible = (jsx) => {
127182
+ if (jsx.attributes.length > 0)
127183
+ return false;
127184
+ const headerCells = new Set();
127185
+ let headerRowSeen = false;
127186
+ let convertible = true;
127187
+ visit(jsx, isMDXElement, (child) => {
127188
+ if (child.name === 'tr' && !headerRowSeen) {
127189
+ headerRowSeen = true;
127190
+ visit(child, mdxish_jsx_to_mdast_isTableCell, cell => {
127191
+ headerCells.add(cell);
127192
+ });
127193
+ }
127194
+ if (child.name === null || !tableTags.has(child.name) || child.attributes.length === 0)
127195
+ return;
127196
+ if (!headerCells.has(child) || !hasOnlyWidthAttributes(child) || getCellWidth(child) === null) {
127197
+ convertible = false;
127198
+ }
127199
+ });
127200
+ return convertible;
127201
+ };
127202
+ /**
127203
+ * Converts a JSX <Table>, or a lowercase <table> carrying only widths, to an MDAST table
127204
+ * node with alignment and widths. Returns null for header-less tables since MDAST always
127205
+ * promotes the first row to <thead>.
126928
127206
  */
126929
127207
  const transformTable = (jsx) => {
127208
+ const isLowercase = jsx.name === 'table';
127209
+ if (isLowercase && !lowercaseTableIsConvertible(jsx))
127210
+ return null;
126930
127211
  wrapBareCellsInRow(jsx);
126931
127212
  let hasThead = false;
126932
127213
  visit(jsx, isMDXElement, (child) => {
@@ -126938,6 +127219,7 @@ const transformTable = (jsx) => {
126938
127219
  const { align: alignAttr } = getAttrs(jsx);
126939
127220
  const align = Array.isArray(alignAttr) ? alignAttr : null;
126940
127221
  const rows = [];
127222
+ const widths = [];
126941
127223
  visit(jsx, isMDXElement, (child) => {
126942
127224
  if (child.name !== 'thead' && child.name !== 'tbody')
126943
127225
  return;
@@ -126945,6 +127227,7 @@ const transformTable = (jsx) => {
126945
127227
  if (row.name !== 'tr')
126946
127228
  return;
126947
127229
  const cells = [];
127230
+ const isHeaderRow = rows.length === 0;
126948
127231
  visit(row, mdxish_jsx_to_mdast_isTableCell, (cell) => {
126949
127232
  const parsedChildren = unwrapSoleParagraph(cell.children);
126950
127233
  cells.push({
@@ -126952,6 +127235,8 @@ const transformTable = (jsx) => {
126952
127235
  children: parsedChildren,
126953
127236
  position: cell.position,
126954
127237
  });
127238
+ if (isHeaderRow)
127239
+ widths.push(getCellWidth(cell));
126955
127240
  });
126956
127241
  rows.push({
126957
127242
  type: 'tableRow',
@@ -126964,11 +127249,16 @@ const transformTable = (jsx) => {
126964
127249
  const alignArray = align && columnCount > 0
126965
127250
  ? align.slice(0, columnCount).concat(Array.from({ length: Math.max(0, columnCount - align.length) }, () => null))
126966
127251
  : Array.from({ length: columnCount }, () => null);
127252
+ const data = {
127253
+ ...(isLowercase && { lowercaseTable: true }),
127254
+ ...(widths.some(Boolean) && { widths }),
127255
+ };
126967
127256
  return {
126968
127257
  type: 'table',
126969
127258
  align: alignArray,
126970
127259
  position: jsx.position,
126971
127260
  children: rows,
127261
+ ...(Object.keys(data).length > 0 && { data }),
126972
127262
  };
126973
127263
  };
126974
127264
  /**
@@ -126998,6 +127288,7 @@ const COMPONENT_MAP = {
126998
127288
  figure: transformFigure,
126999
127289
  Recipe: transformRecipe,
127000
127290
  Table: transformTable,
127291
+ table: transformTable,
127001
127292
  };
127002
127293
  /**
127003
127294
  * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
@@ -127477,25 +127768,15 @@ const restoreBooleanProperties = () => tree => {
127477
127768
  /* unused harmony import specifier */ var mdxish_tables_to_jsx_phrasing;
127478
127769
  /* unused harmony import specifier */ var mdxish_tables_to_jsx_visit;
127479
127770
  /* unused harmony import specifier */ var mdxish_tables_to_jsx_NodeTypes;
127771
+ /* unused harmony import specifier */ var cellStyle;
127480
127772
  /* unused harmony import specifier */ var hasChildren;
127481
127773
  /* unused harmony import specifier */ var normalizeCellChildrenForGfm;
127482
127774
 
127483
127775
 
127484
127776
 
127485
127777
 
127778
+
127486
127779
  const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
127487
- const mdxish_tables_to_jsx_alignToStyle = (align) => {
127488
- if (!align || align === 'left')
127489
- return null;
127490
- return {
127491
- type: 'mdxJsxAttribute',
127492
- name: 'style',
127493
- value: {
127494
- type: 'mdxJsxAttributeValueExpression',
127495
- value: `{ textAlign: "${align}" }`,
127496
- },
127497
- };
127498
- };
127499
127780
  const mdxish_tables_to_jsx_isTableCell = (node) => ['tableHead', 'tableCell'].includes(node.type);
127500
127781
  const mdxish_tables_to_jsx_isLiteral = (node) => 'value' in node;
127501
127782
  /**
@@ -127551,12 +127832,17 @@ const mdxishTablesToJsx = () => tree => {
127551
127832
  gfmCells.push([cell, normalized]);
127552
127833
  return undefined;
127553
127834
  });
127554
- const stayLowercase = table.data?.lowercaseTable === true;
127835
+ const widths = table.data?.widths ?? [];
127836
+ const hasWidths = widths.some(Boolean);
127837
+ // Lowercase cells can carry a width but not an alignment, so an aligned table becomes <Table>
127838
+ const hasAlignment = table.align.some(align => align && align !== 'left');
127839
+ const stayLowercase = table.data?.lowercaseTable === true && !hasAlignment;
127555
127840
  // We transform to GFM tables if:
127556
127841
  // 1. If it doesn't contain complex elements that the syntax can't represent
127557
- // 2. The original table is not lowercase HTML <table>, because we want to
127842
+ // 2. The original table is not lowercase HTML <table>, because we want to
127558
127843
  // preserve original tables as much as possible
127559
- if (!requiresJsxTable && !stayLowercase) {
127844
+ // 3. No column has a width, which GFM can't express
127845
+ if (!requiresJsxTable && !stayLowercase && !hasWidths) {
127560
127846
  gfmCells.forEach(([cell, children]) => {
127561
127847
  cell.children = children;
127562
127848
  });
@@ -127568,7 +127854,8 @@ const mdxishTablesToJsx = () => tree => {
127568
127854
  if (!headerRow)
127569
127855
  return;
127570
127856
  mdxish_tables_to_jsx_visit(table, mdxish_tables_to_jsx_isTableCell, flattenBreaksToNewlines);
127571
- const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
127857
+ const headerStyles = table.align.map((align, i) => cellStyle(align, widths[i] ?? null, { html: stayLowercase }));
127858
+ const bodyStyles = table.align.map(align => cellStyle(align, null, { html: stayLowercase }));
127572
127859
  const head = {
127573
127860
  attributes: [],
127574
127861
  type: 'mdxJsxFlowElement',
@@ -127584,7 +127871,7 @@ const mdxishTablesToJsx = () => tree => {
127584
127871
  type: 'mdxJsxFlowElement',
127585
127872
  name: 'th',
127586
127873
  children: cell.children,
127587
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
127874
+ ...(headerStyles[cellIndex] && { attributes: [headerStyles[cellIndex]] }),
127588
127875
  };
127589
127876
  }),
127590
127877
  },
@@ -127604,7 +127891,7 @@ const mdxishTablesToJsx = () => tree => {
127604
127891
  type: 'mdxJsxFlowElement',
127605
127892
  name: 'td',
127606
127893
  children: cell.children,
127607
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
127894
+ ...(bodyStyles[cellIndex] && { attributes: [bodyStyles[cellIndex]] }),
127608
127895
  };
127609
127896
  }),
127610
127897
  };
@@ -127883,6 +128170,8 @@ function loadComponents() {
127883
128170
 
127884
128171
 
127885
128172
 
128173
+
128174
+
127886
128175
 
127887
128176
 
127888
128177
 
@@ -128010,7 +128299,7 @@ function mdxishMdastToMd(mdast) {
128010
128299
  * @see .claude/context/MDXish/Processor Overview.md
128011
128300
  */
128012
128301
  function mdxish(mdContent, opts = {}) {
128013
- const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
128302
+ const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, sanitize = false, variables, } = opts;
128014
128303
  const components = {
128015
128304
  ...loadComponents(),
128016
128305
  ...userComponents,
@@ -128021,7 +128310,7 @@ function mdxish(mdContent, opts = {}) {
128021
128310
  const contentWithoutComments = restoreCodeBlocks(withoutComments, protectedCode);
128022
128311
  const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
128023
128312
  processor
128024
- .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
128313
+ .use(safeMode ? undefined : evaluate_exports, { sanitize }) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
128025
128314
  .use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
128026
128315
  .use(safeMode ? undefined : evaluate_expressions, { components, variables }) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
128027
128316
  .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
@@ -128032,13 +128321,15 @@ function mdxish(mdContent, opts = {}) {
128032
128321
  .use(restoreBooleanProperties)
128033
128322
  .use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
128034
128323
  .use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
128324
+ .use(sanitize ? rehypeStripTags : undefined) // Strip STRIPPED_TAG_NAMES elements; this pipeline has no sanitization step
128035
128325
  .use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
128036
128326
  .use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
128037
128327
  .use(heading_slugs)
128038
128328
  .use(rehypeMdxishComponents, {
128039
128329
  components,
128040
128330
  processMarkdown: (markdown) => mdxish(markdown, opts),
128041
- });
128331
+ })
128332
+ .use(safeMode ? enforceSafeModeHtmlBlocks : undefined); // Force safeMode on every HTMLBlock; runs last so every producer is covered
128042
128333
  const vfile = new VFile({ value: parserReadyContent });
128043
128334
  const mdast = processor.parse(parserReadyContent);
128044
128335
  const hast = processor.runSync(mdast, vfile);
@@ -129114,7 +129405,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
129114
129405
  /******/ // startup
129115
129406
  /******/ // Load entry module and return exports
129116
129407
  /******/ // This entry module used 'module' so it can't be inlined
129117
- /******/ let __webpack_exports__ = __webpack_require__(5072);
129408
+ /******/ let __webpack_exports__ = __webpack_require__(8900);
129118
129409
  /******/ module.exports = __webpack_exports__;
129119
129410
  /******/
129120
129411
  /******/ })()