@xyd-js/content 0.0.0-build
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/CHANGELOG.md +14 -0
- package/ISSUES.md +1 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/TODO.md +2 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +1625 -0
- package/dist/index.js.map +1 -0
- package/dist/md.d.ts +72 -0
- package/dist/md.js +23508 -0
- package/dist/md.js.map +1 -0
- package/dist/mdToc-NBBxMJ4l.d.ts +12 -0
- package/dist/vite.d.ts +1066 -0
- package/dist/vite.js +20156 -0
- package/dist/vite.js.map +1 -0
- package/package.json +67 -0
- package/packages/md/index.ts +25 -0
- package/packages/md/plugins/component-directives/index.ts +3 -0
- package/packages/md/plugins/component-directives/mdComponentDirective.ts +577 -0
- package/packages/md/plugins/component-directives/types.ts +1 -0
- package/packages/md/plugins/component-directives/utils.ts +27 -0
- package/packages/md/plugins/composer/__fixtures__/1.single-example/input.md +7 -0
- package/packages/md/plugins/composer/__fixtures__/1.single-example/output.json +63 -0
- package/packages/md/plugins/composer/__fixtures__/2.single-example-with-name/input.md +7 -0
- package/packages/md/plugins/composer/__fixtures__/2.single-example-with-name/output.json +63 -0
- package/packages/md/plugins/composer/__fixtures__/3.multiple-examples/input.md +15 -0
- package/packages/md/plugins/composer/__fixtures__/3.multiple-examples/output.json +122 -0
- package/packages/md/plugins/composer/__fixtures__/4.example-groups/input.md +23 -0
- package/packages/md/plugins/composer/__fixtures__/4.example-groups/output.json +184 -0
- package/packages/md/plugins/composer/__tests__/mdComposer.test.ts +41 -0
- package/packages/md/plugins/composer/__tests__/testHelpers.ts +48 -0
- package/packages/md/plugins/composer/index.ts +1 -0
- package/packages/md/plugins/composer/mdComposer.ts +146 -0
- package/packages/md/plugins/developer-writing/index.ts +3 -0
- package/packages/md/plugins/developer-writing/mdCodeRehype.ts +81 -0
- package/packages/md/plugins/functions/__fixtures__/external.ts +4 -0
- package/packages/md/plugins/functions/__fixtures__/test-include.md +31 -0
- package/packages/md/plugins/functions/__fixtures__/test.js +11 -0
- package/packages/md/plugins/functions/__fixtures__/test.py +9 -0
- package/packages/md/plugins/functions/__fixtures__/test.ts +18 -0
- package/packages/md/plugins/functions/__tests__/mdFunctionImportCode.test.ts +314 -0
- package/packages/md/plugins/functions/__tests__/mdFunctionInclude.test.ts +44 -0
- package/packages/md/plugins/functions/__tests__/parseFunctionCall.test.ts +70 -0
- package/packages/md/plugins/functions/__tests__/testHelpers.ts +95 -0
- package/packages/md/plugins/functions/index.ts +15 -0
- package/packages/md/plugins/functions/mdFunctionChangelog.ts +135 -0
- package/packages/md/plugins/functions/mdFunctionImportCode.ts +92 -0
- package/packages/md/plugins/functions/mdFunctionInclude.ts +119 -0
- package/packages/md/plugins/functions/mdFunctionUniform.ts +79 -0
- package/packages/md/plugins/functions/types.ts +9 -0
- package/packages/md/plugins/functions/uniformProcessor.ts +349 -0
- package/packages/md/plugins/functions/utils.ts +457 -0
- package/packages/md/plugins/index.ts +125 -0
- package/packages/md/plugins/mdCode.ts +16 -0
- package/packages/md/plugins/mdHeadingId.ts +47 -0
- package/packages/md/plugins/mdImage.test.ts +59 -0
- package/packages/md/plugins/mdImage.ts +55 -0
- package/packages/md/plugins/mdImageRehype.ts +13 -0
- package/packages/md/plugins/mdPage.ts +35 -0
- package/packages/md/plugins/mdThemeSettings.ts +34 -0
- package/packages/md/plugins/mdToc.ts +229 -0
- package/packages/md/plugins/meta/index.ts +1 -0
- package/packages/md/plugins/meta/mdMeta.ts +198 -0
- package/packages/md/plugins/output-variables/__fixtures__/1.simple/input.md +22 -0
- package/packages/md/plugins/output-variables/__fixtures__/1.simple/output.json +191 -0
- package/packages/md/plugins/output-variables/__fixtures__/2.multiple-vars/input.md +21 -0
- package/packages/md/plugins/output-variables/__fixtures__/2.multiple-vars/output.json +127 -0
- package/packages/md/plugins/output-variables/__tests__/index.test.ts +28 -0
- package/packages/md/plugins/output-variables/__tests__/testHelpers.ts +36 -0
- package/packages/md/plugins/output-variables/index.ts +1 -0
- package/packages/md/plugins/output-variables/lib/const.ts +4 -0
- package/packages/md/plugins/output-variables/lib/factoryAttributes.ts +350 -0
- package/packages/md/plugins/output-variables/lib/factoryLabel.ts +135 -0
- package/packages/md/plugins/output-variables/lib/factoryName.ts +59 -0
- package/packages/md/plugins/output-variables/lib/index.ts +21 -0
- package/packages/md/plugins/output-variables/lib/outputVarsContainer.ts +328 -0
- package/packages/md/plugins/output-variables/lib/util.ts +494 -0
- package/packages/md/plugins/output-variables/remarkOutputVars.ts +22 -0
- package/packages/md/plugins/recmaOverrideComponents.ts +74 -0
- package/packages/md/plugins/rehypeHeading.ts +58 -0
- package/packages/md/plugins/types.ts +15 -0
- package/packages/md/plugins/utils/componentLike.ts +76 -0
- package/packages/md/plugins/utils/index.ts +2 -0
- package/packages/md/plugins/utils/injectCodeMeta.ts +59 -0
- package/packages/md/plugins/utils/mdParameters.test.ts +114 -0
- package/packages/md/plugins/utils/mdParameters.ts +249 -0
- package/packages/md/plugins/utils/mdastTypes.ts +42 -0
- package/packages/md/search/index.ts +257 -0
- package/packages/md/search/types.ts +36 -0
- package/packages/vite/index.ts +20 -0
- package/src/fs.ts +81 -0
- package/src/index.ts +7 -0
- package/src/navigation.ts +147 -0
- package/src/types.ts +8 -0
- package/tsconfig.json +49 -0
- package/tsup.config.ts +32 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {describe, it, expect} from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {parseFunctionCall} from '../utils';
|
|
4
|
+
import {FunctionName} from "../types";
|
|
5
|
+
|
|
6
|
+
describe('parseFunctionCall', () => {
|
|
7
|
+
const testCases = [
|
|
8
|
+
{
|
|
9
|
+
name: '1a. should parse uniform with file path and options',
|
|
10
|
+
function: FunctionName.Uniform,
|
|
11
|
+
input: `@uniform('~/path/to/resource.ts', {"mini": "Settings"})`,
|
|
12
|
+
expected: ['~/path/to/resource.ts', {mini: 'Settings'}]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: '1b. should parse uniform with file path and options',
|
|
16
|
+
function: FunctionName.Uniform,
|
|
17
|
+
input: `@uniform('~/path/to/resource.ts', {mini: 'Settings'})`,
|
|
18
|
+
expected: ['~/path/to/resource.ts', {mini: 'Settings'}]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: '2. should parse uniform with file path only',
|
|
22
|
+
function: FunctionName.Uniform,
|
|
23
|
+
input: '@uniform(~/path/to/resource.ts)',
|
|
24
|
+
expected: ['~/path/to/resource.ts']
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: '3a. should handle malformed uniform call',
|
|
28
|
+
function: FunctionName.Uniform,
|
|
29
|
+
input: '@uniform_invalid()',
|
|
30
|
+
expected: null
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: '3b. should handle malformed uniform call',
|
|
34
|
+
function: FunctionName.Uniform,
|
|
35
|
+
input: 'uniform()',
|
|
36
|
+
expected: null
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: '4. should parse function with md attributes',
|
|
40
|
+
function: FunctionName.ImportCode,
|
|
41
|
+
input: `@importCode[descHead="Tip" desc="It's a nice code"] ~/path/to/resource.ts`,
|
|
42
|
+
expected: ['~/path/to/resource.ts', {__mdAttrs: {descHead: 'Tip', desc: "It's a nice code"}}]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: '4. should parse function with md attributes + quotes',
|
|
46
|
+
function: FunctionName.ImportCode,
|
|
47
|
+
input: `@importCode[descHead="Tip" desc="You can use md attributes!"] "~/path/to/resource.ts"`,
|
|
48
|
+
expected: ['~/path/to/resource.ts', {__mdAttrs: {descHead: 'Tip', desc: "You can use md attributes!"}}]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: '4. should parse function with md attributes + shortand attrs',
|
|
52
|
+
function: FunctionName.ImportCode,
|
|
53
|
+
input: `@importCode[!scroll lines descHead="Tip" desc="You can use md attributes!"] "~/path/to/resource.ts"`,
|
|
54
|
+
expected: ['~/path/to/resource.ts', {__mdAttrs: {scroll: "false", lines: "true", descHead: 'Tip', desc: "You can use md attributes!"}}]
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
testCases.forEach(({name, function: functionName, input, expected}) => {
|
|
59
|
+
it(name, () => {
|
|
60
|
+
const node = {
|
|
61
|
+
children: [{
|
|
62
|
+
type: 'text',
|
|
63
|
+
value: input
|
|
64
|
+
}]
|
|
65
|
+
};
|
|
66
|
+
const result = parseFunctionCall(node, functionName);
|
|
67
|
+
expect(result).toEqual(expected);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {VFile} from 'vfile';
|
|
3
|
+
|
|
4
|
+
export function importCodeMockTree(importPath: string) {
|
|
5
|
+
return {
|
|
6
|
+
type: 'root',
|
|
7
|
+
children: [
|
|
8
|
+
{
|
|
9
|
+
type: 'paragraph',
|
|
10
|
+
children: [
|
|
11
|
+
{
|
|
12
|
+
type: 'text',
|
|
13
|
+
value: `@importCode "${importPath}"`
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function importCodeMdAttributesMockTree(
|
|
22
|
+
importPath: string,
|
|
23
|
+
attributes: Record<string, string>
|
|
24
|
+
) {
|
|
25
|
+
// Convert attributes object to md attribute string
|
|
26
|
+
const attrsString = Object.entries(attributes)
|
|
27
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
28
|
+
.join(' ');
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
type: 'root',
|
|
32
|
+
children: [
|
|
33
|
+
{
|
|
34
|
+
type: 'paragraph',
|
|
35
|
+
children: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
value: `@importCode[${attrsString}] "${importPath}"`
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function importCodeMockTreeAlternative(importPath: string) {
|
|
47
|
+
return {
|
|
48
|
+
type: 'root',
|
|
49
|
+
children: [
|
|
50
|
+
{
|
|
51
|
+
type: 'paragraph',
|
|
52
|
+
children: [
|
|
53
|
+
{
|
|
54
|
+
type: 'text',
|
|
55
|
+
value: `@importCode("${importPath}")`
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
export function createMockFile(dirname?: string) {
|
|
65
|
+
return new VFile({
|
|
66
|
+
path: 'test.md',
|
|
67
|
+
value: '',
|
|
68
|
+
dirname: dirname || path.resolve(__dirname, '../__fixtures__')
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
export function createMockFetch(mockResponses: Record<string, string>) {
|
|
74
|
+
const originalFetch = global.fetch;
|
|
75
|
+
|
|
76
|
+
global.fetch = (async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
|
|
77
|
+
const url = input.toString();
|
|
78
|
+
|
|
79
|
+
if (mockResponses[url]) {
|
|
80
|
+
return {
|
|
81
|
+
ok: true,
|
|
82
|
+
text: async () => mockResponses[url]
|
|
83
|
+
} as Response;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
87
|
+
}) as typeof fetch;
|
|
88
|
+
|
|
89
|
+
return originalFetch;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
export function restoreFetch(originalFetch: typeof global.fetch) {
|
|
94
|
+
global.fetch = originalFetch;
|
|
95
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
mdFunctionImportCode
|
|
3
|
+
} from "./mdFunctionImportCode"
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
mdFunctionInclude
|
|
7
|
+
} from "./mdFunctionInclude"
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
mdFunctionUniform
|
|
11
|
+
} from "./mdFunctionUniform"
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
mdFunctionChangelog
|
|
15
|
+
} from "./mdFunctionChangelog"
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import { VFile } from 'vfile';
|
|
3
|
+
import { unified } from 'unified';
|
|
4
|
+
import remarkParse from 'remark-parse';
|
|
5
|
+
import remarkMdx from 'remark-mdx';
|
|
6
|
+
|
|
7
|
+
import { Settings } from '@xyd-js/core';
|
|
8
|
+
|
|
9
|
+
import { FunctionName } from './types';
|
|
10
|
+
import { FunctionOptions, parseFunctionCall, downloadContent, resolvePathAlias } from './utils';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
|
|
13
|
+
interface ChangelogEntry {
|
|
14
|
+
version: string;
|
|
15
|
+
date?: string;
|
|
16
|
+
content: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function mdFunctionChangelog(settings?: Settings) {
|
|
20
|
+
return function (options: FunctionOptions = {}) {
|
|
21
|
+
return async function transformer(tree: any, file: VFile) {
|
|
22
|
+
const promises: Promise<void>[] = [];
|
|
23
|
+
|
|
24
|
+
visit(tree, 'paragraph', (node: any) => {
|
|
25
|
+
if (!file?.dirname) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const result = parseFunctionCall(node, FunctionName.Changelog);
|
|
29
|
+
if (!result || !result.length) return;
|
|
30
|
+
|
|
31
|
+
const importPath = result[0];
|
|
32
|
+
// let fullDirPath = path.join(process.cwd(), file.dirname || "")
|
|
33
|
+
// fullDirPath = process.cwd()
|
|
34
|
+
const resolvedPath = resolvePathAlias(importPath, settings, file) || importPath;
|
|
35
|
+
|
|
36
|
+
const promise = (async () => {
|
|
37
|
+
try {
|
|
38
|
+
const content = await downloadContent(resolvedPath, file, options.resolveFrom);
|
|
39
|
+
const entries = parseChangelog(content);
|
|
40
|
+
|
|
41
|
+
// Replace the node with the generated content
|
|
42
|
+
node.type = 'mdxJsxFlowElement';
|
|
43
|
+
node.attributes = [];
|
|
44
|
+
node.children = entries.map(entry => {
|
|
45
|
+
// Parse the markdown content
|
|
46
|
+
const parsedContent = unified()
|
|
47
|
+
.use(remarkParse)
|
|
48
|
+
.use(remarkMdx)
|
|
49
|
+
.parse(entry.content);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
type: 'mdxJsxFlowElement',
|
|
53
|
+
name: 'Update',
|
|
54
|
+
attributes: [
|
|
55
|
+
{
|
|
56
|
+
type: 'mdxJsxAttribute',
|
|
57
|
+
name: 'version',
|
|
58
|
+
value: entry.version
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'mdxJsxAttribute',
|
|
62
|
+
name: 'date',
|
|
63
|
+
value: entry.date || ''
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
children: parsedContent.children
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`Error processing changelog: ${resolvedPath}`, error);
|
|
71
|
+
}
|
|
72
|
+
})();
|
|
73
|
+
|
|
74
|
+
promises.push(promise);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await Promise.all(promises);
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function parseChangelog(content: string): ChangelogEntry[] {
|
|
83
|
+
const entries: ChangelogEntry[] = [];
|
|
84
|
+
const lines = content.split('\n');
|
|
85
|
+
let currentEntry: ChangelogEntry | null = null;
|
|
86
|
+
let currentContent: string[] = [];
|
|
87
|
+
|
|
88
|
+
for (let i = 0; i < lines.length; i++) {
|
|
89
|
+
const line = lines[i];
|
|
90
|
+
|
|
91
|
+
// Match different version header formats:
|
|
92
|
+
// 1. ## [X.Y.Z] - any date format
|
|
93
|
+
// 2. ## [X.Y.Z]
|
|
94
|
+
// 3. ## X.Y.Z
|
|
95
|
+
// 4. ## [unreleased] - any date format
|
|
96
|
+
// 5. ## [0.0.1-alpha.0] - any date format
|
|
97
|
+
const versionMatch = line.match(/^##\s+(?:\[?([^\]]+)\]?(?:\s*-\s*([^\n]+))?)/);
|
|
98
|
+
if (versionMatch) {
|
|
99
|
+
// Save previous entry if exists
|
|
100
|
+
if (currentEntry) {
|
|
101
|
+
currentEntry.content = currentContent.join('\n').trim();
|
|
102
|
+
entries.push(currentEntry);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Start new entry
|
|
106
|
+
currentEntry = {
|
|
107
|
+
version: versionMatch[1],
|
|
108
|
+
date: versionMatch[2]?.trim() || '',
|
|
109
|
+
content: ''
|
|
110
|
+
};
|
|
111
|
+
currentContent = [];
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Skip the main title (# xyd-js)
|
|
116
|
+
if (line.startsWith('# ')) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Add content to current entry
|
|
121
|
+
if (currentEntry) {
|
|
122
|
+
currentContent.push(line);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Add last entry
|
|
127
|
+
if (currentEntry) {
|
|
128
|
+
currentEntry.content = currentContent.join('\n').trim();
|
|
129
|
+
entries.push(currentEntry);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return entries;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import { VFile } from 'vfile';
|
|
3
|
+
|
|
4
|
+
import { Settings } from '@xyd-js/core';
|
|
5
|
+
|
|
6
|
+
import { FunctionName } from "./types";
|
|
7
|
+
import {
|
|
8
|
+
FunctionOptions,
|
|
9
|
+
parseFunctionCall,
|
|
10
|
+
parseImportPath,
|
|
11
|
+
processContent,
|
|
12
|
+
detectLanguage,
|
|
13
|
+
readLocalFile,
|
|
14
|
+
fetchFileContent,
|
|
15
|
+
resolvePathAlias
|
|
16
|
+
} from './utils';
|
|
17
|
+
import { injectCodeMeta } from '../utils/injectCodeMeta';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
|
|
20
|
+
export function mdFunctionImportCode(settings?: Settings) {
|
|
21
|
+
return function (options: FunctionOptions = {}) {
|
|
22
|
+
return async function transformer(tree: any, file: VFile) {
|
|
23
|
+
// Collect promises for async operations
|
|
24
|
+
const promises: Promise<void>[] = [];
|
|
25
|
+
|
|
26
|
+
console.time('plugin:mdFunctionImportCode');
|
|
27
|
+
|
|
28
|
+
visit(tree, 'paragraph', (node: any) => {
|
|
29
|
+
// Try to parse the function call
|
|
30
|
+
const result = parseFunctionCall(node, FunctionName.ImportCode);
|
|
31
|
+
if (!result) return;
|
|
32
|
+
|
|
33
|
+
const importPath = result[0];
|
|
34
|
+
const args = result[1];
|
|
35
|
+
const mdAttrs = args?.__mdAttrs || {};
|
|
36
|
+
|
|
37
|
+
// let fullDirPath = path.join(process.cwd(), file.dirname || "")
|
|
38
|
+
// fullDirPath = process.cwd()
|
|
39
|
+
// Parse the import path to extract file path, regions, and line ranges
|
|
40
|
+
const { filePath, regions, lineRanges } = parseImportPath(
|
|
41
|
+
resolvePathAlias(importPath, settings, file) || importPath
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Determine if this is a local or external file
|
|
45
|
+
const isExternal = filePath.startsWith('http://') || filePath.startsWith('https://');
|
|
46
|
+
|
|
47
|
+
// Create a promise for this node
|
|
48
|
+
const promise = (async () => {
|
|
49
|
+
try {
|
|
50
|
+
// Get the file content
|
|
51
|
+
let content: string;
|
|
52
|
+
|
|
53
|
+
if (isExternal) {
|
|
54
|
+
// Fetch external content
|
|
55
|
+
content = await fetchFileContent(filePath);
|
|
56
|
+
} else {
|
|
57
|
+
const baseDir = options.resolveFrom || (file.dirname || process.cwd());
|
|
58
|
+
content = readLocalFile(filePath, baseDir);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Process the content based on regions and line ranges
|
|
62
|
+
let processedContent = processContent(content, regions, lineRanges);
|
|
63
|
+
|
|
64
|
+
// Detect language from file extension
|
|
65
|
+
const language = detectLanguage(filePath);
|
|
66
|
+
|
|
67
|
+
// Replace the paragraph with a code block
|
|
68
|
+
node.type = 'code';
|
|
69
|
+
node.lang = language;
|
|
70
|
+
node.value = processedContent;
|
|
71
|
+
node.children = undefined;
|
|
72
|
+
|
|
73
|
+
// Inject code meta and props
|
|
74
|
+
const attrsString = args?.__mdAttrs ? Object.entries(args.__mdAttrs).map(([k,v]) => `${k}="${v}"`).join(' ') : undefined;
|
|
75
|
+
const metaString = attrsString ? `[${attrsString}]` : undefined;
|
|
76
|
+
injectCodeMeta(node, metaString);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(`Error importing file: ${filePath}`, error);
|
|
79
|
+
// Keep the node as is if there's an error
|
|
80
|
+
}
|
|
81
|
+
})();
|
|
82
|
+
|
|
83
|
+
// Add the promise to our collection
|
|
84
|
+
promises.push(promise);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Wait for all promises to resolve
|
|
88
|
+
await Promise.all(promises);
|
|
89
|
+
console.timeEnd('plugin:mdFunctionImportCode');
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import { VFile } from 'vfile';
|
|
3
|
+
import { unified } from 'unified';
|
|
4
|
+
import remarkParse from 'remark-parse';
|
|
5
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
6
|
+
import { mdxjs } from 'micromark-extension-mdxjs';
|
|
7
|
+
import { mdxFromMarkdown } from 'mdast-util-mdx';
|
|
8
|
+
|
|
9
|
+
import { Settings } from '@xyd-js/core';
|
|
10
|
+
|
|
11
|
+
import { FunctionName } from './types';
|
|
12
|
+
import {
|
|
13
|
+
FunctionOptions,
|
|
14
|
+
parseFunctionCall,
|
|
15
|
+
downloadContent,
|
|
16
|
+
resolvePathAlias,
|
|
17
|
+
} from './utils';
|
|
18
|
+
import { defaultRemarkPlugins } from '..';
|
|
19
|
+
import remarkFrontmatter from 'remark-frontmatter';
|
|
20
|
+
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
|
|
21
|
+
import { remarkMdxToc } from '../mdToc';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
|
|
24
|
+
export function mdFunctionInclude(settings?: Settings) {
|
|
25
|
+
return function (options: FunctionOptions = {}) {
|
|
26
|
+
return async function transformer(tree: any, file: VFile) {
|
|
27
|
+
console.time('plugin:mdFunctionInclude');
|
|
28
|
+
|
|
29
|
+
// Collect all replacements to avoid index shifting issues
|
|
30
|
+
const replacements: Array<{
|
|
31
|
+
parent: any;
|
|
32
|
+
index: number;
|
|
33
|
+
children: any[];
|
|
34
|
+
}> = [];
|
|
35
|
+
|
|
36
|
+
// First pass: collect all @include nodes and their replacements
|
|
37
|
+
const promises: Promise<void>[] = [];
|
|
38
|
+
|
|
39
|
+
visit(tree, 'paragraph', (node: any, index: number | undefined, parent: any) => {
|
|
40
|
+
const result = parseFunctionCall(node, FunctionName.Include);
|
|
41
|
+
if (!result || index === undefined) return;
|
|
42
|
+
|
|
43
|
+
const importPath = result[0];
|
|
44
|
+
const resolvedPath =
|
|
45
|
+
resolvePathAlias(importPath, settings, file) || importPath;
|
|
46
|
+
|
|
47
|
+
const resolvedIncludeBasePath =
|
|
48
|
+
resolvePathAlias(resolvedPath, settings, file) || importPath;
|
|
49
|
+
|
|
50
|
+
const promise = (async () => {
|
|
51
|
+
try {
|
|
52
|
+
const ext = resolvedPath.split('.').pop();
|
|
53
|
+
const content = await downloadContent(
|
|
54
|
+
resolvedPath,
|
|
55
|
+
file,
|
|
56
|
+
options.resolveFrom,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const includeFilePath = path.join(file.dirname || "", resolvedIncludeBasePath)
|
|
60
|
+
const includedFile = new VFile({
|
|
61
|
+
path: includeFilePath,
|
|
62
|
+
dirname: path.dirname(includeFilePath),
|
|
63
|
+
value: content
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
let parsedTree;
|
|
67
|
+
|
|
68
|
+
const remarkPlugins = defaultRemarkPlugins({} as any, settings)
|
|
69
|
+
.filter(plugin => plugin !== remarkFrontmatter)
|
|
70
|
+
.filter(plugin => plugin !== remarkMdxFrontmatter)
|
|
71
|
+
.filter(plugin => !(typeof plugin === 'function' && (plugin.name === 'remarkMdxToc' || plugin.name === 'remarkMdxToc2')))
|
|
72
|
+
|
|
73
|
+
if (ext === 'mdx') {
|
|
74
|
+
// Parse MDX into MDAST using micromark + mdast-util-mdx
|
|
75
|
+
parsedTree = fromMarkdown(content, {
|
|
76
|
+
extensions: [mdxjs()],
|
|
77
|
+
mdastExtensions: [mdxFromMarkdown()],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Apply remark plugins to the parsed MDX tree with the correct file context
|
|
81
|
+
const mdxProcessor = unified().use(remarkPlugins);
|
|
82
|
+
parsedTree = await mdxProcessor.run(parsedTree, includedFile);
|
|
83
|
+
} else {
|
|
84
|
+
// Regular Markdown file using remarkParse
|
|
85
|
+
const processor = unified()
|
|
86
|
+
.use(remarkParse)
|
|
87
|
+
.use(remarkPlugins);
|
|
88
|
+
|
|
89
|
+
parsedTree = await processor.run(processor.parse(content), includedFile);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Store the replacement instead of applying it immediately
|
|
93
|
+
replacements.push({
|
|
94
|
+
parent,
|
|
95
|
+
index,
|
|
96
|
+
children: parsedTree.children,
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`Error including file: ${resolvedPath}`, error);
|
|
100
|
+
}
|
|
101
|
+
})();
|
|
102
|
+
|
|
103
|
+
promises.push(promise);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Wait for all content to be downloaded and parsed
|
|
107
|
+
await Promise.all(promises);
|
|
108
|
+
|
|
109
|
+
// Second pass: apply replacements in reverse order to avoid index shifting
|
|
110
|
+
replacements
|
|
111
|
+
.sort((a, b) => b.index - a.index) // Sort by index in descending order
|
|
112
|
+
.forEach(({ parent, index, children }) => {
|
|
113
|
+
parent.children.splice(index, 1, ...children);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
console.timeEnd('plugin:mdFunctionInclude');
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import { VFile } from 'vfile';
|
|
3
|
+
|
|
4
|
+
import { Settings } from '@xyd-js/core'
|
|
5
|
+
import uniform, { pluginJsonView, Reference, TypeDocReferenceContext } from "@xyd-js/uniform"
|
|
6
|
+
|
|
7
|
+
import { FunctionName } from "./types";
|
|
8
|
+
import {
|
|
9
|
+
FunctionOptions,
|
|
10
|
+
parseFunctionCall,
|
|
11
|
+
} from './utils';
|
|
12
|
+
|
|
13
|
+
// Import the processUniformFunctionCall function
|
|
14
|
+
import { processUniformFunctionCall } from './uniformProcessor';
|
|
15
|
+
import { uniformToMiniUniform } from '@xyd-js/sources/ts';
|
|
16
|
+
|
|
17
|
+
export function mdFunctionUniform(settings?: Settings) {
|
|
18
|
+
return function (options: FunctionOptions = {}) {
|
|
19
|
+
return async function transformer(tree: any, file: VFile) {
|
|
20
|
+
// Collect promises for async operations
|
|
21
|
+
const promises: Promise<void>[] = [];
|
|
22
|
+
|
|
23
|
+
console.time('plugin:mdFunctionUniform');
|
|
24
|
+
|
|
25
|
+
visit(tree, 'paragraph', (node: any) => {
|
|
26
|
+
// Try to parse the function call
|
|
27
|
+
const result = parseFunctionCall(node, FunctionName.Uniform);
|
|
28
|
+
if (!result) return;
|
|
29
|
+
|
|
30
|
+
const importPath = result[0];
|
|
31
|
+
const importArgs = result[1];
|
|
32
|
+
|
|
33
|
+
// Create a promise for this node
|
|
34
|
+
const promise = (async () => {
|
|
35
|
+
try {
|
|
36
|
+
// Process the uniform function call
|
|
37
|
+
let references = await processUniformFunctionCall(
|
|
38
|
+
importPath,
|
|
39
|
+
file,
|
|
40
|
+
options.resolveFrom,
|
|
41
|
+
settings,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (importArgs?.mini && references) { // TODO: move to `processUniformFunctionCall`
|
|
45
|
+
references = uniformToMiniUniform(importArgs.mini, references as Reference<TypeDocReferenceContext>[]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (references) {
|
|
49
|
+
node.type = 'code';
|
|
50
|
+
node.lang = 'json';
|
|
51
|
+
const jsonViewRefs = uniform(references, {
|
|
52
|
+
plugins: [
|
|
53
|
+
pluginJsonView()
|
|
54
|
+
]
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// TODO: support multiple json views
|
|
58
|
+
node.value = jsonViewRefs.out.jsonViews[0]
|
|
59
|
+
node.children = undefined;
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(`Error processing uniform function call: ${importPath}`, error);
|
|
63
|
+
// Keep the node as is if there's an error
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
66
|
+
|
|
67
|
+
// Add the promise to our collection
|
|
68
|
+
promises.push(promise);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Wait for all promises to resolve
|
|
72
|
+
await Promise.all(promises);
|
|
73
|
+
console.timeEnd('plugin:mdFunctionUniform');
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|