@xyd-js/content 0.1.0-build.171
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 +2174 -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,257 @@
|
|
|
1
|
+
import { readFileSync, statSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
import { unified } from 'unified'
|
|
5
|
+
import remarkParse from 'remark-parse'
|
|
6
|
+
import remarkRehype from 'remark-rehype'
|
|
7
|
+
import rehypeStringify from 'rehype-stringify'
|
|
8
|
+
import { visit } from "unist-util-visit";
|
|
9
|
+
import type { Node } from 'mdast'
|
|
10
|
+
|
|
11
|
+
import GitHubSlugger from 'github-slugger';
|
|
12
|
+
|
|
13
|
+
import type { Settings, Sidebar, SidebarRoute } from '@xyd-js/core'
|
|
14
|
+
|
|
15
|
+
import { DocSectionSchema } from './types';
|
|
16
|
+
import { markdownPlugins } from "../"
|
|
17
|
+
import { mdParameters } from '../plugins/utils/mdParameters'
|
|
18
|
+
|
|
19
|
+
export async function mapSettingsToDocSections(xydSettings: Settings) {
|
|
20
|
+
const pages = flatPages(xydSettings.navigation?.sidebar || [], {})
|
|
21
|
+
.map(page => ({
|
|
22
|
+
name: page,
|
|
23
|
+
path: path.join(process.cwd(), page)
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
return await processSections(pages, xydSettings)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function mapContentToDocSections(
|
|
30
|
+
xydSettings: Settings,
|
|
31
|
+
route: string,
|
|
32
|
+
content: string,
|
|
33
|
+
) {
|
|
34
|
+
const sections: DocSectionSchema[] = []
|
|
35
|
+
let currentSection: DocSectionSchema | null = null
|
|
36
|
+
|
|
37
|
+
const rootSection: DocSectionSchema = {
|
|
38
|
+
// id: '',
|
|
39
|
+
pageId: '',
|
|
40
|
+
pageUrl: '',
|
|
41
|
+
pageTitle: '',
|
|
42
|
+
headingLevel: 0,
|
|
43
|
+
headingTitle: '',
|
|
44
|
+
summary: '',
|
|
45
|
+
content: '',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { remarkPlugins, rehypePlugins } = await markdownPlugins({}, xydSettings)
|
|
49
|
+
|
|
50
|
+
const processor = unified()
|
|
51
|
+
.use(remarkParse)
|
|
52
|
+
.use(remarkPlugins)
|
|
53
|
+
.use(() => {
|
|
54
|
+
return (tree: any) => {
|
|
55
|
+
let currentContent = ''
|
|
56
|
+
visit(tree, (node) => {
|
|
57
|
+
// Skip yaml frontmatter
|
|
58
|
+
if (node.type === 'yaml') {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Handle headings
|
|
63
|
+
if (node.type === 'heading') {
|
|
64
|
+
const heading = processNode(node)
|
|
65
|
+
|
|
66
|
+
// Save previous section's content
|
|
67
|
+
if (currentSection && currentContent) {
|
|
68
|
+
currentSection.content = currentContent.trim()
|
|
69
|
+
currentContent = ''
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const slug = slugify(heading)
|
|
73
|
+
|
|
74
|
+
if (node.depth === 1) {
|
|
75
|
+
if (rootSection.pageId) {
|
|
76
|
+
console.error("Multiple h1 found")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
rootSection.pageId = slug
|
|
80
|
+
rootSection.pageUrl = `/${route}`
|
|
81
|
+
rootSection.pageTitle = heading
|
|
82
|
+
rootSection.headingLevel = 1
|
|
83
|
+
rootSection.headingTitle = heading
|
|
84
|
+
sections.push(rootSection)
|
|
85
|
+
currentSection = rootSection
|
|
86
|
+
} else {
|
|
87
|
+
const section: DocSectionSchema = {
|
|
88
|
+
pageId: rootSection.pageId,
|
|
89
|
+
pageUrl: `${rootSection.pageUrl}#${slug}`, // TODO: QUERY PARAMS
|
|
90
|
+
pageTitle: rootSection.headingTitle,
|
|
91
|
+
headingLevel: node.depth,
|
|
92
|
+
headingTitle: heading,
|
|
93
|
+
content: '',
|
|
94
|
+
summary: '',
|
|
95
|
+
}
|
|
96
|
+
sections.push(section)
|
|
97
|
+
currentSection = section
|
|
98
|
+
}
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Skip if we're not in a section yet
|
|
103
|
+
if (!currentSection) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// For list items, add proper formatting
|
|
108
|
+
if (node.type === 'listItem') {
|
|
109
|
+
const itemContent = processNode(node)
|
|
110
|
+
currentContent += `- ${itemContent}\n`
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// For links, preserve the markdown format
|
|
115
|
+
if (node.type === 'link') {
|
|
116
|
+
const text = processNode(node)
|
|
117
|
+
currentContent += `[${text}](${node.url})\n`
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// For other nodes, just add their content
|
|
122
|
+
const nodeContent = processNode(node)
|
|
123
|
+
if (nodeContent) {
|
|
124
|
+
currentContent += nodeContent + '\n'
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// Save the last section's content
|
|
129
|
+
if (currentSection && currentContent) {
|
|
130
|
+
currentSection.content = currentContent.trim()
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
.use(remarkRehype)
|
|
135
|
+
.use(rehypePlugins)
|
|
136
|
+
.use(rehypeStringify)
|
|
137
|
+
|
|
138
|
+
await processor.process(content)
|
|
139
|
+
|
|
140
|
+
return sections
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function processNode(node: Node): string {
|
|
144
|
+
if ('value' in node) {
|
|
145
|
+
const value = node.value as string
|
|
146
|
+
|
|
147
|
+
// TODO: check if sanitized does not remove something important
|
|
148
|
+
const { sanitizedText } = mdParameters(value)
|
|
149
|
+
|
|
150
|
+
return sanitizedText
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if ('children' in node && Array.isArray(node.children)) {
|
|
154
|
+
return node.children.map((child: Node) => processNode(child)).join('')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return ''
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
async function processSections(pages: { name: string, path: string }[], xydSettings: Settings) {
|
|
162
|
+
return (await Promise.all(
|
|
163
|
+
pages.flatMap(async (file, i) => {
|
|
164
|
+
let filePath = ""
|
|
165
|
+
let err
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const p = file.path + ".md"
|
|
169
|
+
statSync(p)
|
|
170
|
+
filePath = p
|
|
171
|
+
} catch (error) {
|
|
172
|
+
err = error
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!filePath) {
|
|
176
|
+
try {
|
|
177
|
+
const p = file.path + ".mdx"
|
|
178
|
+
statSync(p)
|
|
179
|
+
filePath = p
|
|
180
|
+
err = null
|
|
181
|
+
} catch (error) {
|
|
182
|
+
err = error
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (err) {
|
|
187
|
+
console.error(err)
|
|
188
|
+
return []
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const content = readFileSync(filePath, 'utf-8')
|
|
192
|
+
const sections = await mapContentToDocSections(
|
|
193
|
+
xydSettings,
|
|
194
|
+
file.name,
|
|
195
|
+
content,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return sections.flat()
|
|
199
|
+
})
|
|
200
|
+
)).flat()
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// TODO: !!!! DRY !!!
|
|
204
|
+
function flatPages(
|
|
205
|
+
sidebar: (SidebarRoute | Sidebar | string)[],
|
|
206
|
+
groups: { [key: string]: string },
|
|
207
|
+
resp: string[] = [],
|
|
208
|
+
) {
|
|
209
|
+
sidebar.map(async side => {
|
|
210
|
+
if (typeof side === "string") {
|
|
211
|
+
resp.push(side)
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if ("route" in side) {
|
|
216
|
+
side.pages?.map(item => {
|
|
217
|
+
return flatPages([item], groups, resp)
|
|
218
|
+
})
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Type guard to check if it's a Sidebar
|
|
223
|
+
if ("group" in side) {
|
|
224
|
+
const groupKey = side.group || "";
|
|
225
|
+
if (groups[groupKey]) {
|
|
226
|
+
const link = groups[groupKey];
|
|
227
|
+
if (link) {
|
|
228
|
+
resp.push(link);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
side.pages?.map(async page => {
|
|
233
|
+
if (typeof page === "string") {
|
|
234
|
+
resp.push(page);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if ("virtual" in page && page.virtual) {
|
|
239
|
+
resp.push(page.virtual);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if ("pages" in page) {
|
|
244
|
+
return flatPages([page as Sidebar], groups, resp);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return resp;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function slugify(text: string) {
|
|
254
|
+
const slugger = new GitHubSlugger()
|
|
255
|
+
|
|
256
|
+
return slugger.slug(text)
|
|
257
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface DocSectionSchema { // TODO: move to @xyd-js/plugins/search ?
|
|
2
|
+
/**
|
|
3
|
+
* Id of the page e.g. "getting-started"
|
|
4
|
+
*/
|
|
5
|
+
pageId: string
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* URL of the page e.g. "/getting-started"
|
|
9
|
+
*/
|
|
10
|
+
pageUrl: string
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Title of the page e.g. "Getting Started"
|
|
14
|
+
*/
|
|
15
|
+
pageTitle: string
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Level of the heading e.g. 1, 2
|
|
19
|
+
*/
|
|
20
|
+
headingLevel: number
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Title of the heading e.g. "Making a new project"
|
|
24
|
+
*/
|
|
25
|
+
headingTitle: string
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Summary of the page e.g. "This is the summary of the page"
|
|
29
|
+
*/
|
|
30
|
+
summary: string
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Content of the section
|
|
34
|
+
*/
|
|
35
|
+
content: string
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type {Plugin} from 'rollup';
|
|
2
|
+
import mdx from '@mdx-js/rollup';
|
|
3
|
+
|
|
4
|
+
import {Settings} from "@xyd-js/core";
|
|
5
|
+
|
|
6
|
+
import {RemarkMdxTocOptions, markdownPlugins} from "../md";
|
|
7
|
+
|
|
8
|
+
export interface VitePluginInterface {
|
|
9
|
+
toc: RemarkMdxTocOptions
|
|
10
|
+
settings: Settings
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function vitePlugins(options: VitePluginInterface): Promise<Plugin[]> {
|
|
14
|
+
return [
|
|
15
|
+
mdx(await markdownPlugins(
|
|
16
|
+
options.toc,
|
|
17
|
+
options.settings
|
|
18
|
+
)),
|
|
19
|
+
];
|
|
20
|
+
}
|
package/src/fs.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { tmpdir } from "os";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { pathToFileURL } from "url";
|
|
4
|
+
import fs, { rm, writeFile } from "fs/promises"
|
|
5
|
+
|
|
6
|
+
import { VFile } from "vfile"
|
|
7
|
+
import { PluggableList } from "unified";
|
|
8
|
+
import { compile as mdxCompile } from "@mdx-js/mdx";
|
|
9
|
+
|
|
10
|
+
import { Settings } from "@xyd-js/core"
|
|
11
|
+
|
|
12
|
+
export type { VarCode } from "./types"
|
|
13
|
+
|
|
14
|
+
export class ContentFS {
|
|
15
|
+
constructor(
|
|
16
|
+
private readonly settings: Settings,
|
|
17
|
+
private readonly remarkPlugins: PluggableList,
|
|
18
|
+
private readonly rehypePlugins: PluggableList,
|
|
19
|
+
private readonly recmaPlugins: PluggableList,
|
|
20
|
+
) { }
|
|
21
|
+
|
|
22
|
+
public async compile(filePath: string): Promise<string> {
|
|
23
|
+
await fs.access(filePath)
|
|
24
|
+
|
|
25
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
26
|
+
|
|
27
|
+
return await this.compileContent(content, filePath)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async compileContent(content: string, filePath?: string): Promise<string> {
|
|
31
|
+
const vfile = new VFile({
|
|
32
|
+
path: filePath,
|
|
33
|
+
value: content,
|
|
34
|
+
contents: content
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const compiled = await mdxCompile(vfile, {
|
|
38
|
+
remarkPlugins: this.remarkPlugins,
|
|
39
|
+
rehypePlugins: this.rehypePlugins,
|
|
40
|
+
recmaPlugins: this.recmaPlugins || [],
|
|
41
|
+
development: false,
|
|
42
|
+
outputFormat: 'function-body',
|
|
43
|
+
jsx: false,
|
|
44
|
+
// jsx: false,
|
|
45
|
+
// outputFormat: "program", // needed for import/export
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return String(compiled)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
public async compileContentV2(content: string, filePath?: string): Promise<string> {
|
|
53
|
+
const vfile = new VFile({
|
|
54
|
+
path: filePath,
|
|
55
|
+
value: content,
|
|
56
|
+
contents: content
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const compiled = await mdxCompile(vfile, {
|
|
60
|
+
remarkPlugins: this.remarkPlugins,
|
|
61
|
+
rehypePlugins: this.rehypePlugins,
|
|
62
|
+
recmaPlugins: [],
|
|
63
|
+
development: false,
|
|
64
|
+
jsx: true,
|
|
65
|
+
outputFormat: "program", // needed for import/export
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const tempPath = join(tmpdir(), `mdx-${Date.now()}.mjs`);
|
|
69
|
+
await writeFile(tempPath, String(compiled), "utf8");
|
|
70
|
+
|
|
71
|
+
return tempPath
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public async readRaw(filePath: string) {
|
|
75
|
+
await fs.access(filePath)
|
|
76
|
+
|
|
77
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
78
|
+
|
|
79
|
+
return content
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {promises as fs} from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import React from "react";
|
|
5
|
+
import remarkFrontmatter from "remark-frontmatter";
|
|
6
|
+
import remarkMdxFrontmatter from "remark-mdx-frontmatter";
|
|
7
|
+
import {VFile} from "vfile";
|
|
8
|
+
import {compile as mdxCompile} from "@mdx-js/mdx";
|
|
9
|
+
|
|
10
|
+
import {Metadata, Sidebar, MetadataMap, PageURL, VirtualPage} from "@xyd-js/core";
|
|
11
|
+
|
|
12
|
+
// TODO: better algorithm + data structures - since it's on build time it's not a big deal nevertheless it should be changed in the future
|
|
13
|
+
|
|
14
|
+
// pageFrontMatters gets frontmatters for given navigation
|
|
15
|
+
export async function pageFrontMatters(navigation: Sidebar[], pagePathMapping: {
|
|
16
|
+
[key: string]: string
|
|
17
|
+
}): Promise<MetadataMap> {
|
|
18
|
+
const frontmatters: MetadataMap = {}
|
|
19
|
+
|
|
20
|
+
const promises: Promise<any>[] = []
|
|
21
|
+
|
|
22
|
+
function mapPages(page: PageURL) {
|
|
23
|
+
if (typeof page !== "string") {
|
|
24
|
+
if ("virtual" in page) {
|
|
25
|
+
promises.push(job(page, frontmatters, pagePathMapping))
|
|
26
|
+
} else if ("pages" in page) {
|
|
27
|
+
page.pages?.forEach(mapPages)
|
|
28
|
+
}
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
promises.push(job(page, frontmatters, pagePathMapping))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
navigation.map(async (nav: Sidebar) => {
|
|
36
|
+
if (typeof nav === "string") {
|
|
37
|
+
mapPages(nav)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
nav.pages?.forEach(mapPages)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
await Promise.all(promises)
|
|
45
|
+
|
|
46
|
+
// TODO: IN THE FUTURE BETTER API
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
if (globalThis.__xydHasIndexPage) {
|
|
49
|
+
await job("index", frontmatters, pagePathMapping)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return frontmatters
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function mdxExport(code: string) {
|
|
56
|
+
const scope = {
|
|
57
|
+
Fragment: React.Fragment,
|
|
58
|
+
jsxs: React.createElement,
|
|
59
|
+
jsx: React.createElement,
|
|
60
|
+
jsxDEV: React.createElement,
|
|
61
|
+
}
|
|
62
|
+
const fn = new Function(...Object.keys(scope), code)
|
|
63
|
+
return fn(scope)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function getFrontmatter(filePath: string): Promise<Metadata> {
|
|
67
|
+
const body = await fs.readFile(filePath, "utf-8");
|
|
68
|
+
|
|
69
|
+
const vfile = new VFile({
|
|
70
|
+
path: filePath,
|
|
71
|
+
value: body,
|
|
72
|
+
contents: body
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const compiled = await mdxCompile(vfile, {
|
|
76
|
+
remarkPlugins: [
|
|
77
|
+
remarkFrontmatter,
|
|
78
|
+
remarkMdxFrontmatter
|
|
79
|
+
],
|
|
80
|
+
rehypePlugins: [],
|
|
81
|
+
recmaPlugins: [],
|
|
82
|
+
outputFormat: 'function-body',
|
|
83
|
+
development: false,
|
|
84
|
+
|
|
85
|
+
// outputFormat: "program",
|
|
86
|
+
// jsx: true,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const code = String(compiled)
|
|
90
|
+
|
|
91
|
+
const {
|
|
92
|
+
reactFrontmatter, // in the future same key?
|
|
93
|
+
frontmatter
|
|
94
|
+
} = mdxExport(code)
|
|
95
|
+
|
|
96
|
+
const matter: Metadata = frontmatter
|
|
97
|
+
|
|
98
|
+
if (!matter) {
|
|
99
|
+
throw new Error(`Frontmatter not found in ${filePath}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let title = ""
|
|
103
|
+
if (typeof matter.title === "string") {
|
|
104
|
+
title = matter.title
|
|
105
|
+
}
|
|
106
|
+
if (reactFrontmatter) {
|
|
107
|
+
console.error("currently react frontmatter is not supported")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return matter
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// TODO: indices map to not do like this - search for mdx if not then md
|
|
114
|
+
async function job(page: string | VirtualPage, frontmatters: MetadataMap, pagePathMapping: { [key: string]: string }) {
|
|
115
|
+
let pageName = ""
|
|
116
|
+
if (typeof page === "string") {
|
|
117
|
+
pageName = page
|
|
118
|
+
} else if (page.page) {
|
|
119
|
+
pageName = page.page
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// @ts-ignore TODO: IN THE FUTURE BETTER API
|
|
123
|
+
if (globalThis.__xydFrontmatterNotExists && globalThis.__xydFrontmatterNotExists[pageName]) {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!pageName || !pagePathMapping[pageName]) {
|
|
128
|
+
console.log(`⚠️ "${pageName}" is defined in the docs.json navigation but the file does not exist.`)
|
|
129
|
+
|
|
130
|
+
// @ts-ignore
|
|
131
|
+
if (!globalThis.__xydFrontmatterNotExists) {
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
globalThis.__xydFrontmatterNotExists = {}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// @ts-ignore
|
|
137
|
+
globalThis.__xydFrontmatterNotExists[pageName] = true
|
|
138
|
+
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const filePath = path.join(process.cwd(), pagePathMapping[pageName])
|
|
143
|
+
|
|
144
|
+
const matter = await getFrontmatter(filePath)
|
|
145
|
+
|
|
146
|
+
frontmatters[pageName] = matter
|
|
147
|
+
}
|
package/src/types.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": ".",
|
|
4
|
+
"paths": {
|
|
5
|
+
"@/mdx/*": [
|
|
6
|
+
"src/mdx/*"
|
|
7
|
+
],
|
|
8
|
+
"@/navigation/*": [
|
|
9
|
+
"src/navigation/*"
|
|
10
|
+
],
|
|
11
|
+
"@/utils/*": [
|
|
12
|
+
"src/utils/*"
|
|
13
|
+
],
|
|
14
|
+
"@/vite-plugins/*": [
|
|
15
|
+
"src/vite-plugins/*"
|
|
16
|
+
],
|
|
17
|
+
"@xyd-js/core": [
|
|
18
|
+
"../xyd-core"
|
|
19
|
+
],
|
|
20
|
+
"@xyd-js/context": [
|
|
21
|
+
"../xyd-context/src/index.ts"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"target": "ES2020",
|
|
25
|
+
"module": "ESNext",
|
|
26
|
+
"moduleResolution": "node",
|
|
27
|
+
"strict": true,
|
|
28
|
+
"esModuleInterop": true,
|
|
29
|
+
"skipLibCheck": true,
|
|
30
|
+
"forceConsistentCasingInFileNames": true,
|
|
31
|
+
"outDir": "./dist",
|
|
32
|
+
"types": [
|
|
33
|
+
"node",
|
|
34
|
+
"estree",
|
|
35
|
+
"vite"
|
|
36
|
+
],
|
|
37
|
+
"declaration": true,
|
|
38
|
+
"declarationMap": true,
|
|
39
|
+
"incremental": true,
|
|
40
|
+
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo",
|
|
41
|
+
},
|
|
42
|
+
"include": [
|
|
43
|
+
"src/**/*.ts"
|
|
44
|
+
],
|
|
45
|
+
"exclude": [
|
|
46
|
+
"node_modules",
|
|
47
|
+
"dist"
|
|
48
|
+
]
|
|
49
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {defineConfig, Options} from 'tsup';
|
|
2
|
+
|
|
3
|
+
const config: Options = {
|
|
4
|
+
entry: {
|
|
5
|
+
index: 'src/index.ts',
|
|
6
|
+
vite: 'packages/vite/index.ts',
|
|
7
|
+
md: 'packages/md/index.ts',
|
|
8
|
+
},
|
|
9
|
+
dts: {
|
|
10
|
+
entry: {
|
|
11
|
+
index: 'src/index.ts',
|
|
12
|
+
vite: 'packages/vite/index.ts',
|
|
13
|
+
md: 'packages/md/index.ts'
|
|
14
|
+
},
|
|
15
|
+
resolve: true, // Resolve external types
|
|
16
|
+
},
|
|
17
|
+
format: ['esm'], // Output both ESM and CJS formats
|
|
18
|
+
target: 'node16', // Ensure compatibility with Node.js 16
|
|
19
|
+
splitting: false, // Disable code splitting
|
|
20
|
+
sourcemap: true, // Generate source maps
|
|
21
|
+
clean: true, // Clean the output directory before each build
|
|
22
|
+
esbuildOptions: (options) => {
|
|
23
|
+
// options.platform = 'node'; // Ensure the platform is set to Node.js
|
|
24
|
+
// options.external = ['node:fs/promises']; // Mark 'node:fs/promises' as external
|
|
25
|
+
// options.loader = { '.js': 'jsx' }; // Ensure proper handling of .js files
|
|
26
|
+
options.external = [
|
|
27
|
+
'rehype-mermaid'
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default defineConfig(config);
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {defineConfig} from 'vitest/config'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: [
|
|
8
|
+
'src/**/*.test.ts',
|
|
9
|
+
'packages/**/*.test.ts',
|
|
10
|
+
'**/__tests__/**/*.test.ts'
|
|
11
|
+
],
|
|
12
|
+
coverage: {
|
|
13
|
+
provider: 'v8',
|
|
14
|
+
reporter: ['text', 'json', 'html'],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
})
|