@hanzo/docs-mdx 14.1.0
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/LICENSE +21 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +16 -0
- package/dist/build-mdx-LN7FEKIP.js +8 -0
- package/dist/build-mdx-RXJZQXGA.js +8 -0
- package/dist/bun/index.d.ts +25 -0
- package/dist/bun/index.js +52 -0
- package/dist/chunk-4JSFLXXT.js +8 -0
- package/dist/chunk-5OBUOALK.js +141 -0
- package/dist/chunk-72JS4QVZ.js +17 -0
- package/dist/chunk-7I4W7XGI.js +179 -0
- package/dist/chunk-7W73RILB.js +173 -0
- package/dist/chunk-A3YIGE7S.js +334 -0
- package/dist/chunk-AOTZP2TV.js +152 -0
- package/dist/chunk-AXJB5MGS.js +173 -0
- package/dist/chunk-DMIIE3XZ.js +179 -0
- package/dist/chunk-DTFUANSF.js +40 -0
- package/dist/chunk-JWZR25CW.js +116 -0
- package/dist/chunk-K7N6GD4M.js +17 -0
- package/dist/chunk-LXB7WYAF.js +334 -0
- package/dist/chunk-MYAVS2LD.js +116 -0
- package/dist/chunk-OLD35ARB.js +116 -0
- package/dist/chunk-PW2AZGGD.js +125 -0
- package/dist/chunk-RGBNABKS.js +334 -0
- package/dist/chunk-RPUM7REY.js +40 -0
- package/dist/chunk-RR2X6AE6.js +274 -0
- package/dist/chunk-S7KOJHHO.js +89 -0
- package/dist/chunk-STUCUTJQ.js +334 -0
- package/dist/chunk-T6G5VOED.js +116 -0
- package/dist/chunk-U5YPLCO5.js +89 -0
- package/dist/chunk-UB55AMXC.js +274 -0
- package/dist/chunk-VITVHHR6.js +334 -0
- package/dist/chunk-VKSHE52K.js +274 -0
- package/dist/chunk-VWJKRQZR.js +19 -0
- package/dist/chunk-WAAWFNDX.js +179 -0
- package/dist/chunk-WGXYJGSZ.js +141 -0
- package/dist/chunk-WLJ6EKOZ.js +17 -0
- package/dist/chunk-WMYYALAS.js +334 -0
- package/dist/chunk-Y7ISNZ7X.js +216 -0
- package/dist/chunk-YKRCQ42E.js +216 -0
- package/dist/chunk-ZAYZWFWP.js +89 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.js +63 -0
- package/dist/core-BQcKaqmC.d.ts +350 -0
- package/dist/core-BhWOtait.d.ts +350 -0
- package/dist/core-CV8uFMUa.d.ts +350 -0
- package/dist/core-DAQ64Hkq.d.ts +350 -0
- package/dist/core-DZtRjhds.d.ts +350 -0
- package/dist/core-De5K4ixv.d.ts +350 -0
- package/dist/core-X5ggQtBM.d.ts +350 -0
- package/dist/index-BqkSNsGO.d.ts +8 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +0 -0
- package/dist/load-from-file-FHW724YY.js +8 -0
- package/dist/load-from-file-S5CQ4H6T.js +8 -0
- package/dist/next/index.cjs +1165 -0
- package/dist/next/index.d.ts +33 -0
- package/dist/next/index.js +181 -0
- package/dist/node/loader.d.ts +5 -0
- package/dist/node/loader.js +41 -0
- package/dist/plugins/index-file.d.ts +14 -0
- package/dist/plugins/index-file.js +8 -0
- package/dist/plugins/json-schema.d.ts +31 -0
- package/dist/plugins/json-schema.js +80 -0
- package/dist/plugins/last-modified.d.ts +40 -0
- package/dist/plugins/last-modified.js +89 -0
- package/dist/runtime/browser.d.ts +53 -0
- package/dist/runtime/browser.js +67 -0
- package/dist/runtime/dynamic.d.ts +27 -0
- package/dist/runtime/dynamic.js +79 -0
- package/dist/runtime/server.d.ts +14 -0
- package/dist/runtime/server.js +8 -0
- package/dist/runtime/types.d.ts +61 -0
- package/dist/runtime/types.js +0 -0
- package/dist/vite/index.d.ts +44 -0
- package/dist/vite/index.js +122 -0
- package/dist/webpack/mdx.d.ts +6 -0
- package/dist/webpack/mdx.js +37 -0
- package/dist/webpack/meta.d.ts +6 -0
- package/dist/webpack/meta.js +40 -0
- package/loader-mdx.cjs +7 -0
- package/loader-meta.cjs +7 -0
- package/package.json +137 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fumaMatter
|
|
3
|
+
} from "./chunk-VWJKRQZR.js";
|
|
4
|
+
import {
|
|
5
|
+
createCodegen,
|
|
6
|
+
ident
|
|
7
|
+
} from "./chunk-PW2AZGGD.js";
|
|
8
|
+
|
|
9
|
+
// src/plugins/index-file.ts
|
|
10
|
+
import path2 from "path";
|
|
11
|
+
import { glob } from "tinyglobby";
|
|
12
|
+
|
|
13
|
+
// src/utils/fs-cache.ts
|
|
14
|
+
import fs from "fs/promises";
|
|
15
|
+
import path from "path";
|
|
16
|
+
var map = /* @__PURE__ */ new Map();
|
|
17
|
+
function createFSCache() {
|
|
18
|
+
return {
|
|
19
|
+
read(file) {
|
|
20
|
+
const fullPath = toFullPath(file);
|
|
21
|
+
const cached = map.get(fullPath);
|
|
22
|
+
if (cached) return cached;
|
|
23
|
+
const read = fs.readFile(fullPath).then((s) => s.toString());
|
|
24
|
+
map.set(fullPath, read);
|
|
25
|
+
return read;
|
|
26
|
+
},
|
|
27
|
+
delete(file) {
|
|
28
|
+
map.delete(toFullPath(file));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function toFullPath(file) {
|
|
33
|
+
if (path.isAbsolute(file)) {
|
|
34
|
+
return path.relative(process.cwd(), file);
|
|
35
|
+
}
|
|
36
|
+
return file;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/plugins/index-file.ts
|
|
40
|
+
import { createHash } from "crypto";
|
|
41
|
+
var indexFileCache = createFSCache();
|
|
42
|
+
function indexFile(options = {}) {
|
|
43
|
+
const {
|
|
44
|
+
target = "default",
|
|
45
|
+
addJsExtension,
|
|
46
|
+
browser = true,
|
|
47
|
+
dynamic = true
|
|
48
|
+
} = options;
|
|
49
|
+
let dynamicCollections;
|
|
50
|
+
function isDynamic(collection) {
|
|
51
|
+
return collection.type === "docs" && collection.docs.dynamic || collection.type === "doc" && collection.dynamic;
|
|
52
|
+
}
|
|
53
|
+
function generateConfigs(core) {
|
|
54
|
+
const serverOptions = {};
|
|
55
|
+
const typeConfigs = [
|
|
56
|
+
'import("@hanzo/docs-mdx/runtime/types").InternalTypeConfig'
|
|
57
|
+
];
|
|
58
|
+
const ctx = core.getPluginContext();
|
|
59
|
+
for (const plugin of core.getPlugins()) {
|
|
60
|
+
const indexFilePlugin = plugin["index-file"];
|
|
61
|
+
if (!indexFilePlugin) continue;
|
|
62
|
+
indexFilePlugin.serverOptions?.call(ctx, serverOptions);
|
|
63
|
+
const config = indexFilePlugin.generateTypeConfig?.call(ctx);
|
|
64
|
+
if (config) typeConfigs.push(config);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
serverOptions,
|
|
68
|
+
tc: typeConfigs.join(" & ")
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
name: "index-file",
|
|
73
|
+
config() {
|
|
74
|
+
dynamicCollections = this.core.getCollections().filter(isDynamic);
|
|
75
|
+
},
|
|
76
|
+
configureServer(server) {
|
|
77
|
+
if (!server.watcher) return;
|
|
78
|
+
server.watcher.on("all", async (event, file) => {
|
|
79
|
+
indexFileCache.delete(file);
|
|
80
|
+
if (dynamicCollections.length === 0) {
|
|
81
|
+
if (target === "vite") return;
|
|
82
|
+
if (target === "default" && event === "change") return;
|
|
83
|
+
}
|
|
84
|
+
const updatedCollection = this.core.getCollections().find((collection) => collection.hasFile(file));
|
|
85
|
+
if (!updatedCollection) return;
|
|
86
|
+
if (!isDynamic(updatedCollection)) {
|
|
87
|
+
if (target === "vite") return;
|
|
88
|
+
if (target === "default" && event === "change") return;
|
|
89
|
+
}
|
|
90
|
+
await this.core.emit({
|
|
91
|
+
filterPlugin: (plugin) => plugin.name === "index-file",
|
|
92
|
+
filterWorkspace: () => false,
|
|
93
|
+
write: true
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
async emit() {
|
|
98
|
+
const globCache = /* @__PURE__ */ new Map();
|
|
99
|
+
const { workspace, outDir } = this.core.getOptions();
|
|
100
|
+
const { serverOptions, tc } = generateConfigs(this.core);
|
|
101
|
+
const toEmitEntry = async (path3, content) => {
|
|
102
|
+
const codegen = createCodegen({
|
|
103
|
+
target,
|
|
104
|
+
outDir,
|
|
105
|
+
jsExtension: addJsExtension,
|
|
106
|
+
globCache
|
|
107
|
+
});
|
|
108
|
+
await content({
|
|
109
|
+
core: this.core,
|
|
110
|
+
codegen,
|
|
111
|
+
serverOptions,
|
|
112
|
+
tc,
|
|
113
|
+
workspace: workspace?.name
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
path: path3,
|
|
117
|
+
content: codegen.toString()
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
const out = [
|
|
121
|
+
toEmitEntry("server.ts", generateServerIndexFile)
|
|
122
|
+
];
|
|
123
|
+
if (dynamic)
|
|
124
|
+
out.push(toEmitEntry("dynamic.ts", generateDynamicIndexFile));
|
|
125
|
+
if (browser)
|
|
126
|
+
out.push(toEmitEntry("browser.ts", generateBrowserIndexFile));
|
|
127
|
+
return await Promise.all(out);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async function generateServerIndexFile(ctx) {
|
|
132
|
+
const { core, codegen, serverOptions, tc } = ctx;
|
|
133
|
+
codegen.lines.push(
|
|
134
|
+
`import { server } from '@hanzo/docs/mdx/runtime/server';`,
|
|
135
|
+
`import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
|
|
136
|
+
"",
|
|
137
|
+
`const create = server<typeof Config, ${tc}>(${JSON.stringify(serverOptions)});`
|
|
138
|
+
);
|
|
139
|
+
async function generateCollectionObject(collection) {
|
|
140
|
+
const base = getBase(collection);
|
|
141
|
+
switch (collection.type) {
|
|
142
|
+
case "docs": {
|
|
143
|
+
if (collection.docs.dynamic) return;
|
|
144
|
+
if (collection.docs.async) {
|
|
145
|
+
const [metaGlob2, headGlob, bodyGlob] = await Promise.all([
|
|
146
|
+
generateMetaCollectionGlob(ctx, collection.meta, true),
|
|
147
|
+
generateDocCollectionFrontmatterGlob(ctx, collection.docs, true),
|
|
148
|
+
generateDocCollectionGlob(ctx, collection.docs)
|
|
149
|
+
]);
|
|
150
|
+
return `await create.docsLazy("${collection.name}", "${base}", ${metaGlob2}, ${headGlob}, ${bodyGlob})`;
|
|
151
|
+
}
|
|
152
|
+
const [metaGlob, docGlob] = await Promise.all([
|
|
153
|
+
generateMetaCollectionGlob(ctx, collection.meta, true),
|
|
154
|
+
generateDocCollectionGlob(ctx, collection.docs, true)
|
|
155
|
+
]);
|
|
156
|
+
return `await create.docs("${collection.name}", "${base}", ${metaGlob}, ${docGlob})`;
|
|
157
|
+
}
|
|
158
|
+
case "doc":
|
|
159
|
+
if (collection.dynamic) return;
|
|
160
|
+
if (collection.async) {
|
|
161
|
+
const [headGlob, bodyGlob] = await Promise.all([
|
|
162
|
+
generateDocCollectionFrontmatterGlob(ctx, collection, true),
|
|
163
|
+
generateDocCollectionGlob(ctx, collection)
|
|
164
|
+
]);
|
|
165
|
+
return `await create.docLazy("${collection.name}", "${base}", ${headGlob}, ${bodyGlob})`;
|
|
166
|
+
}
|
|
167
|
+
return `await create.doc("${collection.name}", "${base}", ${await generateDocCollectionGlob(
|
|
168
|
+
ctx,
|
|
169
|
+
collection,
|
|
170
|
+
true
|
|
171
|
+
)})`;
|
|
172
|
+
case "meta":
|
|
173
|
+
return `await create.meta("${collection.name}", "${base}", ${await generateMetaCollectionGlob(
|
|
174
|
+
ctx,
|
|
175
|
+
collection,
|
|
176
|
+
true
|
|
177
|
+
)})`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
await codegen.pushAsync(
|
|
181
|
+
core.getCollections().map(async (collection) => {
|
|
182
|
+
const obj = await generateCollectionObject(collection);
|
|
183
|
+
if (!obj) return;
|
|
184
|
+
return `
|
|
185
|
+
export const ${collection.name} = ${obj};`;
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
async function generateDynamicIndexFile(ctx) {
|
|
190
|
+
const { core, codegen, serverOptions, tc } = ctx;
|
|
191
|
+
const { configPath, environment, outDir } = core.getOptions();
|
|
192
|
+
const partialOptions = {
|
|
193
|
+
configPath,
|
|
194
|
+
environment,
|
|
195
|
+
outDir
|
|
196
|
+
};
|
|
197
|
+
codegen.lines.push(
|
|
198
|
+
`import { dynamic } from '@hanzo/docs/mdx/runtime/dynamic';`,
|
|
199
|
+
`import * as Config from '${codegen.formatImportPath(configPath)}';`,
|
|
200
|
+
"",
|
|
201
|
+
`const create = await dynamic<typeof Config, ${tc}>(Config, ${JSON.stringify(partialOptions)}, ${JSON.stringify(serverOptions)});`
|
|
202
|
+
);
|
|
203
|
+
async function generateCollectionObjectEntry(collection, absolutePath) {
|
|
204
|
+
const fullPath = path2.relative(process.cwd(), absolutePath);
|
|
205
|
+
const content = await indexFileCache.read(fullPath).catch(() => "");
|
|
206
|
+
const parsed = fumaMatter(content);
|
|
207
|
+
const data = await core.transformFrontmatter(
|
|
208
|
+
{
|
|
209
|
+
collection,
|
|
210
|
+
filePath: fullPath,
|
|
211
|
+
source: content
|
|
212
|
+
},
|
|
213
|
+
parsed.data
|
|
214
|
+
);
|
|
215
|
+
const hash = createHash("md5").update(content).digest("hex");
|
|
216
|
+
const infoStr = [
|
|
217
|
+
// make sure it's included in vercel/nft
|
|
218
|
+
`absolutePath: path.resolve(${JSON.stringify(fullPath)})`
|
|
219
|
+
];
|
|
220
|
+
for (const [k, v] of Object.entries({
|
|
221
|
+
info: {
|
|
222
|
+
fullPath,
|
|
223
|
+
path: path2.relative(collection.dir, absolutePath)
|
|
224
|
+
},
|
|
225
|
+
data,
|
|
226
|
+
hash
|
|
227
|
+
})) {
|
|
228
|
+
infoStr.push(`${k}: ${JSON.stringify(v)}`);
|
|
229
|
+
}
|
|
230
|
+
return `{ ${infoStr.join(", ")} }`;
|
|
231
|
+
}
|
|
232
|
+
async function generateCollectionObject(parent) {
|
|
233
|
+
let collection;
|
|
234
|
+
if (parent.type === "doc") collection = parent;
|
|
235
|
+
else if (parent.type === "docs") collection = parent.docs;
|
|
236
|
+
if (!collection || !collection.dynamic) return;
|
|
237
|
+
const files = await glob(collection.patterns, {
|
|
238
|
+
cwd: collection.dir,
|
|
239
|
+
absolute: true
|
|
240
|
+
});
|
|
241
|
+
const entries = await Promise.all(
|
|
242
|
+
files.map((file) => generateCollectionObjectEntry(collection, file))
|
|
243
|
+
);
|
|
244
|
+
switch (parent.type) {
|
|
245
|
+
case "docs": {
|
|
246
|
+
const metaGlob = await generateMetaCollectionGlob(
|
|
247
|
+
ctx,
|
|
248
|
+
parent.meta,
|
|
249
|
+
true
|
|
250
|
+
);
|
|
251
|
+
return `await create.docs("${parent.name}", "${getBase(parent)}", ${metaGlob}, ${entries.join(", ")})`;
|
|
252
|
+
}
|
|
253
|
+
case "doc":
|
|
254
|
+
return `await create.doc("${collection.name}", "${getBase(collection)}", ${entries.join(", ")})`;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
await codegen.pushAsync(
|
|
258
|
+
core.getCollections().map(async (collection) => {
|
|
259
|
+
const obj = await generateCollectionObject(collection);
|
|
260
|
+
if (!obj) return;
|
|
261
|
+
return `
|
|
262
|
+
export const ${collection.name} = ${obj};`;
|
|
263
|
+
})
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
async function generateBrowserIndexFile(ctx) {
|
|
267
|
+
const { core, codegen, tc } = ctx;
|
|
268
|
+
codegen.lines.push(
|
|
269
|
+
`import { browser } from '@hanzo/docs/mdx/runtime/browser';`,
|
|
270
|
+
`import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
|
|
271
|
+
"",
|
|
272
|
+
`const create = browser<typeof Config, ${tc}>();`
|
|
273
|
+
);
|
|
274
|
+
async function generateCollectionObject(collection) {
|
|
275
|
+
switch (collection.type) {
|
|
276
|
+
case "docs": {
|
|
277
|
+
if (collection.docs.dynamic) return;
|
|
278
|
+
return generateCollectionObject(collection.docs);
|
|
279
|
+
}
|
|
280
|
+
case "doc":
|
|
281
|
+
if (collection.dynamic) return;
|
|
282
|
+
return `create.doc("${collection.name}", ${await generateDocCollectionGlob(ctx, collection)})`;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
codegen.lines.push("const browserCollections = {");
|
|
286
|
+
await codegen.pushAsync(
|
|
287
|
+
core.getCollections().map(async (collection) => {
|
|
288
|
+
const obj = await generateCollectionObject(collection);
|
|
289
|
+
if (!obj) return;
|
|
290
|
+
return ident(`${collection.name}: ${obj},`);
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
codegen.lines.push("};", "export default browserCollections;");
|
|
294
|
+
}
|
|
295
|
+
function getBase(collection) {
|
|
296
|
+
return path2.relative(process.cwd(), collection.dir);
|
|
297
|
+
}
|
|
298
|
+
function generateDocCollectionFrontmatterGlob({ codegen, workspace }, collection, eager = false) {
|
|
299
|
+
return codegen.generateGlobImport(collection.patterns, {
|
|
300
|
+
query: {
|
|
301
|
+
collection: collection.name,
|
|
302
|
+
only: "frontmatter",
|
|
303
|
+
workspace
|
|
304
|
+
},
|
|
305
|
+
import: "frontmatter",
|
|
306
|
+
base: collection.dir,
|
|
307
|
+
eager
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function generateDocCollectionGlob({ codegen, workspace }, collection, eager = false) {
|
|
311
|
+
return codegen.generateGlobImport(collection.patterns, {
|
|
312
|
+
query: {
|
|
313
|
+
collection: collection.name,
|
|
314
|
+
workspace
|
|
315
|
+
},
|
|
316
|
+
base: collection.dir,
|
|
317
|
+
eager
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
function generateMetaCollectionGlob({ codegen, workspace }, collection, eager = false) {
|
|
321
|
+
return codegen.generateGlobImport(collection.patterns, {
|
|
322
|
+
query: {
|
|
323
|
+
collection: collection.name,
|
|
324
|
+
workspace
|
|
325
|
+
},
|
|
326
|
+
import: "default",
|
|
327
|
+
base: collection.dir,
|
|
328
|
+
eager
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export {
|
|
333
|
+
indexFile
|
|
334
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fumaMatter
|
|
3
|
+
} from "./chunk-VWJKRQZR.js";
|
|
4
|
+
|
|
5
|
+
// src/loaders/mdx/remark-include.ts
|
|
6
|
+
import { unified } from "unified";
|
|
7
|
+
import { visit as visit2 } from "unist-util-visit";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as fs from "fs/promises";
|
|
10
|
+
import { remarkHeading } from "fumadocs-core/mdx-plugins";
|
|
11
|
+
import { VFile } from "vfile";
|
|
12
|
+
|
|
13
|
+
// src/loaders/mdx/remark-unravel.ts
|
|
14
|
+
import { visit } from "unist-util-visit";
|
|
15
|
+
function remarkMarkAndUnravel() {
|
|
16
|
+
return (tree) => {
|
|
17
|
+
visit(tree, function(node, index, parent) {
|
|
18
|
+
let offset = -1;
|
|
19
|
+
let all = true;
|
|
20
|
+
let oneOrMore = false;
|
|
21
|
+
if (parent && typeof index === "number" && node.type === "paragraph") {
|
|
22
|
+
const children = node.children;
|
|
23
|
+
while (++offset < children.length) {
|
|
24
|
+
const child = children[offset];
|
|
25
|
+
if (child.type === "mdxJsxTextElement" || child.type === "mdxTextExpression") {
|
|
26
|
+
oneOrMore = true;
|
|
27
|
+
} else if (child.type === "text" && child.value.trim().length === 0) {
|
|
28
|
+
} else {
|
|
29
|
+
all = false;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (all && oneOrMore) {
|
|
34
|
+
offset = -1;
|
|
35
|
+
const newChildren = [];
|
|
36
|
+
while (++offset < children.length) {
|
|
37
|
+
const child = children[offset];
|
|
38
|
+
if (child.type === "mdxJsxTextElement") {
|
|
39
|
+
child.type = "mdxJsxFlowElement";
|
|
40
|
+
}
|
|
41
|
+
if (child.type === "mdxTextExpression") {
|
|
42
|
+
child.type = "mdxFlowExpression";
|
|
43
|
+
}
|
|
44
|
+
if (child.type === "text" && /^[\t\r\n ]+$/.test(String(child.value))) {
|
|
45
|
+
} else {
|
|
46
|
+
newChildren.push(child);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
parent.children.splice(index, 1, ...newChildren);
|
|
50
|
+
return index;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/loaders/mdx/mdast-utils.ts
|
|
58
|
+
function flattenNode(node) {
|
|
59
|
+
if ("children" in node)
|
|
60
|
+
return node.children.map((child) => flattenNode(child)).join("");
|
|
61
|
+
if ("value" in node) return node.value;
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/loaders/mdx/remark-include.ts
|
|
66
|
+
var ElementLikeTypes = [
|
|
67
|
+
"mdxJsxFlowElement",
|
|
68
|
+
"mdxJsxTextElement",
|
|
69
|
+
"containerDirective",
|
|
70
|
+
"textDirective",
|
|
71
|
+
"leafDirective"
|
|
72
|
+
];
|
|
73
|
+
function isElementLike(node) {
|
|
74
|
+
return ElementLikeTypes.includes(node.type);
|
|
75
|
+
}
|
|
76
|
+
function parseElementAttributes(element) {
|
|
77
|
+
if (Array.isArray(element.attributes)) {
|
|
78
|
+
const attributes = {};
|
|
79
|
+
for (const attr of element.attributes) {
|
|
80
|
+
if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
|
|
81
|
+
attributes[attr.name] = attr.value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return attributes;
|
|
85
|
+
}
|
|
86
|
+
return element.attributes ?? {};
|
|
87
|
+
}
|
|
88
|
+
function parseSpecifier(specifier) {
|
|
89
|
+
const idx = specifier.lastIndexOf("#");
|
|
90
|
+
if (idx === -1) return { file: specifier };
|
|
91
|
+
return {
|
|
92
|
+
file: specifier.slice(0, idx),
|
|
93
|
+
section: specifier.slice(idx + 1)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function extractSection(root, section) {
|
|
97
|
+
let nodes;
|
|
98
|
+
let capturingHeadingContent = false;
|
|
99
|
+
visit2(root, (node) => {
|
|
100
|
+
if (node.type === "heading") {
|
|
101
|
+
if (capturingHeadingContent) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (node.data?.hProperties?.id === section) {
|
|
105
|
+
capturingHeadingContent = true;
|
|
106
|
+
nodes = [node];
|
|
107
|
+
return "skip";
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (capturingHeadingContent) {
|
|
112
|
+
nodes?.push(node);
|
|
113
|
+
return "skip";
|
|
114
|
+
}
|
|
115
|
+
if (isElementLike(node) && node.name === "section") {
|
|
116
|
+
const attributes = parseElementAttributes(node);
|
|
117
|
+
if (attributes.id === section) {
|
|
118
|
+
nodes = node.children;
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
if (nodes)
|
|
124
|
+
return {
|
|
125
|
+
type: "root",
|
|
126
|
+
children: nodes
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function remarkInclude() {
|
|
130
|
+
const TagName = "include";
|
|
131
|
+
const embedContent = async (targetPath, heading, params, parent) => {
|
|
132
|
+
const { _getProcessor = () => this, _compiler } = parent.data;
|
|
133
|
+
let content;
|
|
134
|
+
try {
|
|
135
|
+
content = (await fs.readFile(targetPath)).toString();
|
|
136
|
+
} catch (e) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`failed to read file ${targetPath}
|
|
139
|
+
${e instanceof Error ? e.message : String(e)}`,
|
|
140
|
+
{ cause: e }
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const ext = path.extname(targetPath);
|
|
144
|
+
_compiler?.addDependency(targetPath);
|
|
145
|
+
if (params.lang || ext !== ".md" && ext !== ".mdx") {
|
|
146
|
+
const lang = params.lang ?? ext.slice(1);
|
|
147
|
+
return {
|
|
148
|
+
type: "code",
|
|
149
|
+
lang,
|
|
150
|
+
meta: params.meta,
|
|
151
|
+
value: content,
|
|
152
|
+
data: {}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const parser = _getProcessor(ext === ".mdx" ? "mdx" : "md");
|
|
156
|
+
const parsed = fumaMatter(content);
|
|
157
|
+
const targetFile = new VFile({
|
|
158
|
+
path: targetPath,
|
|
159
|
+
value: parsed.content,
|
|
160
|
+
data: {
|
|
161
|
+
...parent.data,
|
|
162
|
+
frontmatter: parsed.data
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
let mdast = parser.parse(targetFile);
|
|
166
|
+
const baseProcessor = unified().use(remarkMarkAndUnravel);
|
|
167
|
+
if (heading) {
|
|
168
|
+
const extracted = extractSection(
|
|
169
|
+
await baseProcessor.use(remarkHeading).run(mdast),
|
|
170
|
+
heading
|
|
171
|
+
);
|
|
172
|
+
if (!extracted)
|
|
173
|
+
throw new Error(
|
|
174
|
+
`Cannot find section ${heading} in ${targetPath}, make sure you have encapsulated the section in a <section id="${heading}"> tag, or a :::section directive with remark-directive configured.`
|
|
175
|
+
);
|
|
176
|
+
mdast = extracted;
|
|
177
|
+
} else {
|
|
178
|
+
mdast = await baseProcessor.run(mdast);
|
|
179
|
+
}
|
|
180
|
+
await update(mdast, targetFile);
|
|
181
|
+
return mdast;
|
|
182
|
+
};
|
|
183
|
+
async function update(tree, file) {
|
|
184
|
+
const queue = [];
|
|
185
|
+
visit2(tree, ElementLikeTypes, (_node, _, parent) => {
|
|
186
|
+
const node = _node;
|
|
187
|
+
if (node.name !== TagName) return;
|
|
188
|
+
const specifier = flattenNode(node);
|
|
189
|
+
if (specifier.length === 0) return "skip";
|
|
190
|
+
const attributes = parseElementAttributes(node);
|
|
191
|
+
const { file: relativePath, section } = parseSpecifier(specifier);
|
|
192
|
+
const targetPath = path.resolve(
|
|
193
|
+
"cwd" in attributes ? file.cwd : file.dirname,
|
|
194
|
+
relativePath
|
|
195
|
+
);
|
|
196
|
+
queue.push(
|
|
197
|
+
embedContent(targetPath, section, attributes, file).then((replace) => {
|
|
198
|
+
Object.assign(
|
|
199
|
+
parent && parent.type === "paragraph" ? parent : node,
|
|
200
|
+
replace
|
|
201
|
+
);
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
return "skip";
|
|
205
|
+
});
|
|
206
|
+
await Promise.all(queue);
|
|
207
|
+
}
|
|
208
|
+
return async (tree, file) => {
|
|
209
|
+
await update(tree, file);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export {
|
|
214
|
+
flattenNode,
|
|
215
|
+
remarkInclude
|
|
216
|
+
};
|