fumadocs-core 16.17.1 → 16.17.3
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.
|
@@ -11,12 +11,10 @@ import { cache } from "react";
|
|
|
11
11
|
*/
|
|
12
12
|
var FileSystem = class {
|
|
13
13
|
constructor(inherit) {
|
|
14
|
-
this.files = /* @__PURE__ */ new Map();
|
|
15
14
|
this.folders = /* @__PURE__ */ new Map();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} else this.folders.set("", []);
|
|
15
|
+
this.files = new Map(inherit?.files);
|
|
16
|
+
if (inherit) for (const [k, v] of inherit.folders) this.folders.set(k, [...v]);
|
|
17
|
+
else this.folders.set("", []);
|
|
20
18
|
}
|
|
21
19
|
read(path) {
|
|
22
20
|
return this.files.get(path);
|
|
@@ -56,6 +54,7 @@ var FileSystem = class {
|
|
|
56
54
|
return Array.from(this.files.keys());
|
|
57
55
|
}
|
|
58
56
|
makeDir(path) {
|
|
57
|
+
if (this.folders.has(path)) return;
|
|
59
58
|
const cur = [];
|
|
60
59
|
let parentPath = "";
|
|
61
60
|
for (const seg of path.split("/")) {
|
|
@@ -129,29 +128,26 @@ const EmptyLang = Symbol();
|
|
|
129
128
|
*/
|
|
130
129
|
function createContentStorageBuilder(loaderConfig) {
|
|
131
130
|
const { input, plugins, i18n } = loaderConfig;
|
|
132
|
-
let parser;
|
|
133
|
-
if (
|
|
134
|
-
else if (i18n.parser === "dir") {
|
|
131
|
+
let parser = (path) => [path];
|
|
132
|
+
if (i18n) {
|
|
135
133
|
const langSet = new Set(i18n.languages);
|
|
136
134
|
parser = (path) => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (langSet.has(locale)) return [segs.join("/"), locale];
|
|
154
|
-
if (locale === "$") return [segs.join("/"), i18n.languages];
|
|
135
|
+
let locale;
|
|
136
|
+
let rest;
|
|
137
|
+
if (i18n.parser === "dir") {
|
|
138
|
+
const slash = path.indexOf("/");
|
|
139
|
+
if (slash <= 0) return [path];
|
|
140
|
+
locale = path.slice(0, slash);
|
|
141
|
+
rest = path.slice(slash + 1);
|
|
142
|
+
} else {
|
|
143
|
+
const ext = path.lastIndexOf(".");
|
|
144
|
+
const dot = path.lastIndexOf(".", ext - 1);
|
|
145
|
+
if (dot === -1 || dot < path.lastIndexOf("/")) return [path];
|
|
146
|
+
locale = path.slice(dot + 1, ext);
|
|
147
|
+
rest = path.slice(0, dot) + path.slice(ext);
|
|
148
|
+
}
|
|
149
|
+
if (langSet.has(locale)) return [rest, locale];
|
|
150
|
+
if (locale === "$") return [rest, i18n.languages];
|
|
155
151
|
return [path];
|
|
156
152
|
};
|
|
157
153
|
}
|
|
@@ -216,371 +212,266 @@ function pushMapList(map, k, v) {
|
|
|
216
212
|
list.push(v);
|
|
217
213
|
}
|
|
218
214
|
//#endregion
|
|
219
|
-
//#region src/source/page-tree/transformer-fallback.ts
|
|
220
|
-
function transformerFallback() {
|
|
221
|
-
const addedFiles = /* @__PURE__ */ new Set();
|
|
222
|
-
function shouldIgnore(context) {
|
|
223
|
-
return context.custom?._fallback === true;
|
|
224
|
-
}
|
|
225
|
-
return {
|
|
226
|
-
root(root) {
|
|
227
|
-
if (shouldIgnore(this)) return root;
|
|
228
|
-
const isolatedStorage = new FileSystem();
|
|
229
|
-
if (addedFiles.size === this.storage.files.size) return root;
|
|
230
|
-
for (const file of this.storage.getFiles()) {
|
|
231
|
-
if (addedFiles.has(file)) continue;
|
|
232
|
-
isolatedStorage.write(file, this.storage.read(file));
|
|
233
|
-
}
|
|
234
|
-
root.fallback = createPageTreeBuilder(isolatedStorage, {
|
|
235
|
-
...this.options,
|
|
236
|
-
idPrefix: this.options.idPrefix ? `fallback:${this.options.idPrefix}` : "fallback",
|
|
237
|
-
generateFallback: false,
|
|
238
|
-
context: {
|
|
239
|
-
...this.custom,
|
|
240
|
-
_fallback: true
|
|
241
|
-
}
|
|
242
|
-
}).root();
|
|
243
|
-
addedFiles.clear();
|
|
244
|
-
return root;
|
|
245
|
-
},
|
|
246
|
-
file(node, file) {
|
|
247
|
-
if (shouldIgnore(this)) return node;
|
|
248
|
-
if (file) addedFiles.add(file);
|
|
249
|
-
return node;
|
|
250
|
-
},
|
|
251
|
-
folder(node, _dir, metaPath) {
|
|
252
|
-
if (shouldIgnore(this)) return node;
|
|
253
|
-
if (metaPath) addedFiles.add(metaPath);
|
|
254
|
-
return node;
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
//#endregion
|
|
259
215
|
//#region src/source/page-tree/builder.ts
|
|
260
216
|
const group = /^\((?<name>.+)\)$/;
|
|
261
217
|
const link = /^(?<external>external:)?(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
|
|
262
218
|
const separator = /^---(?:\[(?<icon>[^\]]+)])?(?<name>.+)---|^---$/;
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
return builder;
|
|
286
|
-
},
|
|
287
|
-
storage: storages[locale],
|
|
288
|
-
storages,
|
|
289
|
-
locale,
|
|
290
|
-
transformers,
|
|
291
|
-
custom: options.context,
|
|
292
|
-
options
|
|
293
|
-
};
|
|
294
|
-
} else ctx = {
|
|
295
|
-
get builder() {
|
|
296
|
-
return builder;
|
|
297
|
-
},
|
|
298
|
-
storage: input,
|
|
219
|
+
function createPageTreeBuilder(storage, options, locale, storages) {
|
|
220
|
+
const { idPrefix, transformers = [], sort = {} } = options;
|
|
221
|
+
const byName = sort.by === "name";
|
|
222
|
+
const compare = sort.locales || sort.options ? new Intl.Collator(sort.locales, sort.options).compare : (a, b) => a.localeCompare(b);
|
|
223
|
+
/** file or folder path -> entry */
|
|
224
|
+
const entries = /* @__PURE__ */ new Map();
|
|
225
|
+
const entryOf = /* @__PURE__ */ new Map();
|
|
226
|
+
const metaPaths = /* @__PURE__ */ new Set();
|
|
227
|
+
/** format -> file path without extension -> file path */
|
|
228
|
+
const flattenPaths = /* @__PURE__ */ new Map();
|
|
229
|
+
let nextId = 0;
|
|
230
|
+
let usedPages = 0;
|
|
231
|
+
for (const [path, file] of storage.files) {
|
|
232
|
+
let paths = flattenPaths.get(file.format);
|
|
233
|
+
if (!paths) flattenPaths.set(file.format, paths = /* @__PURE__ */ new Map());
|
|
234
|
+
paths.set(path.slice(0, path.length - extname(path).length), path);
|
|
235
|
+
}
|
|
236
|
+
const builder = {
|
|
237
|
+
resolveFlattenPath,
|
|
238
|
+
root
|
|
239
|
+
};
|
|
240
|
+
const ctx = {
|
|
299
241
|
transformers,
|
|
242
|
+
builder,
|
|
243
|
+
storage,
|
|
244
|
+
storages,
|
|
245
|
+
locale,
|
|
300
246
|
custom: options.context,
|
|
301
247
|
options
|
|
302
248
|
};
|
|
303
|
-
const { storage, locale } = ctx;
|
|
304
|
-
for (const file of storage.getFiles()) {
|
|
305
|
-
const content = storage.read(file);
|
|
306
|
-
const flattenPath = file.substring(0, file.length - extname(file).length);
|
|
307
|
-
flattenPathToFullPath.set(flattenPath + "." + content.format, file);
|
|
308
|
-
}
|
|
309
249
|
function resolveFlattenPath(name, format) {
|
|
310
|
-
return
|
|
250
|
+
return flattenPaths.get(format)?.get(name) ?? name;
|
|
251
|
+
}
|
|
252
|
+
function createId(localId = `_${nextId++}`) {
|
|
253
|
+
if (locale) localId = `${locale}:${localId}`;
|
|
254
|
+
return idPrefix ? `${idPrefix}:${localId}` : localId;
|
|
311
255
|
}
|
|
312
256
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* when a node is referenced by multiple folders, this determines which folder they should belong to.
|
|
316
|
-
*
|
|
317
|
-
* @returns whether the owner owns the node.
|
|
257
|
+
* claim a node for `folder`, a node referenced by multiple folders belongs to the highest priority:
|
|
258
|
+
* `pagesIndex` (3) > path & extract (2) > rest & default index (0), the first one wins a tie.
|
|
318
259
|
*/
|
|
319
|
-
function own(
|
|
320
|
-
if (
|
|
321
|
-
const
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
priority
|
|
326
|
-
};
|
|
327
|
-
return true;
|
|
328
|
-
}
|
|
329
|
-
if (existing.owner === ownerPath) {
|
|
330
|
-
existing.priority = Math.max(existing.priority, priority);
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
if (existing.priority >= priority) return false;
|
|
334
|
-
const folder = pathToNode.get(existing.owner);
|
|
335
|
-
if (folder && folder.type === "folder") {
|
|
336
|
-
if (folder.index === node) delete folder.index;
|
|
260
|
+
function own(folder, entry, priority) {
|
|
261
|
+
if (!entry.done) return false;
|
|
262
|
+
const prev = entry.owner;
|
|
263
|
+
if (prev && prev !== folder) {
|
|
264
|
+
if (entry.priority >= priority) return false;
|
|
265
|
+
if (prev.node.index === entry.node) delete prev.node.index;
|
|
337
266
|
else {
|
|
338
|
-
const idx =
|
|
339
|
-
if (idx !== -1)
|
|
267
|
+
const idx = prev.node.children.indexOf(entry.node);
|
|
268
|
+
if (idx !== -1) prev.node.children.splice(idx, 1);
|
|
340
269
|
}
|
|
341
270
|
}
|
|
342
|
-
|
|
343
|
-
|
|
271
|
+
entry.owner = folder;
|
|
272
|
+
entry.priority = Math.max(entry.priority, priority);
|
|
344
273
|
return true;
|
|
345
274
|
}
|
|
346
|
-
function
|
|
347
|
-
const
|
|
348
|
-
if (
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (locale) id = `${locale}:${id}`;
|
|
353
|
-
if (idPrefix) id = `${idPrefix}:${id}`;
|
|
354
|
-
return id;
|
|
355
|
-
}
|
|
356
|
-
function buildPaths(paths, filter, reversed = false) {
|
|
357
|
-
const nodes = [];
|
|
358
|
-
let indexNode;
|
|
359
|
-
for (const path of paths) {
|
|
360
|
-
if (filter && !filter(path)) continue;
|
|
361
|
-
const fileNode = buildFile(path);
|
|
362
|
-
if (fileNode) {
|
|
363
|
-
nodes.push(fileNode);
|
|
364
|
-
if (!indexNode && basename(path, extname(path)) === "index") indexNode = fileNode;
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
const dirNode = buildFolder(path);
|
|
368
|
-
if (dirNode) nodes.push(dirNode);
|
|
369
|
-
}
|
|
370
|
-
const factor = reversed ? -1 : 1;
|
|
371
|
-
const useName = sortBy === "name";
|
|
372
|
-
return nodes.sort((a, b) => {
|
|
373
|
-
if (a === indexNode) return -100;
|
|
374
|
-
if (b === indexNode) return 100;
|
|
375
|
-
const aT = useName && a[SymbolName] || (a.type === "folder" ? a.$ref.folder : a.$ref);
|
|
376
|
-
const bT = useName && b[SymbolName] || (b.type === "folder" ? b.$ref.folder : b.$ref);
|
|
377
|
-
const aK = a.type === "folder" ? 10 : 0;
|
|
378
|
-
const bK = b.type === "folder" ? 10 : 0;
|
|
379
|
-
return factor * (aT.localeCompare(bT, sortLocales, sortOptions) + (aK - bK));
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
function resolveLink(item) {
|
|
383
|
-
const match = link.exec(item);
|
|
384
|
-
if (!match?.groups) return;
|
|
385
|
-
const { icon, url, name, external } = match.groups;
|
|
275
|
+
function buildFile(path) {
|
|
276
|
+
const cached = entries.get(path);
|
|
277
|
+
if (cached) return cached;
|
|
278
|
+
const file = storage.read(path);
|
|
279
|
+
if (file?.format !== "page") return;
|
|
280
|
+
const { title, description, icon } = file.data;
|
|
386
281
|
let node = {
|
|
387
|
-
$id:
|
|
282
|
+
$id: createId(path),
|
|
388
283
|
type: "page",
|
|
284
|
+
name: title ?? pathToName(basename(path, extname(path))),
|
|
285
|
+
description,
|
|
389
286
|
icon,
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
external: external ? true : void 0
|
|
287
|
+
url: options.url(file.slugs, locale),
|
|
288
|
+
$ref: path
|
|
393
289
|
};
|
|
394
|
-
for (const
|
|
395
|
-
|
|
396
|
-
node
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const match = separator.exec(item);
|
|
402
|
-
if (!match?.groups) return;
|
|
403
|
-
let node = {
|
|
404
|
-
$id: generateId(),
|
|
405
|
-
type: "separator",
|
|
406
|
-
icon: match.groups.icon,
|
|
407
|
-
name: match.groups.name
|
|
290
|
+
for (const t of transformers) if (t.file) node = t.file.call(ctx, node, path);
|
|
291
|
+
const entry = {
|
|
292
|
+
node,
|
|
293
|
+
path,
|
|
294
|
+
title,
|
|
295
|
+
priority: 0,
|
|
296
|
+
done: true
|
|
408
297
|
};
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
return node;
|
|
298
|
+
entries.set(path, entry);
|
|
299
|
+
entryOf.set(node, entry);
|
|
300
|
+
usedPages++;
|
|
301
|
+
return entry;
|
|
414
302
|
}
|
|
415
|
-
function
|
|
416
|
-
|
|
417
|
-
outputArray.push(item);
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
const separator = resolveSeparator(item);
|
|
421
|
-
if (separator) {
|
|
422
|
-
outputArray.push(separator);
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
const link = resolveLink(item);
|
|
426
|
-
if (link) {
|
|
427
|
-
outputArray.push(link);
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (item.startsWith(excludePrefix)) {
|
|
431
|
-
const path = joinPath(folderPath, item.slice(1));
|
|
432
|
-
excludedPaths.add(path);
|
|
433
|
-
excludedPaths.add(resolveFlattenPath(path, "page"));
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
if (item.startsWith(extractPrefix)) {
|
|
437
|
-
const path = joinPath(folderPath, item.slice(3));
|
|
438
|
-
const node = buildFolder(path);
|
|
439
|
-
if (!node) return;
|
|
440
|
-
const children = node.index ? [node.index, ...node.children] : node.children;
|
|
441
|
-
if (own(folderPath, node, 2)) {
|
|
442
|
-
for (const child of children) {
|
|
443
|
-
transferOwner(folderPath, child);
|
|
444
|
-
outputArray.push(child);
|
|
445
|
-
}
|
|
446
|
-
excludedPaths.add(path);
|
|
447
|
-
} else for (const child of children) if (own(folderPath, child, 2)) outputArray.push(child);
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
let path = joinPath(folderPath, item);
|
|
451
|
-
let node = buildFolder(path);
|
|
452
|
-
if (!node) {
|
|
453
|
-
path = resolveFlattenPath(path, "page");
|
|
454
|
-
node = buildFile(path);
|
|
455
|
-
}
|
|
456
|
-
if (!node || !own(folderPath, node, 2)) return;
|
|
457
|
-
outputArray.push(node);
|
|
458
|
-
excludedPaths.add(path);
|
|
459
|
-
}
|
|
460
|
-
function buildFolder(folderPath, isGlobalRoot = false) {
|
|
461
|
-
const cached = pathToNode.get(folderPath);
|
|
303
|
+
function buildFolder(path, isGlobalRoot = false) {
|
|
304
|
+
const cached = entries.get(path);
|
|
462
305
|
if (cached) return cached;
|
|
463
|
-
const files = storage.readDir(
|
|
306
|
+
const files = storage.readDir(path);
|
|
464
307
|
if (!files) return;
|
|
465
|
-
let metaPath = resolveFlattenPath(joinPath(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
const
|
|
473
|
-
let node = {
|
|
308
|
+
let metaPath = resolveFlattenPath(joinPath(path, "meta"), "meta");
|
|
309
|
+
const metaFile = storage.read(metaPath);
|
|
310
|
+
let meta = {};
|
|
311
|
+
if (metaFile?.format === "meta") {
|
|
312
|
+
meta = metaFile.data;
|
|
313
|
+
metaPaths.add(metaPath);
|
|
314
|
+
} else metaPath = void 0;
|
|
315
|
+
const node = {
|
|
474
316
|
type: "folder",
|
|
475
317
|
name: null,
|
|
476
|
-
root:
|
|
477
|
-
defaultOpen:
|
|
478
|
-
description:
|
|
479
|
-
collapsible:
|
|
318
|
+
root: meta.root,
|
|
319
|
+
defaultOpen: meta.defaultOpen,
|
|
320
|
+
description: meta.description,
|
|
321
|
+
collapsible: meta.collapsible,
|
|
480
322
|
children: [],
|
|
481
|
-
$id:
|
|
323
|
+
$id: createId(path),
|
|
482
324
|
$ref: {
|
|
483
|
-
folder:
|
|
325
|
+
folder: path,
|
|
484
326
|
meta: metaPath
|
|
485
|
-
}
|
|
486
|
-
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const self = {
|
|
330
|
+
node,
|
|
331
|
+
path,
|
|
332
|
+
priority: 0,
|
|
333
|
+
done: false
|
|
487
334
|
};
|
|
488
|
-
|
|
335
|
+
entries.set(path, self);
|
|
336
|
+
const indexName = meta.pagesIndex || (meta.root ?? isGlobalRoot ? void 0 : "index");
|
|
337
|
+
const indexPage = indexName && buildFile(resolveFlattenPath(joinPath(path, indexName), "page"));
|
|
489
338
|
let indexPath;
|
|
490
|
-
if (
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
if (page && own(folderPath, page, 0)) {
|
|
501
|
-
indexPath = defaultPath;
|
|
502
|
-
node.index = page;
|
|
339
|
+
if (indexPage && own(self, indexPage, meta.pagesIndex ? 3 : 0)) {
|
|
340
|
+
node.index = indexPage.node;
|
|
341
|
+
indexPath = indexPage.path;
|
|
342
|
+
} else if (meta.pagesIndex) node.index = resolveLink(meta.pagesIndex);
|
|
343
|
+
const items = [];
|
|
344
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
345
|
+
for (const item of meta.pages ?? ["..."]) {
|
|
346
|
+
if (item === "..." || item === "z...a") {
|
|
347
|
+
items.push(item);
|
|
348
|
+
continue;
|
|
503
349
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
for (const item of metadata.pages) resolveFolderItem(folderPath, item, outputArray, excludedPaths);
|
|
509
|
-
if (indexPath) {
|
|
510
|
-
if (excludedPaths.has(indexPath)) delete node.index;
|
|
511
|
-
else excludedPaths.add(indexPath);
|
|
350
|
+
const inline = resolveSeparator(item) ?? resolveLink(item);
|
|
351
|
+
if (inline) {
|
|
352
|
+
items.push(inline);
|
|
353
|
+
continue;
|
|
512
354
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
355
|
+
if (item.startsWith("!")) {
|
|
356
|
+
const target = joinPath(path, item.slice(1));
|
|
357
|
+
excluded.add(target).add(resolveFlattenPath(target, "page"));
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (item.startsWith("...")) {
|
|
361
|
+
const folder = buildFolder(joinPath(path, item.slice(3)));
|
|
362
|
+
if (!folder) continue;
|
|
363
|
+
const { index, children } = folder.node;
|
|
364
|
+
const owned = own(self, folder, 2);
|
|
365
|
+
if (owned) excluded.add(folder.path);
|
|
366
|
+
for (const child of index ? [index, ...children] : children) {
|
|
367
|
+
const entry = entryOf.get(child);
|
|
368
|
+
if (entry && owned) entry.owner = self;
|
|
369
|
+
else if (entry && !own(self, entry, 2)) continue;
|
|
370
|
+
items.push(child);
|
|
517
371
|
}
|
|
518
|
-
|
|
519
|
-
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
const target = joinPath(path, item);
|
|
375
|
+
const entry = buildFolder(target) ?? buildFile(resolveFlattenPath(target, "page"));
|
|
376
|
+
if (entry && own(self, entry, 2)) {
|
|
377
|
+
items.push(entry.node);
|
|
378
|
+
excluded.add(entry.path);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (indexPath) {
|
|
382
|
+
if (excluded.has(indexPath)) delete node.index;
|
|
383
|
+
else excluded.add(indexPath);
|
|
384
|
+
}
|
|
385
|
+
for (const item of items) {
|
|
386
|
+
if (item === "..." || item === "z...a") {
|
|
387
|
+
for (const entry of buildRest(files, excluded, item === "z...a")) if (own(self, entry, 0)) node.children.push(entry.node);
|
|
388
|
+
continue;
|
|
520
389
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
node
|
|
390
|
+
const entry = entryOf.get(item);
|
|
391
|
+
if (!entry || entry.owner === self) node.children.push(item);
|
|
392
|
+
}
|
|
393
|
+
node.icon = meta.icon ?? node.index?.icon;
|
|
394
|
+
node.name = meta.title ?? node.index?.name;
|
|
395
|
+
self.title = meta.title ?? (node.index && entryOf.get(node.index)?.title);
|
|
525
396
|
if (!node.name) {
|
|
526
|
-
const
|
|
527
|
-
node.name = pathToName(group.exec(
|
|
397
|
+
const name = basename(path);
|
|
398
|
+
node.name = pathToName(group.exec(name)?.[1] ?? name);
|
|
528
399
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
400
|
+
let result = node;
|
|
401
|
+
for (const t of transformers) if (t.folder) result = t.folder.call(ctx, result, path, metaPath);
|
|
402
|
+
self.node = result;
|
|
403
|
+
self.done = true;
|
|
404
|
+
entryOf.set(result, self);
|
|
405
|
+
return self;
|
|
406
|
+
}
|
|
407
|
+
/** build the remaining items of a folder for `...` */
|
|
408
|
+
function buildRest(paths, excluded, reversed) {
|
|
409
|
+
const out = [];
|
|
410
|
+
let index;
|
|
411
|
+
for (const path of paths) {
|
|
412
|
+
if (excluded.has(path)) continue;
|
|
413
|
+
const file = buildFile(path);
|
|
414
|
+
if (file && !index && basename(path, extname(path)) === "index") index = file;
|
|
415
|
+
const entry = file ?? buildFolder(path);
|
|
416
|
+
if (entry) out.push(entry);
|
|
532
417
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
418
|
+
const factor = reversed ? -1 : 1;
|
|
419
|
+
return out.sort((a, b) => {
|
|
420
|
+
if (a === index) return -1;
|
|
421
|
+
if (b === index) return 1;
|
|
422
|
+
const type = Number(a.node.type === "folder") - Number(b.node.type === "folder");
|
|
423
|
+
return factor * (type || compare(byName && a.title || a.path, byName && b.title || b.path));
|
|
424
|
+
});
|
|
536
425
|
}
|
|
537
|
-
function
|
|
538
|
-
const
|
|
539
|
-
if (
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const { title, description, icon } = page.data;
|
|
543
|
-
let item = {
|
|
544
|
-
$id: generateId(path),
|
|
426
|
+
function resolveLink(item) {
|
|
427
|
+
const match = link.exec(item)?.groups;
|
|
428
|
+
if (!match) return;
|
|
429
|
+
let node = {
|
|
430
|
+
$id: createId(),
|
|
545
431
|
type: "page",
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
$ref: path,
|
|
551
|
-
[SymbolName]: title
|
|
432
|
+
icon: match.icon,
|
|
433
|
+
name: match.name,
|
|
434
|
+
url: match.url,
|
|
435
|
+
external: match.external ? true : void 0
|
|
552
436
|
};
|
|
553
|
-
for (const
|
|
554
|
-
|
|
555
|
-
item = transformer.file.call(ctx, item, path);
|
|
556
|
-
}
|
|
557
|
-
pathToNode.set(path, item);
|
|
558
|
-
return item;
|
|
437
|
+
for (const t of transformers) if (t.file) node = t.file.call(ctx, node);
|
|
438
|
+
return node;
|
|
559
439
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
440
|
+
function resolveSeparator(item) {
|
|
441
|
+
const match = separator.exec(item)?.groups;
|
|
442
|
+
if (!match) return;
|
|
443
|
+
let node = {
|
|
444
|
+
$id: createId(),
|
|
445
|
+
type: "separator",
|
|
446
|
+
icon: match.icon,
|
|
447
|
+
name: match.name
|
|
448
|
+
};
|
|
449
|
+
for (const t of transformers) if (t.separator) node = t.separator.call(ctx, node);
|
|
450
|
+
return node;
|
|
451
|
+
}
|
|
452
|
+
function root(id = "root", path = "") {
|
|
453
|
+
const folder = buildFolder(path, true)?.node;
|
|
454
|
+
if (options.noRef) for (const { node } of entries.values()) delete node.$ref;
|
|
455
|
+
let out = {
|
|
456
|
+
type: "root",
|
|
457
|
+
$ref: folder?.$ref,
|
|
458
|
+
$id: createId(id),
|
|
459
|
+
name: folder?.name || "Docs",
|
|
460
|
+
description: folder?.description,
|
|
461
|
+
children: folder ? folder.children : []
|
|
462
|
+
};
|
|
463
|
+
for (const t of transformers) if (t.root) out = t.root.call(ctx, out);
|
|
464
|
+
if ((options.generateFallback ?? true) && usedPages + metaPaths.size < storage.files.size) {
|
|
465
|
+
const unused = new FileSystem();
|
|
466
|
+
for (const [path, file] of storage.files) if (!entries.has(path) && !metaPaths.has(path)) unused.write(path, file);
|
|
467
|
+
out.fallback = createPageTreeBuilder(unused, {
|
|
468
|
+
...options,
|
|
469
|
+
idPrefix: idPrefix ? `fallback:${idPrefix}` : "fallback",
|
|
470
|
+
generateFallback: false
|
|
471
|
+
}, locale, storages).root();
|
|
582
472
|
}
|
|
583
|
-
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
584
475
|
return builder;
|
|
585
476
|
}
|
|
586
477
|
/**
|
|
@@ -589,17 +480,15 @@ function createPageTreeBuilder(input, options) {
|
|
|
589
480
|
* @param name - file name
|
|
590
481
|
*/
|
|
591
482
|
function pathToName(name) {
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
else if (c === "-") result.push(" ");
|
|
595
|
-
else result.push(c);
|
|
596
|
-
return result.join("");
|
|
483
|
+
const [first = "", ...rest] = name;
|
|
484
|
+
return first.toLocaleUpperCase() + rest.join("").replaceAll("-", " ");
|
|
597
485
|
}
|
|
598
486
|
//#endregion
|
|
599
487
|
//#region src/source/loader.ts
|
|
600
488
|
/** decoded, generated slugs are URI encoded but some routers pass them decoded */
|
|
601
489
|
function slugsKey(slugs) {
|
|
602
490
|
const key = slugs.join("/");
|
|
491
|
+
if (!key.includes("%")) return key;
|
|
603
492
|
try {
|
|
604
493
|
return decodeURI(key);
|
|
605
494
|
} catch {
|
|
@@ -607,18 +496,20 @@ function slugsKey(slugs) {
|
|
|
607
496
|
}
|
|
608
497
|
}
|
|
609
498
|
function createPageIndexer({ url }) {
|
|
610
|
-
|
|
611
|
-
const
|
|
612
|
-
const pathToPage = /* @__PURE__ */ new Map();
|
|
613
|
-
const urlToPage = /* @__PURE__ */ new Map();
|
|
499
|
+
/** locale (empty without i18n) -> index */
|
|
500
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
614
501
|
return {
|
|
615
502
|
scan(storage, lang) {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
503
|
+
const index = {
|
|
504
|
+
pages: /* @__PURE__ */ new Map(),
|
|
505
|
+
pathToPage: /* @__PURE__ */ new Map(),
|
|
506
|
+
pathToMeta: /* @__PURE__ */ new Map(),
|
|
507
|
+
urlToPage: /* @__PURE__ */ new Map()
|
|
508
|
+
};
|
|
509
|
+
indexes.set(lang ?? "", index);
|
|
510
|
+
for (const [path, item] of storage.files) {
|
|
620
511
|
if (item.format === "meta") {
|
|
621
|
-
pathToMeta.set(path, {
|
|
512
|
+
index.pathToMeta.set(path, {
|
|
622
513
|
type: item.type,
|
|
623
514
|
path: item.path,
|
|
624
515
|
absolutePath: item.absolutePath,
|
|
@@ -635,41 +526,43 @@ function createPageIndexer({ url }) {
|
|
|
635
526
|
data: item.data,
|
|
636
527
|
locale: lang
|
|
637
528
|
};
|
|
638
|
-
pathToPage.set(path, page);
|
|
639
|
-
pages.set(
|
|
640
|
-
urlToPage.set(
|
|
529
|
+
index.pathToPage.set(path, page);
|
|
530
|
+
index.pages.set(slugsKey(page.slugs), page);
|
|
531
|
+
index.urlToPage.set(page.url, page);
|
|
641
532
|
}
|
|
642
533
|
},
|
|
643
534
|
getPage(path, lang = "") {
|
|
644
|
-
return pathToPage.get(
|
|
535
|
+
return indexes.get(lang)?.pathToPage.get(path);
|
|
645
536
|
},
|
|
646
537
|
getPageByUrl(url, lang = "") {
|
|
647
|
-
return urlToPage.get(
|
|
538
|
+
return indexes.get(lang)?.urlToPage.get(url);
|
|
648
539
|
},
|
|
649
540
|
getMeta(path, lang = "") {
|
|
650
|
-
return pathToMeta.get(
|
|
541
|
+
return indexes.get(lang)?.pathToMeta.get(path);
|
|
651
542
|
},
|
|
652
543
|
getPageBySlugs(slugs, lang = "") {
|
|
653
|
-
return pages.get(
|
|
544
|
+
return indexes.get(lang)?.pages.get(slugsKey(slugs));
|
|
654
545
|
},
|
|
655
546
|
/** do not filter by language if `lang` is not specified */
|
|
656
547
|
getPages(lang) {
|
|
657
548
|
const out = [];
|
|
658
|
-
for (const [key,
|
|
549
|
+
for (const [key, index] of indexes) {
|
|
550
|
+
if (lang !== void 0 && key !== lang) continue;
|
|
551
|
+
for (const page of index.pages.values()) out.push(page);
|
|
552
|
+
}
|
|
659
553
|
return out;
|
|
660
554
|
}
|
|
661
555
|
};
|
|
662
556
|
}
|
|
663
557
|
function createGetUrl(baseUrl, i18n) {
|
|
664
|
-
const
|
|
558
|
+
const hideLocale = i18n?.hideLocale ?? "never";
|
|
559
|
+
let base = "";
|
|
560
|
+
for (const seg of baseUrl.split("/")) if (seg.length > 0) base += `/${seg}`;
|
|
665
561
|
return (slugs, locale) => {
|
|
666
|
-
const
|
|
667
|
-
let
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
const paths = [...baseSlugs, ...slugs];
|
|
671
|
-
if (urlLocale) paths.unshift(urlLocale);
|
|
672
|
-
return `/${paths.filter((v) => v.length > 0).join("/")}`;
|
|
562
|
+
const showLocale = hideLocale === "never" || hideLocale === "default-locale" && locale !== i18n?.defaultLanguage;
|
|
563
|
+
let url = locale && showLocale ? `/${locale}${base}` : base;
|
|
564
|
+
for (const slug of slugs) if (slug.length > 0) url += `/${slug}`;
|
|
565
|
+
return url || "/";
|
|
673
566
|
};
|
|
674
567
|
}
|
|
675
568
|
function loader(...args) {
|
|
@@ -692,11 +585,9 @@ function loader(...args) {
|
|
|
692
585
|
transformers
|
|
693
586
|
};
|
|
694
587
|
if (storage instanceof FileSystem) return pageTrees = createPageTreeBuilder(storage, options).root();
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
return pageTrees = out;
|
|
699
|
-
}
|
|
588
|
+
const out = {};
|
|
589
|
+
for (const locale in storage) out[locale] = createPageTreeBuilder(storage[locale], options, locale, storage).root();
|
|
590
|
+
return pageTrees = out;
|
|
700
591
|
}
|
|
701
592
|
const out = {
|
|
702
593
|
_i18n: i18n,
|
|
@@ -772,12 +663,17 @@ function loader(...args) {
|
|
|
772
663
|
}
|
|
773
664
|
return getPageTrees();
|
|
774
665
|
},
|
|
775
|
-
generateParams(slug, lang) {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
666
|
+
generateParams(slug = "slug", lang = "lang") {
|
|
667
|
+
const params = [];
|
|
668
|
+
if (!i18n) {
|
|
669
|
+
for (const page of this.getPages()) params.push({ [slug]: page.slugs });
|
|
670
|
+
return params;
|
|
671
|
+
}
|
|
672
|
+
for (const entry of this.getLanguages()) for (const page of entry.pages) params.push({
|
|
673
|
+
[slug]: page.slugs,
|
|
674
|
+
[lang]: entry.language
|
|
675
|
+
});
|
|
676
|
+
return params;
|
|
781
677
|
},
|
|
782
678
|
async serializePageTree(tree) {
|
|
783
679
|
const { renderToString } = await import("react-dom/server.edge");
|
package/dist/source/dynamic.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as dynamicLoader } from "../dynamic-
|
|
1
|
+
import { t as dynamicLoader } from "../dynamic-CsxXgQ9d.js";
|
|
2
2
|
export { dynamicLoader };
|
package/dist/source/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as path_exports } from "../path-m9Srg2Jq.js";
|
|
2
|
-
import { a as update, i as multiple, n as createGetUrl, o as FileSystem, r as loader, t as dynamicLoader } from "../dynamic-
|
|
2
|
+
import { a as update, i as multiple, n as createGetUrl, o as FileSystem, r as loader, t as dynamicLoader } from "../dynamic-CsxXgQ9d.js";
|
|
3
3
|
import { getSlugs } from "./plugins/slugs.js";
|
|
4
4
|
import { llms } from "./llms.js";
|
|
5
5
|
export { FileSystem, path_exports as PathUtils, createGetUrl, dynamicLoader, getSlugs, llms, loader, multiple, update };
|
|
@@ -16,9 +16,8 @@ function slugsPlugin(optsOrFn = {}) {
|
|
|
16
16
|
transformStorage({ storage }) {
|
|
17
17
|
const indexFiles = [];
|
|
18
18
|
const taken = /* @__PURE__ */ new Set();
|
|
19
|
-
for (const path of storage.
|
|
20
|
-
|
|
21
|
-
if (!file || file.format !== "page") continue;
|
|
19
|
+
for (const [path, file] of storage.files) {
|
|
20
|
+
if (file.format !== "page") continue;
|
|
22
21
|
if (file.slugs) {
|
|
23
22
|
if (baseSlugs.length > 0 && !prepended.has(file)) {
|
|
24
23
|
file.slugs = [...baseSlugs, ...file.slugs];
|