@readme/markdown 15.7.2 → 15.8.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/README.md +2 -2
- package/components/Callout/style.scss +15 -0
- 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 +159 -7
- package/dist/main.node.js +159 -7
- package/dist/main.node.js.map +1 -1
- package/dist/processor/plugin/strip-tags.d.ts +31 -0
- package/dist/processor/transform/mdxish/evaluate-exports.d.ts +5 -1
- package/dist/render-fixture.node.js +159 -7
- package/dist/render-fixture.node.js.map +1 -1
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -11423,7 +11423,7 @@ module.exports = function () {
|
|
|
11423
11423
|
|
|
11424
11424
|
/***/ },
|
|
11425
11425
|
|
|
11426
|
-
/***/
|
|
11426
|
+
/***/ 9607
|
|
11427
11427
|
(module, __webpack_exports__, __webpack_require__) {
|
|
11428
11428
|
|
|
11429
11429
|
"use strict";
|
|
@@ -94009,6 +94009,133 @@ const hardBreaks = () => tree => {
|
|
|
94009
94009
|
};
|
|
94010
94010
|
/* harmony default export */ const hard_breaks = (hardBreaks);
|
|
94011
94011
|
|
|
94012
|
+
;// ./processor/plugin/strip-tags.ts
|
|
94013
|
+
|
|
94014
|
+
/**
|
|
94015
|
+
* Tags removed from user-provided content because rendering them executes in the
|
|
94016
|
+
* page. Add an entry to cover another vector; nothing else needs to change.
|
|
94017
|
+
*
|
|
94018
|
+
* Deliberately narrow for now — `<script>` is the only vector this plugin claims
|
|
94019
|
+
* to close. Broader parity with the `md` sanitization schema (`javascript:` URLs,
|
|
94020
|
+
* `on*` handlers, `<iframe>`, `<object>`, …) is tracked in readmeio/markdown#1526.
|
|
94021
|
+
*/
|
|
94022
|
+
const STRIPPED_TAG_NAMES = new Set(['script']);
|
|
94023
|
+
/** JSX names starting with a capital are component references, not literal tags. */
|
|
94024
|
+
const LITERAL_TAG_NAME = /^[a-z]/;
|
|
94025
|
+
/**
|
|
94026
|
+
* Whether a node would render as one of the stripped literal DOM elements.
|
|
94027
|
+
* Browsers match tag names case-insensitively, so `<sCrIpT>` executes too.
|
|
94028
|
+
*
|
|
94029
|
+
* `<Script />` and friends are component references and are left alone.
|
|
94030
|
+
*/
|
|
94031
|
+
const isStrippedTag = (node) => {
|
|
94032
|
+
if (node.type === 'element')
|
|
94033
|
+
return STRIPPED_TAG_NAMES.has(node.tagName.toLowerCase());
|
|
94034
|
+
if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
|
|
94035
|
+
const name = node.name ?? '';
|
|
94036
|
+
return LITERAL_TAG_NAME.test(name) && STRIPPED_TAG_NAMES.has(name.toLowerCase());
|
|
94037
|
+
}
|
|
94038
|
+
return false;
|
|
94039
|
+
};
|
|
94040
|
+
/**
|
|
94041
|
+
* Removes matching elements and their subtrees when `sanitize` is enabled.
|
|
94042
|
+
*
|
|
94043
|
+
* Explicit `HTMLBlock`s are an intentional exception, matching legacy: their
|
|
94044
|
+
* scripts live in a string prop rather than as elements, so they never appear
|
|
94045
|
+
* in SSR HTML, and they only execute client-side when the author opts in via
|
|
94046
|
+
* `runScripts`.
|
|
94047
|
+
*/
|
|
94048
|
+
const rehypeStripTags = () => {
|
|
94049
|
+
return (tree) => {
|
|
94050
|
+
visit(tree, isStrippedTag, (_node, index, parent) => {
|
|
94051
|
+
parent.children.splice(index, 1);
|
|
94052
|
+
return [(/* inlined export .SKIP */"skip"), index];
|
|
94053
|
+
});
|
|
94054
|
+
};
|
|
94055
|
+
};
|
|
94056
|
+
/** The automatic-runtime factories MDX compiles JSX into. */
|
|
94057
|
+
const JSX_FACTORIES = new Set(['_jsx', '_jsxs', '_jsxDEV']);
|
|
94058
|
+
/**
|
|
94059
|
+
* Matches raw JSX and compiled `_jsx('tag', …)` calls. MDX may rewrite literal
|
|
94060
|
+
* tags as `_components.<tag>` so a `components` prop can override them.
|
|
94061
|
+
*/
|
|
94062
|
+
const isStrippedJsxElement = (node) => {
|
|
94063
|
+
if (node.type === 'JSXElement') {
|
|
94064
|
+
const { name } = node.openingElement;
|
|
94065
|
+
if (name.type === 'JSXIdentifier') {
|
|
94066
|
+
return LITERAL_TAG_NAME.test(name.name) && STRIPPED_TAG_NAMES.has(name.name.toLowerCase());
|
|
94067
|
+
}
|
|
94068
|
+
return (name.type === 'JSXMemberExpression' &&
|
|
94069
|
+
name.object.type === 'JSXIdentifier' &&
|
|
94070
|
+
name.object.name === '_components' &&
|
|
94071
|
+
STRIPPED_TAG_NAMES.has(name.property.name.toLowerCase()));
|
|
94072
|
+
}
|
|
94073
|
+
if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && JSX_FACTORIES.has(node.callee.name)) {
|
|
94074
|
+
const [tag] = node.arguments;
|
|
94075
|
+
if (!tag)
|
|
94076
|
+
return false;
|
|
94077
|
+
if (tag.type === 'Literal')
|
|
94078
|
+
return typeof tag.value === 'string' && STRIPPED_TAG_NAMES.has(tag.value.toLowerCase());
|
|
94079
|
+
return (tag.type === 'MemberExpression' &&
|
|
94080
|
+
tag.object.type === 'Identifier' &&
|
|
94081
|
+
tag.object.name === '_components' &&
|
|
94082
|
+
tag.property.type === 'Identifier' &&
|
|
94083
|
+
STRIPPED_TAG_NAMES.has(tag.property.name.toLowerCase()));
|
|
94084
|
+
}
|
|
94085
|
+
return false;
|
|
94086
|
+
};
|
|
94087
|
+
const isEstreeNode = (value) => typeof value === 'object' && value !== null && typeof value.type === 'string';
|
|
94088
|
+
const nullLiteral = () => ({ type: 'Literal', value: null });
|
|
94089
|
+
/**
|
|
94090
|
+
* JSX inside expressions and exports stays in ESTree, outside the HAST pass.
|
|
94091
|
+
* Strip it before evaluation in mdxish or after JSX compilation in MDX.
|
|
94092
|
+
*
|
|
94093
|
+
* Elements are spliced out of JSX children and replaced with `null` anywhere
|
|
94094
|
+
* else, which React renders as nothing.
|
|
94095
|
+
*/
|
|
94096
|
+
const stripJsxTags = (program) => {
|
|
94097
|
+
const walk = (node) => {
|
|
94098
|
+
const record = node;
|
|
94099
|
+
Object.keys(record).forEach(key => {
|
|
94100
|
+
if (key === 'loc' || key === 'range' || key === 'position')
|
|
94101
|
+
return;
|
|
94102
|
+
const value = record[key];
|
|
94103
|
+
if (Array.isArray(value)) {
|
|
94104
|
+
for (let i = value.length - 1; i >= 0; i -= 1) {
|
|
94105
|
+
const child = value[i];
|
|
94106
|
+
if (isEstreeNode(child)) {
|
|
94107
|
+
if (isStrippedJsxElement(child)) {
|
|
94108
|
+
if (key === 'children')
|
|
94109
|
+
value.splice(i, 1);
|
|
94110
|
+
else
|
|
94111
|
+
value[i] = nullLiteral();
|
|
94112
|
+
}
|
|
94113
|
+
else {
|
|
94114
|
+
walk(child);
|
|
94115
|
+
}
|
|
94116
|
+
}
|
|
94117
|
+
}
|
|
94118
|
+
return;
|
|
94119
|
+
}
|
|
94120
|
+
if (!isEstreeNode(value))
|
|
94121
|
+
return;
|
|
94122
|
+
if (isStrippedJsxElement(value)) {
|
|
94123
|
+
record[key] =
|
|
94124
|
+
node.type === 'JSXAttribute' ? { type: 'JSXExpressionContainer', expression: nullLiteral() } : nullLiteral();
|
|
94125
|
+
}
|
|
94126
|
+
else {
|
|
94127
|
+
walk(value);
|
|
94128
|
+
}
|
|
94129
|
+
});
|
|
94130
|
+
};
|
|
94131
|
+
walk(program);
|
|
94132
|
+
return program;
|
|
94133
|
+
};
|
|
94134
|
+
/** `stripJsxTags` as a recma plugin, for the `mdx` compile pipeline. */
|
|
94135
|
+
const recmaStripTags = () => tree => {
|
|
94136
|
+
stripJsxTags(tree);
|
|
94137
|
+
};
|
|
94138
|
+
|
|
94012
94139
|
;// ./node_modules/estree-util-value-to-estree/dist/estree-util-value-to-estree.js
|
|
94013
94140
|
/**
|
|
94014
94141
|
* Create an ESTree identifier node for a given name.
|
|
@@ -96746,6 +96873,7 @@ const tocHastToMdx = (toc, components, variables) => {
|
|
|
96746
96873
|
|
|
96747
96874
|
|
|
96748
96875
|
|
|
96876
|
+
|
|
96749
96877
|
const sanitizeSchema = cjs_default()(defaultSchema, {
|
|
96750
96878
|
attributes: {
|
|
96751
96879
|
a: ['target'],
|
|
@@ -96754,7 +96882,10 @@ const sanitizeSchema = cjs_default()(defaultSchema, {
|
|
|
96754
96882
|
href: ['doc', 'ref', 'blog', 'changelog', 'page'],
|
|
96755
96883
|
},
|
|
96756
96884
|
});
|
|
96757
|
-
const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, hardBreaks,
|
|
96885
|
+
const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, hardBreaks, sanitize = false,
|
|
96886
|
+
// Pulled out of `...opts` so a caller's plugins extend the pipeline instead of
|
|
96887
|
+
// replacing it — otherwise the spread below would drop `rehypeStripTags`.
|
|
96888
|
+
remarkPlugins: userRemarkPlugins, rehypePlugins: userRehypePlugins, recmaPlugins: userRecmaPlugins, ...opts } = {}) => {
|
|
96758
96889
|
// Destructure at runtime to avoid circular dependency issues
|
|
96759
96890
|
const { codeTabsTransformer, ...transforms } = defaultTransforms;
|
|
96760
96891
|
const remarkPlugins = [
|
|
@@ -96772,7 +96903,12 @@ const compile_compile = (text, { components = {}, missingComponents, copyButtons
|
|
|
96772
96903
|
if (useTailwind) {
|
|
96773
96904
|
remarkPlugins.push([transform_tailwind, { components }]);
|
|
96774
96905
|
}
|
|
96775
|
-
|
|
96906
|
+
remarkPlugins.push(...(userRemarkPlugins ?? []));
|
|
96907
|
+
const rehypePlugins = [
|
|
96908
|
+
...ast_processor_rehypePlugins,
|
|
96909
|
+
[rehypeToc, { components }],
|
|
96910
|
+
...(userRehypePlugins ?? []),
|
|
96911
|
+
];
|
|
96776
96912
|
if (opts.format === 'md') {
|
|
96777
96913
|
/**
|
|
96778
96914
|
* When running in `md` format we need to sanitize the content for security reasons.
|
|
@@ -96790,12 +96926,23 @@ const compile_compile = (text, { components = {}, missingComponents, copyButtons
|
|
|
96790
96926
|
]);
|
|
96791
96927
|
rehypePlugins.push([rehypeSanitize, sanitizeSchema]);
|
|
96792
96928
|
}
|
|
96929
|
+
const recmaPlugins = [...(userRecmaPlugins ?? [])];
|
|
96930
|
+
// In `mdx` format a literal <script> parses as JSX rather than raw HTML, so it
|
|
96931
|
+
// bypasses sanitization entirely — strip it in every format. Must stay last:
|
|
96932
|
+
// in `md` format raw HTML isn't an element until `rehypeRaw` has run. A tag
|
|
96933
|
+
// inside an expression or export is code, not an element, so the recma pass
|
|
96934
|
+
// catches it in the compiled program instead.
|
|
96935
|
+
if (sanitize) {
|
|
96936
|
+
rehypePlugins.push(rehypeStripTags);
|
|
96937
|
+
recmaPlugins.push(recmaStripTags);
|
|
96938
|
+
}
|
|
96793
96939
|
try {
|
|
96794
96940
|
const vfile = compileSync(text, {
|
|
96795
96941
|
outputFormat: 'function-body',
|
|
96796
96942
|
providerImportSource: '#',
|
|
96797
96943
|
remarkPlugins,
|
|
96798
96944
|
rehypePlugins,
|
|
96945
|
+
recmaPlugins,
|
|
96799
96946
|
...opts,
|
|
96800
96947
|
});
|
|
96801
96948
|
const string = String(vfile)
|
|
@@ -105052,6 +105199,7 @@ const collectImportValues = (importDeclarations, registry = defaultModuleRegistr
|
|
|
105052
105199
|
|
|
105053
105200
|
|
|
105054
105201
|
|
|
105202
|
+
|
|
105055
105203
|
/**
|
|
105056
105204
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
105057
105205
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -105096,7 +105244,7 @@ const collectExportNames = (declaration) => {
|
|
|
105096
105244
|
* Any evaluation error is consumed and logged. We don't throw because it's
|
|
105097
105245
|
* against the spirit of this engine to be less permissive than MDX needs.
|
|
105098
105246
|
*/
|
|
105099
|
-
const evaluateExports = () => (tree, file) => {
|
|
105247
|
+
const evaluateExports = (opts) => (tree, file) => {
|
|
105100
105248
|
const programBody = [];
|
|
105101
105249
|
const exportNames = [];
|
|
105102
105250
|
const importDeclarations = [];
|
|
@@ -105142,6 +105290,8 @@ const evaluateExports = () => (tree, file) => {
|
|
|
105142
105290
|
// Evaluate the declarations together at once in a single sandboxed Function
|
|
105143
105291
|
try {
|
|
105144
105292
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
105293
|
+
if (opts?.sanitize)
|
|
105294
|
+
stripJsxTags(program);
|
|
105145
105295
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
105146
105296
|
const { value: source } = toJs(program);
|
|
105147
105297
|
// Make sure import values are available in the scope
|
|
@@ -107965,6 +108115,7 @@ function loadComponents() {
|
|
|
107965
108115
|
|
|
107966
108116
|
|
|
107967
108117
|
|
|
108118
|
+
|
|
107968
108119
|
|
|
107969
108120
|
|
|
107970
108121
|
const defaultTransformers = [
|
|
@@ -108091,7 +108242,7 @@ function mdxishMdastToMd(mdast) {
|
|
|
108091
108242
|
* @see .claude/context/MDXish/Processor Overview.md
|
|
108092
108243
|
*/
|
|
108093
108244
|
function mdxish(mdContent, opts = {}) {
|
|
108094
|
-
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
|
|
108245
|
+
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, sanitize = false, variables, } = opts;
|
|
108095
108246
|
const components = {
|
|
108096
108247
|
...loadComponents(),
|
|
108097
108248
|
...userComponents,
|
|
@@ -108102,7 +108253,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
108102
108253
|
const contentWithoutComments = restoreCodeBlocks(withoutComments, protectedCode);
|
|
108103
108254
|
const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
|
|
108104
108255
|
processor
|
|
108105
|
-
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
108256
|
+
.use(safeMode ? undefined : evaluate_exports, { sanitize }) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
108106
108257
|
.use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
108107
108258
|
.use(safeMode ? undefined : evaluate_expressions, { components, variables }) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
108108
108259
|
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
@@ -108113,6 +108264,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
108113
108264
|
.use(restoreBooleanProperties)
|
|
108114
108265
|
.use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
|
|
108115
108266
|
.use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
|
|
108267
|
+
.use(sanitize ? rehypeStripTags : undefined) // Strip STRIPPED_TAG_NAMES elements; this pipeline has no sanitization step
|
|
108116
108268
|
.use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
|
|
108117
108269
|
.use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
|
|
108118
108270
|
.use(heading_slugs)
|
|
@@ -109091,7 +109243,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
|
|
|
109091
109243
|
/******/ // startup
|
|
109092
109244
|
/******/ // Load entry module and return exports
|
|
109093
109245
|
/******/ // This entry module used 'module' so it can't be inlined
|
|
109094
|
-
/******/ let __webpack_exports__ = __webpack_require__(
|
|
109246
|
+
/******/ let __webpack_exports__ = __webpack_require__(9607);
|
|
109095
109247
|
/******/
|
|
109096
109248
|
/******/ return __webpack_exports__;
|
|
109097
109249
|
/******/ })()
|
package/dist/main.node.js
CHANGED
|
@@ -19045,7 +19045,7 @@ module.exports = function () {
|
|
|
19045
19045
|
|
|
19046
19046
|
/***/ },
|
|
19047
19047
|
|
|
19048
|
-
/***/
|
|
19048
|
+
/***/ 4246
|
|
19049
19049
|
(module, __webpack_exports__, __webpack_require__) {
|
|
19050
19050
|
|
|
19051
19051
|
"use strict";
|
|
@@ -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,
|
|
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
|
-
|
|
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)
|
|
@@ -125235,6 +125382,7 @@ const collectImportValues = (importDeclarations, registry = defaultModuleRegistr
|
|
|
125235
125382
|
|
|
125236
125383
|
|
|
125237
125384
|
|
|
125385
|
+
|
|
125238
125386
|
/**
|
|
125239
125387
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
125240
125388
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -125279,7 +125427,7 @@ const collectExportNames = (declaration) => {
|
|
|
125279
125427
|
* Any evaluation error is consumed and logged. We don't throw because it's
|
|
125280
125428
|
* against the spirit of this engine to be less permissive than MDX needs.
|
|
125281
125429
|
*/
|
|
125282
|
-
const evaluateExports = () => (tree, file) => {
|
|
125430
|
+
const evaluateExports = (opts) => (tree, file) => {
|
|
125283
125431
|
const programBody = [];
|
|
125284
125432
|
const exportNames = [];
|
|
125285
125433
|
const importDeclarations = [];
|
|
@@ -125325,6 +125473,8 @@ const evaluateExports = () => (tree, file) => {
|
|
|
125325
125473
|
// Evaluate the declarations together at once in a single sandboxed Function
|
|
125326
125474
|
try {
|
|
125327
125475
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
125476
|
+
if (opts?.sanitize)
|
|
125477
|
+
stripJsxTags(program);
|
|
125328
125478
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
125329
125479
|
const { value: source } = toJs(program);
|
|
125330
125480
|
// Make sure import values are available in the scope
|
|
@@ -128148,6 +128298,7 @@ function loadComponents() {
|
|
|
128148
128298
|
|
|
128149
128299
|
|
|
128150
128300
|
|
|
128301
|
+
|
|
128151
128302
|
|
|
128152
128303
|
|
|
128153
128304
|
const defaultTransformers = [
|
|
@@ -128274,7 +128425,7 @@ function mdxishMdastToMd(mdast) {
|
|
|
128274
128425
|
* @see .claude/context/MDXish/Processor Overview.md
|
|
128275
128426
|
*/
|
|
128276
128427
|
function mdxish(mdContent, opts = {}) {
|
|
128277
|
-
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
|
|
128428
|
+
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, sanitize = false, variables, } = opts;
|
|
128278
128429
|
const components = {
|
|
128279
128430
|
...loadComponents(),
|
|
128280
128431
|
...userComponents,
|
|
@@ -128285,7 +128436,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
128285
128436
|
const contentWithoutComments = restoreCodeBlocks(withoutComments, protectedCode);
|
|
128286
128437
|
const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
|
|
128287
128438
|
processor
|
|
128288
|
-
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
128439
|
+
.use(safeMode ? undefined : evaluate_exports, { sanitize }) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
128289
128440
|
.use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
128290
128441
|
.use(safeMode ? undefined : evaluate_expressions, { components, variables }) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
128291
128442
|
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
@@ -128296,6 +128447,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
128296
128447
|
.use(restoreBooleanProperties)
|
|
128297
128448
|
.use(safeMode ? undefined : resolve_deferred_attribute_expression_props) // Evaluate deferred attribute expressions on mdx-jsx nodes (now past rehypeRaw's clone)
|
|
128298
128449
|
.use(normalize_mdx_jsx_nodes) // Rewrite `mdx-jsx` back to standard `element` nodes for downstream plugins
|
|
128450
|
+
.use(sanitize ? rehypeStripTags : undefined) // Strip STRIPPED_TAG_NAMES elements; this pipeline has no sanitization step
|
|
128299
128451
|
.use(rehypeFlattenTableCellParagraphs) // Remove <p> wrappers inside table cells to prevent margin issues
|
|
128300
128452
|
.use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
|
|
128301
128453
|
.use(heading_slugs)
|
|
@@ -129333,7 +129485,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
|
|
|
129333
129485
|
/******/ // startup
|
|
129334
129486
|
/******/ // Load entry module and return exports
|
|
129335
129487
|
/******/ // This entry module used 'module' so it can't be inlined
|
|
129336
|
-
/******/ let __webpack_exports__ = __webpack_require__(
|
|
129488
|
+
/******/ let __webpack_exports__ = __webpack_require__(4246);
|
|
129337
129489
|
/******/ module.exports = __webpack_exports__;
|
|
129338
129490
|
/******/
|
|
129339
129491
|
/******/ })()
|