@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.
package/dist/main.node.js CHANGED
@@ -19045,7 +19045,7 @@ module.exports = function () {
19045
19045
 
19046
19046
  /***/ },
19047
19047
 
19048
- /***/ 6817
19048
+ /***/ 5789
19049
19049
  (module, __webpack_exports__, __webpack_require__) {
19050
19050
 
19051
19051
  "use strict";
@@ -24743,9 +24743,9 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
24743
24743
  const safeMode = typeof safeModeRaw !== 'boolean' ? safeModeRaw === 'true' : safeModeRaw;
24744
24744
  const [cleanedHtml, exec] = extractScripts(html);
24745
24745
  (0,external_react_.useEffect)(() => {
24746
- if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
24746
+ if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts && !safeMode)
24747
24747
  exec();
24748
- }, [runScripts, exec]);
24748
+ }, [runScripts, safeMode, exec]);
24749
24749
  if (nonStringChildren) {
24750
24750
  // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
24751
24751
  // raw string) should never throw, so render the child nodes directly
@@ -114192,6 +114192,133 @@ const hardBreaks = () => tree => {
114192
114192
  };
114193
114193
  /* harmony default export */ const hard_breaks = (hardBreaks);
114194
114194
 
114195
+ ;// ./processor/plugin/strip-tags.ts
114196
+
114197
+ /**
114198
+ * Tags removed from user-provided content because rendering them executes in the
114199
+ * page. Add an entry to cover another vector; nothing else needs to change.
114200
+ *
114201
+ * Deliberately narrow for now — `<script>` is the only vector this plugin claims
114202
+ * to close. Broader parity with the `md` sanitization schema (`javascript:` URLs,
114203
+ * `on*` handlers, `<iframe>`, `<object>`, …) is tracked in readmeio/markdown#1526.
114204
+ */
114205
+ const STRIPPED_TAG_NAMES = new Set(['script']);
114206
+ /** JSX names starting with a capital are component references, not literal tags. */
114207
+ const LITERAL_TAG_NAME = /^[a-z]/;
114208
+ /**
114209
+ * Whether a node would render as one of the stripped literal DOM elements.
114210
+ * Browsers match tag names case-insensitively, so `<sCrIpT>` executes too.
114211
+ *
114212
+ * `<Script />` and friends are component references and are left alone.
114213
+ */
114214
+ const isStrippedTag = (node) => {
114215
+ if (node.type === 'element')
114216
+ return STRIPPED_TAG_NAMES.has(node.tagName.toLowerCase());
114217
+ if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
114218
+ const name = node.name ?? '';
114219
+ return LITERAL_TAG_NAME.test(name) && STRIPPED_TAG_NAMES.has(name.toLowerCase());
114220
+ }
114221
+ return false;
114222
+ };
114223
+ /**
114224
+ * Removes matching elements and their subtrees when `sanitize` is enabled.
114225
+ *
114226
+ * Explicit `HTMLBlock`s are an intentional exception, matching legacy: their
114227
+ * scripts live in a string prop rather than as elements, so they never appear
114228
+ * in SSR HTML, and they only execute client-side when the author opts in via
114229
+ * `runScripts`.
114230
+ */
114231
+ const rehypeStripTags = () => {
114232
+ return (tree) => {
114233
+ visit(tree, isStrippedTag, (_node, index, parent) => {
114234
+ parent.children.splice(index, 1);
114235
+ return [(/* inlined export .SKIP */"skip"), index];
114236
+ });
114237
+ };
114238
+ };
114239
+ /** The automatic-runtime factories MDX compiles JSX into. */
114240
+ const JSX_FACTORIES = new Set(['_jsx', '_jsxs', '_jsxDEV']);
114241
+ /**
114242
+ * Matches raw JSX and compiled `_jsx('tag', …)` calls. MDX may rewrite literal
114243
+ * tags as `_components.<tag>` so a `components` prop can override them.
114244
+ */
114245
+ const isStrippedJsxElement = (node) => {
114246
+ if (node.type === 'JSXElement') {
114247
+ const { name } = node.openingElement;
114248
+ if (name.type === 'JSXIdentifier') {
114249
+ return LITERAL_TAG_NAME.test(name.name) && STRIPPED_TAG_NAMES.has(name.name.toLowerCase());
114250
+ }
114251
+ return (name.type === 'JSXMemberExpression' &&
114252
+ name.object.type === 'JSXIdentifier' &&
114253
+ name.object.name === '_components' &&
114254
+ STRIPPED_TAG_NAMES.has(name.property.name.toLowerCase()));
114255
+ }
114256
+ if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && JSX_FACTORIES.has(node.callee.name)) {
114257
+ const [tag] = node.arguments;
114258
+ if (!tag)
114259
+ return false;
114260
+ if (tag.type === 'Literal')
114261
+ return typeof tag.value === 'string' && STRIPPED_TAG_NAMES.has(tag.value.toLowerCase());
114262
+ return (tag.type === 'MemberExpression' &&
114263
+ tag.object.type === 'Identifier' &&
114264
+ tag.object.name === '_components' &&
114265
+ tag.property.type === 'Identifier' &&
114266
+ STRIPPED_TAG_NAMES.has(tag.property.name.toLowerCase()));
114267
+ }
114268
+ return false;
114269
+ };
114270
+ const isEstreeNode = (value) => typeof value === 'object' && value !== null && typeof value.type === 'string';
114271
+ const nullLiteral = () => ({ type: 'Literal', value: null });
114272
+ /**
114273
+ * JSX inside expressions and exports stays in ESTree, outside the HAST pass.
114274
+ * Strip it before evaluation in mdxish or after JSX compilation in MDX.
114275
+ *
114276
+ * Elements are spliced out of JSX children and replaced with `null` anywhere
114277
+ * else, which React renders as nothing.
114278
+ */
114279
+ const stripJsxTags = (program) => {
114280
+ const walk = (node) => {
114281
+ const record = node;
114282
+ Object.keys(record).forEach(key => {
114283
+ if (key === 'loc' || key === 'range' || key === 'position')
114284
+ return;
114285
+ const value = record[key];
114286
+ if (Array.isArray(value)) {
114287
+ for (let i = value.length - 1; i >= 0; i -= 1) {
114288
+ const child = value[i];
114289
+ if (isEstreeNode(child)) {
114290
+ if (isStrippedJsxElement(child)) {
114291
+ if (key === 'children')
114292
+ value.splice(i, 1);
114293
+ else
114294
+ value[i] = nullLiteral();
114295
+ }
114296
+ else {
114297
+ walk(child);
114298
+ }
114299
+ }
114300
+ }
114301
+ return;
114302
+ }
114303
+ if (!isEstreeNode(value))
114304
+ return;
114305
+ if (isStrippedJsxElement(value)) {
114306
+ record[key] =
114307
+ node.type === 'JSXAttribute' ? { type: 'JSXExpressionContainer', expression: nullLiteral() } : nullLiteral();
114308
+ }
114309
+ else {
114310
+ walk(value);
114311
+ }
114312
+ });
114313
+ };
114314
+ walk(program);
114315
+ return program;
114316
+ };
114317
+ /** `stripJsxTags` as a recma plugin, for the `mdx` compile pipeline. */
114318
+ const recmaStripTags = () => tree => {
114319
+ stripJsxTags(tree);
114320
+ };
114321
+
114195
114322
  ;// ./node_modules/estree-util-value-to-estree/dist/estree-util-value-to-estree.js
114196
114323
  /**
114197
114324
  * Create an ESTree identifier node for a given name.
@@ -116929,6 +117056,7 @@ const tocHastToMdx = (toc, components, variables) => {
116929
117056
 
116930
117057
 
116931
117058
 
117059
+
116932
117060
  const sanitizeSchema = cjs_default()(defaultSchema, {
116933
117061
  attributes: {
116934
117062
  a: ['target'],
@@ -116937,7 +117065,10 @@ const sanitizeSchema = cjs_default()(defaultSchema, {
116937
117065
  href: ['doc', 'ref', 'blog', 'changelog', 'page'],
116938
117066
  },
116939
117067
  });
116940
- const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, hardBreaks, ...opts } = {}) => {
117068
+ const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, hardBreaks, sanitize = false,
117069
+ // Pulled out of `...opts` so a caller's plugins extend the pipeline instead of
117070
+ // replacing it — otherwise the spread below would drop `rehypeStripTags`.
117071
+ remarkPlugins: userRemarkPlugins, rehypePlugins: userRehypePlugins, recmaPlugins: userRecmaPlugins, ...opts } = {}) => {
116941
117072
  // Destructure at runtime to avoid circular dependency issues
116942
117073
  const { codeTabsTransformer, ...transforms } = defaultTransforms;
116943
117074
  const remarkPlugins = [
@@ -116955,7 +117086,12 @@ const compile_compile = (text, { components = {}, missingComponents, copyButtons
116955
117086
  if (useTailwind) {
116956
117087
  remarkPlugins.push([transform_tailwind, { components }]);
116957
117088
  }
116958
- const rehypePlugins = [...ast_processor_rehypePlugins, [rehypeToc, { components }]];
117089
+ remarkPlugins.push(...(userRemarkPlugins ?? []));
117090
+ const rehypePlugins = [
117091
+ ...ast_processor_rehypePlugins,
117092
+ [rehypeToc, { components }],
117093
+ ...(userRehypePlugins ?? []),
117094
+ ];
116959
117095
  if (opts.format === 'md') {
116960
117096
  /**
116961
117097
  * When running in `md` format we need to sanitize the content for security reasons.
@@ -116973,12 +117109,23 @@ const compile_compile = (text, { components = {}, missingComponents, copyButtons
116973
117109
  ]);
116974
117110
  rehypePlugins.push([rehypeSanitize, sanitizeSchema]);
116975
117111
  }
117112
+ const recmaPlugins = [...(userRecmaPlugins ?? [])];
117113
+ // In `mdx` format a literal <script> parses as JSX rather than raw HTML, so it
117114
+ // bypasses sanitization entirely — strip it in every format. Must stay last:
117115
+ // in `md` format raw HTML isn't an element until `rehypeRaw` has run. A tag
117116
+ // inside an expression or export is code, not an element, so the recma pass
117117
+ // catches it in the compiled program instead.
117118
+ if (sanitize) {
117119
+ rehypePlugins.push(rehypeStripTags);
117120
+ recmaPlugins.push(recmaStripTags);
117121
+ }
116976
117122
  try {
116977
117123
  const vfile = compileSync(text, {
116978
117124
  outputFormat: 'function-body',
116979
117125
  providerImportSource: '#',
116980
117126
  remarkPlugins,
116981
117127
  rehypePlugins,
117128
+ recmaPlugins,
116982
117129
  ...opts,
116983
117130
  });
116984
117131
  const string = String(vfile)
@@ -123924,6 +124071,32 @@ const mdxComponentHandlers = {
123924
124071
  [NodeTypes.htmlBlock]: htmlBlockHandler,
123925
124072
  };
123926
124073
 
124074
+ ;// ./processor/plugin/safe-mode-html-blocks.ts
124075
+
124076
+
124077
+ /**
124078
+ * Whether a tag name renders through the `HTMLBlock` component. Mirrors the
124079
+ * separator-agnostic, case-insensitive lookup in `getComponentName` and the
124080
+ * rehype-react component map, so `html-block`, `HTMLBlock`, `HtmlBlock` and
124081
+ * `htmlblock` all match.
124082
+ */
124083
+ const isHtmlBlockTag = (tagName) => toPascalCase(tagName).toLowerCase() === 'htmlblock';
124084
+ /**
124085
+ * Forces `safeMode` on every element that renders through `HTMLBlock` so it is
124086
+ * shown as escaped text instead of injected.
124087
+ *
124088
+ * Runs last, so it sees every producer of the element — `[block:html]`,
124089
+ * `<HTMLBlock>` with a template body or an `html` attribute, and a literal
124090
+ * `<html-block>` — and it is unconditional so an author-supplied
124091
+ * `safeMode="false"` can't opt out.
124092
+ */
124093
+ const enforceSafeModeHtmlBlocks = () => tree => {
124094
+ visit(tree, 'element', node => {
124095
+ if (isHtmlBlockTag(node.tagName))
124096
+ node.properties.safeMode = 'true';
124097
+ });
124098
+ };
124099
+
123927
124100
  ;// ./processor/transform/mdxish/anchor-to-jsx.ts
123928
124101
 
123929
124102
 
@@ -125235,6 +125408,7 @@ const collectImportValues = (importDeclarations, registry = defaultModuleRegistr
125235
125408
 
125236
125409
 
125237
125410
 
125411
+
125238
125412
  /**
125239
125413
  * Recursively extract all identifier names introduced by a binding pattern.
125240
125414
  * Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
@@ -125279,7 +125453,7 @@ const collectExportNames = (declaration) => {
125279
125453
  * Any evaluation error is consumed and logged. We don't throw because it's
125280
125454
  * against the spirit of this engine to be less permissive than MDX needs.
125281
125455
  */
125282
- const evaluateExports = () => (tree, file) => {
125456
+ const evaluateExports = (opts) => (tree, file) => {
125283
125457
  const programBody = [];
125284
125458
  const exportNames = [];
125285
125459
  const importDeclarations = [];
@@ -125325,6 +125499,8 @@ const evaluateExports = () => (tree, file) => {
125325
125499
  // Evaluate the declarations together at once in a single sandboxed Function
125326
125500
  try {
125327
125501
  const program = { type: 'Program', sourceType: 'module', body: programBody };
125502
+ if (opts?.sanitize)
125503
+ stripJsxTags(program);
125328
125504
  buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
125329
125505
  const { value: source } = toJs(program);
125330
125506
  // Make sure import values are available in the scope
@@ -126228,7 +126404,7 @@ const parseApiHeaderTitle = (text) => {
126228
126404
  * Transform a magicBlock node into final MDAST nodes.
126229
126405
  */
126230
126406
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
126231
- const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
126407
+ const { compatibilityMode = false, hardBreaks = true } = options;
126232
126408
  // Handle empty data by returning placeholder nodes for known block types
126233
126409
  // This allows the editor to show appropriate placeholder UI instead of nothing
126234
126410
  if (Object.keys(data).length < 1) {
@@ -126446,7 +126622,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
126446
126622
  wrapPinnedBlocks({
126447
126623
  data: {
126448
126624
  hName: 'html-block',
126449
- hProperties: { html: htmlJson.html, runScripts: compatibilityMode, safeMode },
126625
+ hProperties: { html: htmlJson.html, runScripts: compatibilityMode },
126450
126626
  },
126451
126627
  type: 'html-block',
126452
126628
  }, data),
@@ -126706,6 +126882,80 @@ const mdxishHtmlBlocks = () => tree => {
126706
126882
  };
126707
126883
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
126708
126884
 
126885
+ ;// ./processor/transform/mdxish/tables/cell-width.ts
126886
+
126887
+
126888
+ // Key must follow `{` or `,` so `minWidth`/`maxWidth` don't match on their suffix
126889
+ const STYLE_OBJECT_WIDTH_REGEX = /[{,]\s*["']?width["']?\s*:\s*(?:"([^"]*)"|'([^']*)'|([^,}]+))/i;
126890
+ // First colon only, so `url(http://…)` values stay intact
126891
+ const CSS_DECLARATION_REGEX = /:(.*)/s;
126892
+ const UNITLESS_NUMBER_REGEX = /^\d+(?:\.\d+)?$/;
126893
+ // HTML reads a `width` attribute as a leading number plus optional `%`, ignoring the rest
126894
+ const HTML_DIMENSION_REGEX = /^\s*(\d+(?:\.\d+)?)\s*(%?)/;
126895
+ /** Bare numbers are pixels. A value carrying declaration separators is not a single width. */
126896
+ const normalizeWidth = (value) => {
126897
+ if (typeof value === 'number')
126898
+ return `${value}px`;
126899
+ if (typeof value !== 'string' || !value.trim())
126900
+ return null;
126901
+ const trimmed = value.trim();
126902
+ if (/[;:{}]/.test(trimmed))
126903
+ return null;
126904
+ return UNITLESS_NUMBER_REGEX.test(trimmed) ? `${trimmed}px` : trimmed;
126905
+ };
126906
+ const widthFromAttribute = (value) => {
126907
+ if (typeof value === 'number')
126908
+ return `${value}px`;
126909
+ if (typeof value !== 'string')
126910
+ return null;
126911
+ const match = HTML_DIMENSION_REGEX.exec(value);
126912
+ return match ? `${match[1]}${match[2] || 'px'}` : null;
126913
+ };
126914
+ const cssPropertyNames = (style) => style
126915
+ .split(';')
126916
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX)[0].trim().toLowerCase())
126917
+ .filter(Boolean);
126918
+ /** Handles a CSS declaration list and a style object safe mode left as a string (`{ width: "30%" }`). */
126919
+ const widthFromStyleString = (style) => {
126920
+ const trimmed = style.trim();
126921
+ if (trimmed.startsWith('{')) {
126922
+ return STYLE_OBJECT_WIDTH_REGEX.exec(trimmed)?.slice(1).find(Boolean);
126923
+ }
126924
+ return trimmed
126925
+ .split(';')
126926
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX))
126927
+ .find(([property]) => property.trim().toLowerCase() === 'width')?.[1];
126928
+ };
126929
+ /** Accepts `style={{ width }}`, `style="width: …"` and the hand-authored `width="…"`. */
126930
+ const getCellWidth = (cell) => {
126931
+ const { style, width } = getAttrs(cell);
126932
+ let styleWidth;
126933
+ if (style_object_to_css_isPlainObject(style)) {
126934
+ styleWidth = style.width;
126935
+ }
126936
+ else if (typeof style === 'string') {
126937
+ styleWidth = widthFromStyleString(style);
126938
+ }
126939
+ return normalizeWidth(styleWidth) ?? widthFromAttribute(width);
126940
+ };
126941
+ /** True when the cell's attributes state nothing but its width, which mdast can carry. */
126942
+ const hasOnlyWidthAttributes = (cell) => {
126943
+ if (cell.attributes.length === 0)
126944
+ return false;
126945
+ const { style } = getAttrs(cell);
126946
+ return cell.attributes.every(attribute => {
126947
+ if (!('name' in attribute))
126948
+ return false;
126949
+ if (attribute.name === 'width')
126950
+ return true;
126951
+ if (attribute.name !== 'style')
126952
+ return false;
126953
+ if (style_object_to_css_isPlainObject(style))
126954
+ return Object.keys(style).every(key => key === 'width');
126955
+ return typeof style === 'string' && cssPropertyNames(style).every(property => property === 'width');
126956
+ });
126957
+ };
126958
+
126709
126959
  ;// ./processor/transform/mdxish/mdxish-jsx-to-mdast.ts
126710
126960
 
126711
126961
 
@@ -126713,6 +126963,7 @@ const mdxishHtmlBlocks = () => tree => {
126713
126963
 
126714
126964
 
126715
126965
 
126966
+
126716
126967
  function toImageAlign(value) {
126717
126968
  if (value === 'left' || value === 'center' || value === 'right') {
126718
126969
  return value;
@@ -127154,10 +127405,40 @@ const wrapBareCellsInRow = (node) => {
127154
127405
  });
127155
127406
  };
127156
127407
  /**
127157
- * Converts a JSX <Table> element to an MDAST table node with alignment.
127158
- * Returns null for header-less tables since MDAST always promotes the first row to <thead>.
127408
+ * A lowercase <table> reaches here only because `mdxishTables` kept it as JSX for its
127409
+ * attributes. Widths on first-row cells are the one attribute mdast can carry; anything
127410
+ * else stays JSX so it still renders.
127411
+ */
127412
+ const lowercaseTableIsConvertible = (jsx) => {
127413
+ if (jsx.attributes.length > 0)
127414
+ return false;
127415
+ const headerCells = new Set();
127416
+ let headerRowSeen = false;
127417
+ let convertible = true;
127418
+ visit(jsx, isMDXElement, (child) => {
127419
+ if (child.name === 'tr' && !headerRowSeen) {
127420
+ headerRowSeen = true;
127421
+ visit(child, mdxish_jsx_to_mdast_isTableCell, cell => {
127422
+ headerCells.add(cell);
127423
+ });
127424
+ }
127425
+ if (child.name === null || !tableTags.has(child.name) || child.attributes.length === 0)
127426
+ return;
127427
+ if (!headerCells.has(child) || !hasOnlyWidthAttributes(child) || getCellWidth(child) === null) {
127428
+ convertible = false;
127429
+ }
127430
+ });
127431
+ return convertible;
127432
+ };
127433
+ /**
127434
+ * Converts a JSX <Table>, or a lowercase <table> carrying only widths, to an MDAST table
127435
+ * node with alignment and widths. Returns null for header-less tables since MDAST always
127436
+ * promotes the first row to <thead>.
127159
127437
  */
127160
127438
  const transformTable = (jsx) => {
127439
+ const isLowercase = jsx.name === 'table';
127440
+ if (isLowercase && !lowercaseTableIsConvertible(jsx))
127441
+ return null;
127161
127442
  wrapBareCellsInRow(jsx);
127162
127443
  let hasThead = false;
127163
127444
  visit(jsx, isMDXElement, (child) => {
@@ -127169,6 +127450,7 @@ const transformTable = (jsx) => {
127169
127450
  const { align: alignAttr } = getAttrs(jsx);
127170
127451
  const align = Array.isArray(alignAttr) ? alignAttr : null;
127171
127452
  const rows = [];
127453
+ const widths = [];
127172
127454
  visit(jsx, isMDXElement, (child) => {
127173
127455
  if (child.name !== 'thead' && child.name !== 'tbody')
127174
127456
  return;
@@ -127176,6 +127458,7 @@ const transformTable = (jsx) => {
127176
127458
  if (row.name !== 'tr')
127177
127459
  return;
127178
127460
  const cells = [];
127461
+ const isHeaderRow = rows.length === 0;
127179
127462
  visit(row, mdxish_jsx_to_mdast_isTableCell, (cell) => {
127180
127463
  const parsedChildren = unwrapSoleParagraph(cell.children);
127181
127464
  cells.push({
@@ -127183,6 +127466,8 @@ const transformTable = (jsx) => {
127183
127466
  children: parsedChildren,
127184
127467
  position: cell.position,
127185
127468
  });
127469
+ if (isHeaderRow)
127470
+ widths.push(getCellWidth(cell));
127186
127471
  });
127187
127472
  rows.push({
127188
127473
  type: 'tableRow',
@@ -127195,11 +127480,16 @@ const transformTable = (jsx) => {
127195
127480
  const alignArray = align && columnCount > 0
127196
127481
  ? align.slice(0, columnCount).concat(Array.from({ length: Math.max(0, columnCount - align.length) }, () => null))
127197
127482
  : Array.from({ length: columnCount }, () => null);
127483
+ const data = {
127484
+ ...(isLowercase && { lowercaseTable: true }),
127485
+ ...(widths.some(Boolean) && { widths }),
127486
+ };
127198
127487
  return {
127199
127488
  type: 'table',
127200
127489
  align: alignArray,
127201
127490
  position: jsx.position,
127202
127491
  children: rows,
127492
+ ...(Object.keys(data).length > 0 && { data }),
127203
127493
  };
127204
127494
  };
127205
127495
  /**
@@ -127229,6 +127519,7 @@ const COMPONENT_MAP = {
127229
127519
  figure: transformFigure,
127230
127520
  Recipe: transformRecipe,
127231
127521
  Table: transformTable,
127522
+ table: transformTable,
127232
127523
  };
127233
127524
  /**
127234
127525
  * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
@@ -127704,6 +127995,28 @@ const restoreBooleanProperties = () => tree => {
127704
127995
  };
127705
127996
 
127706
127997
 
127998
+ ;// ./processor/transform/mdxish/tables/cell-style.ts
127999
+ /** `left` is the browser default, so it's omitted. Lowercase tables get the HTML string form. */
128000
+ const cellStyle = (align, width = null, { html = false } = {}) => {
128001
+ if (html) {
128002
+ if (!width)
128003
+ return null;
128004
+ return { type: 'mdxJsxAttribute', name: 'style', value: `width: ${width}` };
128005
+ }
128006
+ const declarations = [];
128007
+ if (align && align !== 'left')
128008
+ declarations.push(`textAlign: ${JSON.stringify(align)}`);
128009
+ if (width)
128010
+ declarations.push(`width: ${JSON.stringify(width)}`);
128011
+ if (declarations.length === 0)
128012
+ return null;
128013
+ return {
128014
+ type: 'mdxJsxAttribute',
128015
+ name: 'style',
128016
+ value: { type: 'mdxJsxAttributeValueExpression', value: `{ ${declarations.join(', ')} }` },
128017
+ };
128018
+ };
128019
+
127707
128020
  ;// ./processor/transform/mdxish/tables/gfm-cell-normalization.ts
127708
128021
  /** `<br />` is the only line break a GFM pipe cell can carry, since cells are single-line. */
127709
128022
  const createLineBreak = () => ({
@@ -127742,19 +128055,8 @@ const normalizeCellChildrenForGfm = (cell) => normalizeNodes(cell.children);
127742
128055
 
127743
128056
 
127744
128057
 
128058
+
127745
128059
  const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
127746
- const mdxish_tables_to_jsx_alignToStyle = (align) => {
127747
- if (!align || align === 'left')
127748
- return null;
127749
- return {
127750
- type: 'mdxJsxAttribute',
127751
- name: 'style',
127752
- value: {
127753
- type: 'mdxJsxAttributeValueExpression',
127754
- value: `{ textAlign: "${align}" }`,
127755
- },
127756
- };
127757
- };
127758
128060
  const mdxish_tables_to_jsx_isTableCell = (node) => ['tableHead', 'tableCell'].includes(node.type);
127759
128061
  const mdxish_tables_to_jsx_isLiteral = (node) => 'value' in node;
127760
128062
  /**
@@ -127810,12 +128112,17 @@ const mdxishTablesToJsx = () => tree => {
127810
128112
  gfmCells.push([cell, normalized]);
127811
128113
  return undefined;
127812
128114
  });
127813
- const stayLowercase = table.data?.lowercaseTable === true;
128115
+ const widths = table.data?.widths ?? [];
128116
+ const hasWidths = widths.some(Boolean);
128117
+ // Lowercase cells can carry a width but not an alignment, so an aligned table becomes <Table>
128118
+ const hasAlignment = table.align.some(align => align && align !== 'left');
128119
+ const stayLowercase = table.data?.lowercaseTable === true && !hasAlignment;
127814
128120
  // We transform to GFM tables if:
127815
128121
  // 1. If it doesn't contain complex elements that the syntax can't represent
127816
- // 2. The original table is not lowercase HTML <table>, because we want to
128122
+ // 2. The original table is not lowercase HTML <table>, because we want to
127817
128123
  // preserve original tables as much as possible
127818
- if (!requiresJsxTable && !stayLowercase) {
128124
+ // 3. No column has a width, which GFM can't express
128125
+ if (!requiresJsxTable && !stayLowercase && !hasWidths) {
127819
128126
  gfmCells.forEach(([cell, children]) => {
127820
128127
  cell.children = children;
127821
128128
  });
@@ -127827,7 +128134,8 @@ const mdxishTablesToJsx = () => tree => {
127827
128134
  if (!headerRow)
127828
128135
  return;
127829
128136
  visit(table, mdxish_tables_to_jsx_isTableCell, flattenBreaksToNewlines);
127830
- const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
128137
+ const headerStyles = table.align.map((align, i) => cellStyle(align, widths[i] ?? null, { html: stayLowercase }));
128138
+ const bodyStyles = table.align.map(align => cellStyle(align, null, { html: stayLowercase }));
127831
128139
  const head = {
127832
128140
  attributes: [],
127833
128141
  type: 'mdxJsxFlowElement',
@@ -127843,7 +128151,7 @@ const mdxishTablesToJsx = () => tree => {
127843
128151
  type: 'mdxJsxFlowElement',
127844
128152
  name: 'th',
127845
128153
  children: cell.children,
127846
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
128154
+ ...(headerStyles[cellIndex] && { attributes: [headerStyles[cellIndex]] }),
127847
128155
  };
127848
128156
  }),
127849
128157
  },
@@ -127863,7 +128171,7 @@ const mdxishTablesToJsx = () => tree => {
127863
128171
  type: 'mdxJsxFlowElement',
127864
128172
  name: 'td',
127865
128173
  children: cell.children,
127866
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
128174
+ ...(bodyStyles[cellIndex] && { attributes: [bodyStyles[cellIndex]] }),
127867
128175
  };
127868
128176
  }),
127869
128177
  };
@@ -128147,6 +128455,8 @@ function loadComponents() {
128147
128455
 
128148
128456
 
128149
128457
 
128458
+
128459
+
128150
128460
 
128151
128461
 
128152
128462
 
@@ -128274,7 +128584,7 @@ function mdxishMdastToMd(mdast) {
128274
128584
  * @see .claude/context/MDXish/Processor Overview.md
128275
128585
  */
128276
128586
  function mdxish(mdContent, opts = {}) {
128277
- const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
128587
+ const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, sanitize = false, variables, } = opts;
128278
128588
  const components = {
128279
128589
  ...loadComponents(),
128280
128590
  ...userComponents,
@@ -128285,7 +128595,7 @@ function mdxish(mdContent, opts = {}) {
128285
128595
  const contentWithoutComments = restoreCodeBlocks(withoutComments, protectedCode);
128286
128596
  const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
128287
128597
  processor
128288
- .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
128598
+ .use(safeMode ? undefined : evaluate_exports, { sanitize }) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
128289
128599
  .use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
128290
128600
  .use(safeMode ? undefined : evaluate_expressions, { components, variables }) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
128291
128601
  .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
@@ -128296,13 +128606,15 @@ function mdxish(mdContent, opts = {}) {
128296
128606
  .use(restoreBooleanProperties)
128297
128607
  .use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
128298
128608
  .use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
128609
+ .use(sanitize ? rehypeStripTags : undefined) // Strip STRIPPED_TAG_NAMES elements; this pipeline has no sanitization step
128299
128610
  .use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
128300
128611
  .use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
128301
128612
  .use(heading_slugs)
128302
128613
  .use(rehypeMdxishComponents, {
128303
128614
  components,
128304
128615
  processMarkdown: (markdown) => mdxish(markdown, opts),
128305
- });
128616
+ })
128617
+ .use(safeMode ? enforceSafeModeHtmlBlocks : undefined); // Force safeMode on every HTMLBlock; runs last so every producer is covered
128306
128618
  const vfile = new VFile({ value: parserReadyContent });
128307
128619
  const mdast = processor.parse(parserReadyContent);
128308
128620
  const hast = processor.runSync(mdast, vfile);
@@ -129333,7 +129645,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
129333
129645
  /******/ // startup
129334
129646
  /******/ // Load entry module and return exports
129335
129647
  /******/ // This entry module used 'module' so it can't be inlined
129336
- /******/ let __webpack_exports__ = __webpack_require__(6817);
129648
+ /******/ let __webpack_exports__ = __webpack_require__(5789);
129337
129649
  /******/ module.exports = __webpack_exports__;
129338
129650
  /******/
129339
129651
  /******/ })()