@readme/markdown 15.7.3 → 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/dist/main.js CHANGED
@@ -11423,7 +11423,7 @@ module.exports = function () {
11423
11423
 
11424
11424
  /***/ },
11425
11425
 
11426
- /***/ 7070
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, ...opts } = {}) => {
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
- const rehypePlugins = [...ast_processor_rehypePlugins, [rehypeToc, { components }]];
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__(7070);
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
- /***/ 6817
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, ...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)
@@ -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__(6817);
129488
+ /******/ let __webpack_exports__ = __webpack_require__(4246);
129337
129489
  /******/ module.exports = __webpack_exports__;
129338
129490
  /******/
129339
129491
  /******/ })()