@mintlify/common 1.0.1293 → 1.0.1294

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.
@@ -2,6 +2,7 @@ import { remarkCurrencyText } from './currencyMath.js';
2
2
  import { remarkPackageIslands, } from './islands/remarkPackageIslands.js';
3
3
  import { rehypeCodeBlocks, rehypeDynamicTailwindCss, rehypeKeyboardSymbols, rehypeListItemText, rehypeMdxExtractEndpoint, rehypeMdxExtractExamples, rehypeParamFieldIds, rehypeRawComponents, rehypeTable, rehypeUnicodeIds, rehypeZoomImages, remarkExtractChangelogFilters, remarkExtractTableOfContents, remarkFileTree, remarkFrames, remarkComponentIds, remarkMdxInjectSnippets, remarkMdxStyleStringToObject, remarkMdxRemoveUnusedVariables, remarkRemoveImports, remarkMdxExtractPanel, remarkResolveRelativeLinks, remarkVideo, remarkMdxClientComponentBoundaries, remarkExtractMultiView, remarkPrompt, remarkUnwrapInlineJsx, remarkUnwrapJsxHeadings, remarkMapExplicitAnchors, } from './plugins/index.js';
4
4
  import { remarkMdxExpandExpressions, } from './plugins/remark/remarkMdxExpandExpressions.js';
5
+ import { remarkMdxPageStyles } from './plugins/remark/remarkMdxPageStyles.js';
5
6
  import { remarkMdxDetectJs } from './plugins/remark/remarkMdxRemoveJs.js';
6
7
  import { remarkMdxRemoveUnknownJsx } from './plugins/remark/remarkMdxRemoveUnknownJsx/index.js';
7
8
  import { remarkMermaid } from './plugins/remark/remarkMermaid.js';
@@ -48,6 +49,7 @@ export const getMDXOptions = ({ data, remarkPlugins = [], earlyRemarkPlugins = [
48
49
  remarkPrompt,
49
50
  ...earlyRemarkPlugins,
50
51
  remarkMdxStyleStringToObject,
52
+ remarkMdxPageStyles,
51
53
  [remarkResolveRelativeLinks, { path: data.path }],
52
54
  remarkParseTitleMarkdown,
53
55
  [remarkComponentIds, data.pageMetadata],
@@ -68,7 +70,10 @@ export const getMDXOptions = ({ data, remarkPlugins = [], earlyRemarkPlugins = [
68
70
  ...remarkPlugins,
69
71
  remarkRenderTitleMarkdown,
70
72
  remarkMapExplicitAnchors,
71
- [remarkMdxRemoveUnknownJsx, { allowlist: [...allowedComponents, ...knownComponents] }],
73
+ [
74
+ remarkMdxRemoveUnknownJsx,
75
+ { allowlist: ['style', ...allowedComponents, ...knownComponents] },
76
+ ],
72
77
  [remarkMdxClientComponentBoundaries, { allowlist: knownComponents }],
73
78
  ],
74
79
  rehypePlugins: [
@@ -8,6 +8,7 @@ export * from './preprocessCustomHeadingIds.js';
8
8
  export * from './preprocessMdxFragmentCode.js';
9
9
  export * from './currencyMath.js';
10
10
  export * from './getMDXOptions.js';
11
+ export * from './page-style.js';
11
12
  export * from './astUtils.js';
12
13
  export * from './getS3ImageUri.js';
13
14
  export * from './getCodeStyling.js';
package/dist/mdx/index.js CHANGED
@@ -8,6 +8,7 @@ export * from './preprocessCustomHeadingIds.js';
8
8
  export * from './preprocessMdxFragmentCode.js';
9
9
  export * from './currencyMath.js';
10
10
  export * from './getMDXOptions.js';
11
+ export * from './page-style.js';
11
12
  export * from './astUtils.js';
12
13
  export * from './getS3ImageUri.js';
13
14
  export * from './getCodeStyling.js';
@@ -0,0 +1,9 @@
1
+ import type { MdxFlowExpression, MdxJsxFlowElement, MdxJsxTextElement, MdxTextExpression } from 'mdast-util-mdx';
2
+ import type { Node } from 'unist';
3
+ export type PageStyleElement = MdxJsxFlowElement | MdxJsxTextElement;
4
+ export declare const CLIENT_PAGE_STYLE_SCOPE = ".mdx-content";
5
+ export declare function sanitizePageStyle(css: string, scope: string): string;
6
+ export declare const isPageStyleElement: (node: Node) => node is PageStyleElement;
7
+ export declare function pageStyleText(element: PageStyleElement): string | undefined;
8
+ export declare function keptPageStyleExpression(element: PageStyleElement): MdxFlowExpression | MdxTextExpression | undefined;
9
+ export declare function canonicalPageStyle(element: PageStyleElement, css: string): PageStyleElement;
@@ -0,0 +1,183 @@
1
+ import { parseExpressionAt } from 'acorn';
2
+ import postcss from 'postcss';
3
+ import { isMdxExpression } from './utils.js';
4
+ const KEYFRAMES_NAME = /^page-[A-Za-z0-9_-]+$/;
5
+ const KEYFRAME_SELECTOR = /^(?:from|to|(?:\d+|\d*\.\d+)%)$/;
6
+ const PROPERTY_NAME = /^-{0,2}[A-Za-z][A-Za-z0-9-]*$/;
7
+ const CSS_ESCAPE = /\\(?:([0-9a-fA-F]{1,6})[ \t\n\r\f]?|([\s\S]))/g;
8
+ const FETCHING_FUNCTION = /(?:^|[^\w-])(?:-[a-z]+-)?(?:url|src|image|image-set|cross-fade|element|paint|expression)\s*\(/i;
9
+ const MAX_CODE_POINT = 0x10ffff;
10
+ const decodeCssEscapes = (value) => value.replace(CSS_ESCAPE, (_match, hex, character) => {
11
+ if (hex === undefined)
12
+ return character !== null && character !== void 0 ? character : '';
13
+ const codePoint = parseInt(hex, 16);
14
+ return codePoint === 0 || codePoint > MAX_CODE_POINT ? '�' : String.fromCodePoint(codePoint);
15
+ });
16
+ export const CLIENT_PAGE_STYLE_SCOPE = '.mdx-content';
17
+ const CONDITIONAL_AT_RULES = new Set(['media', 'supports', 'container']);
18
+ const LEADING_COMBINATOR = /^[>+~|]/;
19
+ const BLOCK_DELIMITER = /[{};]/;
20
+ const CONTAINED_POSITIONS = new Set([
21
+ 'static',
22
+ 'relative',
23
+ 'absolute',
24
+ 'sticky',
25
+ 'inherit',
26
+ 'initial',
27
+ 'unset',
28
+ 'revert',
29
+ 'revert-layer',
30
+ ]);
31
+ const isSafeText = (text) => !text.includes('/*') && !text.includes('</') && !FETCHING_FUNCTION.test(decodeCssEscapes(text));
32
+ const isContainedPosition = (declaration) => declaration.prop.toLowerCase() !== 'position' ||
33
+ CONTAINED_POSITIONS.has(decodeCssEscapes(declaration.value).trim().toLowerCase());
34
+ const isSafeDeclaration = (declaration) => PROPERTY_NAME.test(declaration.prop) &&
35
+ declaration.value.trim() !== '' &&
36
+ isSafeText(declaration.value) &&
37
+ isContainedPosition(declaration);
38
+ const serializeDeclarations = (nodes, allowImportant) => nodes
39
+ .filter((node) => node.type === 'decl' && isSafeDeclaration(node) && (allowImportant || !node.important))
40
+ .map((declaration) => `${declaration.prop}:${declaration.value.trim()}${declaration.important ? '!important' : ''}`)
41
+ .join(';');
42
+ function serializeKeyframe(frame) {
43
+ const selectors = frame.selectors.map((selector) => selector.trim().toLowerCase());
44
+ if (!selectors.every((selector) => KEYFRAME_SELECTOR.test(selector)))
45
+ return '';
46
+ const declarations = serializeDeclarations(frame.nodes, false);
47
+ return declarations ? `${selectors.join(',')}{${declarations}}` : '';
48
+ }
49
+ function serializeKeyframes(rule) {
50
+ var _a;
51
+ const name = rule.params.trim();
52
+ if (!KEYFRAMES_NAME.test(name))
53
+ return '';
54
+ const frames = ((_a = rule.nodes) !== null && _a !== void 0 ? _a : [])
55
+ .filter((node) => node.type === 'rule')
56
+ .map(serializeKeyframe)
57
+ .join('');
58
+ return frames ? `@keyframes ${name}{${frames}}` : '';
59
+ }
60
+ function scopeSelector(selector, scope) {
61
+ const prefix = `${scope} `;
62
+ const inner = (selector.startsWith(prefix) ? selector.slice(prefix.length) : selector).trim();
63
+ if (!inner ||
64
+ inner.includes('&') ||
65
+ LEADING_COMBINATOR.test(inner) ||
66
+ !isSafeText(inner) ||
67
+ BLOCK_DELIMITER.test(inner)) {
68
+ return undefined;
69
+ }
70
+ return `${prefix}${inner}`;
71
+ }
72
+ function serializeRule(rule, scope) {
73
+ const selectors = rule.selectors.map((selector) => scopeSelector(selector.trim(), scope));
74
+ if (selectors.some((selector) => selector === undefined))
75
+ return '';
76
+ const declarations = serializeDeclarations(rule.nodes, true);
77
+ return declarations ? `${selectors.join(',')}{${declarations}}` : '';
78
+ }
79
+ function serializeConditional(rule, name, scope) {
80
+ var _a;
81
+ const params = rule.params.trim();
82
+ if (!params || !isSafeText(params) || BLOCK_DELIMITER.test(params))
83
+ return '';
84
+ const body = ((_a = rule.nodes) !== null && _a !== void 0 ? _a : []).map((node) => serializeNode(node, scope)).join('');
85
+ return body ? `@${name} ${params}{${body}}` : '';
86
+ }
87
+ function serializeNode(node, scope) {
88
+ if (node.type === 'rule')
89
+ return serializeRule(node, scope);
90
+ if (node.type !== 'atrule')
91
+ return '';
92
+ const name = node.name.toLowerCase();
93
+ if (name === 'keyframes')
94
+ return serializeKeyframes(node);
95
+ if (CONDITIONAL_AT_RULES.has(name))
96
+ return serializeConditional(node, name, scope);
97
+ return '';
98
+ }
99
+ export function sanitizePageStyle(css, scope) {
100
+ let nodes;
101
+ try {
102
+ nodes = postcss.parse(css, { from: undefined }).nodes;
103
+ }
104
+ catch (_a) {
105
+ return '';
106
+ }
107
+ const sanitized = nodes.map((node) => serializeNode(node, scope)).join('');
108
+ return sanitized.includes('</') ? '' : sanitized;
109
+ }
110
+ export const isPageStyleElement = (node) => (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') &&
111
+ 'name' in node &&
112
+ node.name === 'style' &&
113
+ 'children' in node &&
114
+ Array.isArray(node.children);
115
+ const isWhitespaceText = (node) => node.type === 'text' && node.value.trim() === '';
116
+ function significantChildren(nodes) {
117
+ return nodes.filter((child) => !isWhitespaceText(child));
118
+ }
119
+ function styleChildren(element) {
120
+ const children = significantChildren(element.children);
121
+ const [only] = children;
122
+ return children.length === 1 && (only === null || only === void 0 ? void 0 : only.type) === 'paragraph'
123
+ ? significantChildren(only.children)
124
+ : children;
125
+ }
126
+ function staticString(source) {
127
+ var _a, _b;
128
+ try {
129
+ const expression = parseExpressionAt(source, 0, { ecmaVersion: 'latest' });
130
+ if (source.slice(expression.end).trim() !== '')
131
+ return undefined;
132
+ if (expression.type === 'TemplateLiteral' && expression.expressions.length === 0) {
133
+ return (_b = (_a = expression.quasis[0]) === null || _a === void 0 ? void 0 : _a.value.cooked) !== null && _b !== void 0 ? _b : undefined;
134
+ }
135
+ if (expression.type === 'Literal' && typeof expression.value === 'string') {
136
+ return expression.value;
137
+ }
138
+ }
139
+ catch (_c) {
140
+ return undefined;
141
+ }
142
+ return undefined;
143
+ }
144
+ export function pageStyleText(element) {
145
+ const [child, ...rest] = styleChildren(element);
146
+ if (!child || rest.length > 0 || !isMdxExpression(child))
147
+ return undefined;
148
+ return staticString(child.value);
149
+ }
150
+ export function keptPageStyleExpression(element) {
151
+ const children = element.children;
152
+ const [child, ...rest] = children;
153
+ if (element.attributes.length > 0 || !child || rest.length > 0 || !isMdxExpression(child)) {
154
+ return undefined;
155
+ }
156
+ const text = staticString(child.value);
157
+ return text && sanitizePageStyle(text, CLIENT_PAGE_STYLE_SCOPE) === text ? child : undefined;
158
+ }
159
+ const escapeTemplate = (text) => text.replace(/[`\\]|\$\{/g, (match) => `\\${match}`);
160
+ function templateProgram(css, raw) {
161
+ return {
162
+ type: 'Program',
163
+ sourceType: 'module',
164
+ comments: [],
165
+ body: [
166
+ {
167
+ type: 'ExpressionStatement',
168
+ expression: {
169
+ type: 'TemplateLiteral',
170
+ expressions: [],
171
+ quasis: [{ type: 'TemplateElement', tail: true, value: { raw, cooked: css } }],
172
+ },
173
+ },
174
+ ],
175
+ };
176
+ }
177
+ export function canonicalPageStyle(element, css) {
178
+ const raw = escapeTemplate(css);
179
+ const value = `\`${raw}\``;
180
+ const data = { estree: templateProgram(css, raw) };
181
+ return element.type === 'mdxJsxFlowElement'
182
+ ? Object.assign(Object.assign({}, element), { attributes: [], children: [{ type: 'mdxFlowExpression', value, data }] }) : Object.assign(Object.assign({}, element), { attributes: [], children: [{ type: 'mdxTextExpression', value, data }] });
183
+ }
@@ -11,6 +11,7 @@ export * from './remarkMdxClientComponentBoundaries.js';
11
11
  export * from './remarkMermaid.js';
12
12
  export * from './remarkNoCopyLanguage.js';
13
13
  export * from './remarkMdxRemoveJs.js';
14
+ export * from './remarkMdxPageStyles.js';
14
15
  export * from './remarkExtractChangelogFilters.js';
15
16
  export * from './remarkExpandContent.js';
16
17
  export * from './remarkSplitCodeGroup.js';
@@ -11,6 +11,7 @@ export * from './remarkMdxClientComponentBoundaries.js';
11
11
  export * from './remarkMermaid.js';
12
12
  export * from './remarkNoCopyLanguage.js';
13
13
  export * from './remarkMdxRemoveJs.js';
14
+ export * from './remarkMdxPageStyles.js';
14
15
  export * from './remarkExtractChangelogFilters.js';
15
16
  export * from './remarkExpandContent.js';
16
17
  export * from './remarkSplitCodeGroup.js';
@@ -0,0 +1,2 @@
1
+ import type { Root } from 'mdast';
2
+ export declare const remarkMdxPageStyles: () => (tree: Root) => void;
@@ -0,0 +1,17 @@
1
+ import { SKIP, visit } from 'unist-util-visit';
2
+ import { CLIENT_PAGE_STYLE_SCOPE, canonicalPageStyle, isPageStyleElement, pageStyleText, sanitizePageStyle, } from '../../page-style.js';
3
+ export const remarkMdxPageStyles = () => (tree) => {
4
+ visit(tree, (node, index, parent) => {
5
+ if (!isPageStyleElement(node) || !parent || index === undefined)
6
+ return;
7
+ const siblings = parent.children;
8
+ const text = pageStyleText(node);
9
+ const css = text === undefined ? '' : sanitizePageStyle(text, CLIENT_PAGE_STYLE_SCOPE);
10
+ if (css) {
11
+ siblings.splice(index, 1, canonicalPageStyle(node, css));
12
+ return SKIP;
13
+ }
14
+ siblings.splice(index, 1);
15
+ return [SKIP, index];
16
+ });
17
+ };
@@ -1,8 +1,9 @@
1
1
  import { jsx as jsxHandlers, toJs } from 'estree-util-to-js';
2
2
  import { remove } from 'unist-util-remove';
3
- import { CONTINUE, visit } from 'unist-util-visit';
3
+ import { CONTINUE, SKIP, visit } from 'unist-util-visit';
4
+ import { isPageStyleElement, keptPageStyleExpression } from '../../page-style.js';
4
5
  import { UNSAFE_OBJECT_KEYS } from '../../static-object-keys.js';
5
- import { isMdxJsEsm } from '../../utils.js';
6
+ import { isMdxExpression, isMdxJsEsm } from '../../utils.js';
6
7
  import { extractIdentifierRef, getKeptEsmStatements } from './pureTemplateComponents.js';
7
8
  const objectEstree = {
8
9
  type: 'Program',
@@ -552,7 +553,6 @@ function tryResolveAsString(estree, constants) {
552
553
  const val = constants.get(expr.name);
553
554
  return val !== undefined ? val : null;
554
555
  }
555
- const isMdxExpression = (node) => node.type === 'mdxTextExpression' || node.type === 'mdxFlowExpression';
556
556
  // mdx comments ({/* … */}) parse to an expression with an empty estree body.
557
557
  // the raw source must also be comment/whitespace-only: empty-body alone is an
558
558
  // undocumented parser detail a toolchain bump could silently widen
@@ -671,7 +671,19 @@ function sanitizer(edit) {
671
671
  edit.replaceChild(parent, index, replacement);
672
672
  });
673
673
  }
674
- edit.remove(tree, (node) => isMdxExpression(node) && !isInertExpression(node));
674
+ const pageStyleExpressions = new Set();
675
+ const unsafePageStyles = new Set();
676
+ visit(tree, isPageStyleElement, (node) => {
677
+ const expression = keptPageStyleExpression(node);
678
+ if (expression)
679
+ pageStyleExpressions.add(expression);
680
+ else
681
+ unsafePageStyles.add(node);
682
+ return SKIP;
683
+ });
684
+ if (unsafePageStyles.size > 0)
685
+ edit.remove(tree, (node) => unsafePageStyles.has(node));
686
+ edit.remove(tree, (node) => isMdxExpression(node) && !isInertExpression(node) && !pageStyleExpressions.has(node));
675
687
  const keptStatements = getKeptEsmStatements(tree);
676
688
  const keptNames = new Set(collectExportedNames({
677
689
  type: 'Program',
@@ -4,6 +4,7 @@ import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
4
4
  import type { Node } from 'unist';
5
5
  import type { MdxNodeBodyChildType } from '../types/mdx/index.js';
6
6
  export declare const isMdxJsEsm: (node: Node) => node is MdxjsEsm;
7
+ export declare const isMdxExpression: (node: Node) => node is MdxFlowExpression | MdxTextExpression;
7
8
  export declare function estreeIsProgram<T extends MdxFlowExpression | MdxTextExpression | MdxjsEsm>(node: T): node is T & {
8
9
  data: {
9
10
  estree: Program;
package/dist/mdx/utils.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export const isMdxJsEsm = (node) => node.type === 'mdxjsEsm';
2
+ export const isMdxExpression = (node) => node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression';
2
3
  export function estreeIsProgram(node) {
3
4
  var _a;
4
5
  return ((_a = node.data) === null || _a === void 0 ? void 0 : _a.estree) != null;