@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/components/Callout/style.scss +11 -2
- package/components/HTMLBlock/index.tsx +2 -2
- package/dist/lib/compile.d.ts +8 -1
- package/dist/lib/mdxish.d.ts +7 -0
- package/dist/main.css +1 -1
- package/dist/main.css.map +1 -1
- package/dist/main.js +344 -32
- package/dist/main.node.js +344 -32
- package/dist/main.node.js.map +1 -1
- package/dist/processor/plugin/safe-mode-html-blocks.d.ts +12 -0
- package/dist/processor/plugin/strip-tags.d.ts +31 -0
- package/dist/processor/transform/mdxish/evaluate-exports.d.ts +5 -1
- package/dist/processor/transform/mdxish/magic-blocks/types.d.ts +0 -1
- package/dist/processor/transform/mdxish/tables/cell-style.d.ts +7 -0
- package/dist/processor/transform/mdxish/tables/cell-width.d.ts +9 -0
- package/dist/render-fixture.node.js +323 -32
- package/dist/render-fixture.node.js.map +1 -1
- package/package.json +2 -2
- package/types.d.ts +2 -0
|
@@ -19045,7 +19045,7 @@ module.exports = function () {
|
|
|
19045
19045
|
|
|
19046
19046
|
/***/ },
|
|
19047
19047
|
|
|
19048
|
-
/***/
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
126927
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
...(
|
|
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
|
-
...(
|
|
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__(
|
|
129408
|
+
/******/ let __webpack_exports__ = __webpack_require__(8900);
|
|
129118
129409
|
/******/ module.exports = __webpack_exports__;
|
|
129119
129410
|
/******/
|
|
129120
129411
|
/******/ })()
|