@mintlify/common 1.0.1278 → 1.0.1279

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.
@@ -34,3 +34,4 @@ export { TITLE_COMPONENTS } from './remarkTitleMarkdown.js';
34
34
  export * from './remarkUserMentions.js';
35
35
  export * from './remarkVisibilityForMarkdown.js';
36
36
  export * from './pureTemplateComponents.js';
37
+ export * from './remarkPrefixMediaBasePath.js';
@@ -34,3 +34,4 @@ export { TITLE_COMPONENTS } from './remarkTitleMarkdown.js';
34
34
  export * from './remarkUserMentions.js';
35
35
  export * from './remarkVisibilityForMarkdown.js';
36
36
  export * from './pureTemplateComponents.js';
37
+ export * from './remarkPrefixMediaBasePath.js';
@@ -0,0 +1,4 @@
1
+ import type { Root } from 'mdast';
2
+ export declare const remarkPrefixMediaBasePath: ({ basePath }: {
3
+ basePath: string;
4
+ }) => (tree: Root) => void;
@@ -0,0 +1,35 @@
1
+ import { visit } from 'unist-util-visit';
2
+ const MEDIA_ATTRIBUTES = new Set(['src', 'srcSet', 'srcset', 'poster', 'img', 'image']);
3
+ const prefix = (value, basePath) => value.startsWith('/') && !value.startsWith('//') ? `${basePath}${value}` : value;
4
+ const prefixSrcSet = (value, basePath) => value
5
+ .split(',')
6
+ .map((candidate) => {
7
+ const trimmed = candidate.trim();
8
+ const [url = '', ...descriptors] = trimmed.split(/\s+/);
9
+ return [prefix(url, basePath), ...descriptors].join(' ');
10
+ })
11
+ .join(', ');
12
+ export const remarkPrefixMediaBasePath = ({ basePath }) => {
13
+ return (tree) => {
14
+ if (!basePath)
15
+ return;
16
+ visit(tree, 'image', (node) => {
17
+ node.url = prefix(node.url, basePath);
18
+ });
19
+ const prefixAttributes = (element) => {
20
+ for (const attribute of element.attributes) {
21
+ if (attribute.type !== 'mdxJsxAttribute' ||
22
+ !MEDIA_ATTRIBUTES.has(attribute.name) ||
23
+ typeof attribute.value !== 'string') {
24
+ continue;
25
+ }
26
+ attribute.value =
27
+ attribute.name.toLowerCase() === 'srcset'
28
+ ? prefixSrcSet(attribute.value, basePath)
29
+ : prefix(attribute.value, basePath);
30
+ }
31
+ };
32
+ visit(tree, 'mdxJsxFlowElement', (node) => prefixAttributes(node));
33
+ visit(tree, 'mdxJsxTextElement', (node) => prefixAttributes(node));
34
+ };
35
+ };
@@ -0,0 +1,45 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { remark } from 'remark';
11
+ import remarkMdx from 'remark-mdx';
12
+ import { describe, expect, it } from 'vitest';
13
+ import { remarkPrefixMediaBasePath } from './remarkPrefixMediaBasePath.js';
14
+ const run = (mdx, basePath) => __awaiter(void 0, void 0, void 0, function* () {
15
+ return String(yield remark().use(remarkMdx).use(remarkPrefixMediaBasePath, { basePath }).process(mdx)).trim();
16
+ });
17
+ describe('remarkPrefixMediaBasePath', () => {
18
+ it('prefixes root-relative markdown images and media attributes', () => __awaiter(void 0, void 0, void 0, function* () {
19
+ const output = yield run([
20
+ '![Logo](/images/logo.png)',
21
+ '',
22
+ '<img src="/images/a.png" srcSet="/images/a.png 1x, /images/a@2x.png 2x" />',
23
+ '',
24
+ '<video src="/videos/demo.mp4" poster="/images/poster.png" />',
25
+ '',
26
+ '<Card title="Card" img="/images/card.png" href="/quickstart" />',
27
+ ].join('\n'), '/docs');
28
+ expect(output).toContain('![Logo](/docs/images/logo.png)');
29
+ expect(output).toContain('src="/docs/images/a.png"');
30
+ expect(output).toContain('srcSet="/docs/images/a.png 1x, /docs/images/a@2x.png 2x"');
31
+ expect(output).toContain('src="/docs/videos/demo.mp4"');
32
+ expect(output).toContain('poster="/docs/images/poster.png"');
33
+ expect(output).toContain('img="/docs/images/card.png"');
34
+ expect(output).toContain('href="/quickstart"');
35
+ }));
36
+ it('leaves external, protocol-relative and data urls alone', () => __awaiter(void 0, void 0, void 0, function* () {
37
+ const output = yield run('![a](https://example.com/a.png) <img src="//cdn.example.com/b.png" /> <img src="data:image/png;base64,AA" />', '/docs');
38
+ expect(output).toContain('(https://example.com/a.png)');
39
+ expect(output).toContain('src="//cdn.example.com/b.png"');
40
+ expect(output).toContain('src="data:image/png;base64,AA"');
41
+ }));
42
+ it('is a no-op without a base path', () => __awaiter(void 0, void 0, void 0, function* () {
43
+ expect(yield run('![Logo](/images/logo.png)', '')).toBe('![Logo](/images/logo.png)');
44
+ }));
45
+ });