next-mdx-remote
Version:
utilities for loading mdx from any remote source as data, rather than as a local import
51 lines (50 loc) • 2.12 kB
JavaScript
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { visit, SKIP } from 'unist-util-visit';
/**
* Remark plugin that removes JavaScript expressions from MDX.
* This blocks patterns like {variable} or {func()} that enable code execution.
*
* Safe patterns (preserved):
* - JSX: <Component />
* - Markdown: # Heading, **bold**, etc.
*
* Blocked patterns:
* - JS expressions: {variable}, {func()}, {obj.prop}
* - JSX attribute expressions: <Component prop={value} />
*/
export const removeJavaScriptExpressions = () => {
return (tree) => {
visit(tree, (node, index, parent) => {
// Remove mdxFlowExpression and mdxTextExpression nodes (JS expressions in MDX)
if (node.type === 'mdxFlowExpression' ||
node.type === 'mdxTextExpression') {
// Remove this node from parent
if (parent && typeof index === 'number') {
parent.children.splice(index, 1);
return [SKIP, index];
}
}
// Remove JavaScript expressions from JSX attribute values
if (node.type === 'mdxJsxFlowElement' ||
node.type === 'mdxJsxTextElement') {
if (node.attributes) {
node.attributes = node.attributes.filter((attr) => {
// Keep literal values, remove expression values
if (attr.type === 'mdxJsxAttribute') {
// If the value is null (boolean attribute) or a literal string, keep it
return (attr.value === null ||
typeof attr.value === 'string' ||
(attr.value &&
attr.value.type !== 'mdxJsxAttributeValueExpression'));
}
// Remove spread attributes entirely as they're JS expressions
return attr.type !== 'mdxJsxExpressionAttribute';
});
}
}
});
};
};