diffwiki-core 0.5.0-rc.202607230329.fb70592 → 0.5.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/dist/{chunk-GVSRD5WB.js → chunk-AZ6SZH6P.js} +1 -17
- package/dist/{events-XSIUMRBG.js → events-H3D7FT4O.js} +1 -1
- package/dist/index.cjs +377 -664
- package/dist/index.d.cts +9 -147
- package/dist/index.d.ts +9 -147
- package/dist/index.js +331 -528
- package/package.json +1 -6
- package/dist/bm25.cjs +0 -85
- package/dist/bm25.d.cts +0 -48
- package/dist/bm25.d.ts +0 -48
- package/dist/bm25.js +0 -8
- package/dist/chunk-FTUF6IXS.js +0 -60
package/dist/index.cjs
CHANGED
|
@@ -40,7 +40,7 @@ var init_types = __esm({
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
// src/errors.ts
|
|
43
|
-
var DiffwikiError, CollectionExistsError, CollectionNotFoundError, NoDefaultCollectionError, ArticleNotFoundError, InvalidTargetError, PluginError
|
|
43
|
+
var DiffwikiError, CollectionExistsError, CollectionNotFoundError, NoDefaultCollectionError, ArticleNotFoundError, InvalidTargetError, PluginError;
|
|
44
44
|
var init_errors = __esm({
|
|
45
45
|
"src/errors.ts"() {
|
|
46
46
|
"use strict";
|
|
@@ -77,16 +77,6 @@ var init_errors = __esm({
|
|
|
77
77
|
};
|
|
78
78
|
PluginError = class extends DiffwikiError {
|
|
79
79
|
};
|
|
80
|
-
WorktreeNotAllowedError = class extends DiffwikiError {
|
|
81
|
-
constructor(root) {
|
|
82
|
-
super(`refusing to add a linked worktree \u2014 add the source repository instead (${root})`);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
CollectionAlreadyAddedError = class extends DiffwikiError {
|
|
86
|
-
constructor(name) {
|
|
87
|
-
super(`this repository is already added as collection "${name}"`);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
80
|
}
|
|
91
81
|
});
|
|
92
82
|
|
|
@@ -514,9 +504,6 @@ async function listCollections() {
|
|
|
514
504
|
async function findCollection(name) {
|
|
515
505
|
return (await readRegistry()).collections.find((c) => c.name === name);
|
|
516
506
|
}
|
|
517
|
-
async function findCollectionById(id) {
|
|
518
|
-
return (await readRegistry()).collections.find((c) => c.id === id);
|
|
519
|
-
}
|
|
520
507
|
async function createCollection(name) {
|
|
521
508
|
if (await findCollection(name)) throw new CollectionExistsError(name);
|
|
522
509
|
const dir = collectionDir(name);
|
|
@@ -556,7 +543,6 @@ var init_collections = __esm({
|
|
|
556
543
|
var index_exports = {};
|
|
557
544
|
__export(index_exports, {
|
|
558
545
|
ArticleNotFoundError: () => ArticleNotFoundError,
|
|
559
|
-
CollectionAlreadyAddedError: () => CollectionAlreadyAddedError,
|
|
560
546
|
CollectionExistsError: () => CollectionExistsError,
|
|
561
547
|
CollectionNotFoundError: () => CollectionNotFoundError,
|
|
562
548
|
DiffwikiError: () => DiffwikiError,
|
|
@@ -565,35 +551,24 @@ __export(index_exports, {
|
|
|
565
551
|
NoDefaultCollectionError: () => NoDefaultCollectionError,
|
|
566
552
|
PluginError: () => PluginError,
|
|
567
553
|
REPO_CONFIG_FILE: () => REPO_CONFIG_FILE,
|
|
568
|
-
WorktreeNotAllowedError: () => WorktreeNotAllowedError,
|
|
569
|
-
addExternalCollection: () => addExternalCollection,
|
|
570
554
|
addTags: () => addTags,
|
|
571
555
|
buildArticleTree: () => buildArticleTree,
|
|
572
|
-
buildCollections: () => buildCollections,
|
|
573
|
-
buildNavTree: () => buildNavTree,
|
|
574
|
-
buildSearchIndex: () => buildSearchIndex,
|
|
575
556
|
collectionDir: () => collectionDir,
|
|
576
|
-
collectionGitStatus: () => collectionGitStatus,
|
|
577
557
|
collectionsDir: () => collectionsDir,
|
|
578
558
|
configPath: () => configPath,
|
|
579
559
|
createArticle: () => createArticle,
|
|
580
560
|
createCollection: () => createCollection,
|
|
581
|
-
currentBranch: () => currentBranch,
|
|
582
561
|
deregisterPlugin: () => deregisterPlugin,
|
|
583
562
|
doctor: () => doctor,
|
|
584
563
|
emitPluginEvent: () => emitPluginEvent,
|
|
585
|
-
ensureGitRepo: () => ensureGitRepo,
|
|
586
564
|
ensurePluginRoot: () => ensurePluginRoot,
|
|
587
565
|
findCollection: () => findCollection,
|
|
588
|
-
findCollectionById: () => findCollectionById,
|
|
589
566
|
findEnabledPlugin: () => findEnabledPlugin,
|
|
590
567
|
findPluginRecord: () => findPluginRecord,
|
|
591
568
|
getConfigValue: () => getConfigValue,
|
|
592
569
|
getLogger: () => getLogger,
|
|
593
|
-
gitToplevel: () => gitToplevel,
|
|
594
570
|
initRepoWiki: () => initRepoWiki,
|
|
595
571
|
installPlugin: () => installPlugin,
|
|
596
|
-
isLinkedWorktree: () => isLinkedWorktree,
|
|
597
572
|
listArticleTree: () => listArticleTree,
|
|
598
573
|
listAvailablePlugins: () => listAvailablePlugins,
|
|
599
574
|
listCollections: () => listCollections,
|
|
@@ -608,7 +583,6 @@ __export(index_exports, {
|
|
|
608
583
|
pluginsDir: () => pluginsDir,
|
|
609
584
|
pluginsRegistryPath: () => pluginsRegistryPath,
|
|
610
585
|
query: () => query,
|
|
611
|
-
rankDocs: () => rankDocs,
|
|
612
586
|
readArticle: () => readArticle,
|
|
613
587
|
readConfig: () => readConfig,
|
|
614
588
|
readPluginRegistry: () => readPluginRegistry,
|
|
@@ -622,24 +596,17 @@ __export(index_exports, {
|
|
|
622
596
|
removePlugin: () => removePlugin,
|
|
623
597
|
removeTags: () => removeTags,
|
|
624
598
|
renderArticle: () => renderArticle,
|
|
625
|
-
repoId: () => repoId,
|
|
626
|
-
repoRemoteName: () => repoRemoteName,
|
|
627
|
-
resolveCwdCollection: () => resolveCwdCollection,
|
|
628
599
|
resolveDefaultSearchMode: () => resolveDefaultSearchMode,
|
|
629
600
|
resolveHome: () => resolveHome,
|
|
630
601
|
resolveLogLevel: () => resolveLogLevel,
|
|
631
|
-
resolvePage: () => resolvePage,
|
|
632
602
|
search: () => search,
|
|
633
603
|
serializeArticle: () => serializeArticle,
|
|
634
604
|
setConfigValue: () => setConfigValue,
|
|
635
605
|
setTags: () => setTags,
|
|
636
606
|
slugify: () => slugify,
|
|
637
|
-
toTreeNodes: () => toTreeNodes,
|
|
638
|
-
tokenize: () => tokenize,
|
|
639
607
|
unregisterCollection: () => unregisterCollection,
|
|
640
608
|
updateArticleBody: () => updateArticleBody,
|
|
641
609
|
upsertPlugin: () => upsertPlugin,
|
|
642
|
-
upstreamStatus: () => upstreamStatus,
|
|
643
610
|
writeConfig: () => writeConfig,
|
|
644
611
|
writePluginRegistry: () => writePluginRegistry,
|
|
645
612
|
writeRegistry: () => writeRegistry
|
|
@@ -881,89 +848,29 @@ async function removeArticle(target) {
|
|
|
881
848
|
|
|
882
849
|
// src/repo.ts
|
|
883
850
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
884
|
-
var import_node_path5 = __toESM(require("path"), 1);
|
|
885
|
-
var import_node_child_process3 = require("child_process");
|
|
886
|
-
var import_node_util2 = require("util");
|
|
887
|
-
var import_yaml2 = require("yaml");
|
|
888
|
-
init_collections();
|
|
889
|
-
init_registry();
|
|
890
|
-
|
|
891
|
-
// src/git.ts
|
|
892
851
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
893
852
|
var import_node_child_process2 = require("child_process");
|
|
894
853
|
var import_node_util = require("util");
|
|
854
|
+
var import_yaml2 = require("yaml");
|
|
855
|
+
init_collections();
|
|
856
|
+
init_registry();
|
|
895
857
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process2.execFile);
|
|
896
|
-
async function git(cwd, args) {
|
|
897
|
-
try {
|
|
898
|
-
const { stdout } = await execFileAsync("git", args, { cwd });
|
|
899
|
-
return stdout.trim();
|
|
900
|
-
} catch {
|
|
901
|
-
return void 0;
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
async function gitToplevel(cwd) {
|
|
905
|
-
return git(cwd, ["rev-parse", "--show-toplevel"]);
|
|
906
|
-
}
|
|
907
|
-
async function isLinkedWorktree(cwd) {
|
|
908
|
-
const gitDir = await git(cwd, ["rev-parse", "--absolute-git-dir"]);
|
|
909
|
-
const commonDir = await git(cwd, ["rev-parse", "--git-common-dir"]);
|
|
910
|
-
if (!gitDir || !commonDir) return false;
|
|
911
|
-
const commonAbs = import_node_path4.default.isAbsolute(commonDir) ? commonDir : import_node_path4.default.resolve(cwd, commonDir);
|
|
912
|
-
return import_node_path4.default.resolve(gitDir) !== import_node_path4.default.resolve(commonAbs);
|
|
913
|
-
}
|
|
914
|
-
async function repoRemoteName(cwd) {
|
|
915
|
-
const url = await git(cwd, ["remote", "get-url", "origin"]);
|
|
916
|
-
if (!url) return void 0;
|
|
917
|
-
const base = url.replace(/\/+$/, "").split(/[/:]/).pop() ?? "";
|
|
918
|
-
const name = base.replace(/\.git$/, "");
|
|
919
|
-
return name.length > 0 ? name : void 0;
|
|
920
|
-
}
|
|
921
|
-
async function repoId(cwd) {
|
|
922
|
-
const roots = await git(cwd, ["rev-list", "--max-parents=0", "HEAD"]);
|
|
923
|
-
if (roots) return `commit:${roots.split("\n")[0]}`;
|
|
924
|
-
const url = await git(cwd, ["remote", "get-url", "origin"]);
|
|
925
|
-
if (url) return `remote:${url.replace(/\.git$/, "").replace(/\/+$/, "")}`;
|
|
926
|
-
return void 0;
|
|
927
|
-
}
|
|
928
|
-
async function currentBranch(cwd) {
|
|
929
|
-
const name = await git(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
930
|
-
return name && name !== "HEAD" ? name : void 0;
|
|
931
|
-
}
|
|
932
|
-
async function upstreamStatus(cwd) {
|
|
933
|
-
const branch = await currentBranch(cwd);
|
|
934
|
-
const counts = await git(cwd, ["rev-list", "--left-right", "--count", "@{upstream}...HEAD"]);
|
|
935
|
-
if (!counts) return { branch, ahead: 0, behind: 0, hasUpstream: false };
|
|
936
|
-
const [behind, ahead] = counts.split(/\s+/).map((n) => Number.parseInt(n, 10) || 0);
|
|
937
|
-
return { branch, ahead, behind, hasUpstream: true };
|
|
938
|
-
}
|
|
939
|
-
async function ensureGitRepo(cwd) {
|
|
940
|
-
const top = await gitToplevel(cwd);
|
|
941
|
-
if (top) return top;
|
|
942
|
-
await execFileAsync("git", ["init"], { cwd });
|
|
943
|
-
const after = await gitToplevel(cwd);
|
|
944
|
-
if (!after) throw new Error("git init did not produce a repository");
|
|
945
|
-
return after;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
// src/repo.ts
|
|
949
|
-
init_errors();
|
|
950
|
-
var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process3.execFile);
|
|
951
858
|
var REPO_CONFIG_FILE = "diffwiki.yaml";
|
|
952
859
|
async function detectRepoName(cwd) {
|
|
953
860
|
try {
|
|
954
|
-
const { stdout } = await
|
|
955
|
-
return
|
|
861
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], { cwd });
|
|
862
|
+
return import_node_path4.default.basename(stdout.trim());
|
|
956
863
|
} catch {
|
|
957
|
-
return
|
|
864
|
+
return import_node_path4.default.basename(import_node_path4.default.resolve(cwd));
|
|
958
865
|
}
|
|
959
866
|
}
|
|
960
867
|
async function readRepoConfig(cwd) {
|
|
961
868
|
try {
|
|
962
|
-
const raw = await import_promises6.default.readFile(
|
|
869
|
+
const raw = await import_promises6.default.readFile(import_node_path4.default.join(cwd, REPO_CONFIG_FILE), "utf8");
|
|
963
870
|
const parsed = (0, import_yaml2.parse)(raw) ?? {};
|
|
964
871
|
if (!parsed.path) return void 0;
|
|
965
872
|
return {
|
|
966
|
-
collection: parsed.collection ??
|
|
873
|
+
collection: parsed.collection ?? import_node_path4.default.basename(import_node_path4.default.resolve(cwd)),
|
|
967
874
|
path: parsed.path
|
|
968
875
|
};
|
|
969
876
|
} catch (err) {
|
|
@@ -972,9 +879,9 @@ async function readRepoConfig(cwd) {
|
|
|
972
879
|
}
|
|
973
880
|
}
|
|
974
881
|
async function initRepoWiki(opts) {
|
|
975
|
-
const cwd =
|
|
882
|
+
const cwd = import_node_path4.default.resolve(opts.cwd);
|
|
976
883
|
const wikiPath = opts.wikiPath ?? "wiki";
|
|
977
|
-
const absWiki =
|
|
884
|
+
const absWiki = import_node_path4.default.join(cwd, wikiPath);
|
|
978
885
|
let name = opts.collection ?? await detectRepoName(cwd);
|
|
979
886
|
const existing = await findCollection(name);
|
|
980
887
|
if (existing && existing.path !== absWiki) {
|
|
@@ -991,7 +898,7 @@ async function initRepoWiki(opts) {
|
|
|
991
898
|
}
|
|
992
899
|
await import_promises6.default.mkdir(absWiki, { recursive: true });
|
|
993
900
|
const config = { collection: name, path: wikiPath };
|
|
994
|
-
await import_promises6.default.writeFile(
|
|
901
|
+
await import_promises6.default.writeFile(import_node_path4.default.join(cwd, REPO_CONFIG_FILE), (0, import_yaml2.stringify)(config), "utf8");
|
|
995
902
|
const entry = {
|
|
996
903
|
name,
|
|
997
904
|
type: "repo",
|
|
@@ -1001,497 +908,152 @@ async function initRepoWiki(opts) {
|
|
|
1001
908
|
await registerCollection(entry);
|
|
1002
909
|
return entry;
|
|
1003
910
|
}
|
|
1004
|
-
async function addExternalCollection(opts) {
|
|
1005
|
-
const cwd = import_node_path5.default.resolve(opts.cwd);
|
|
1006
|
-
const root = await ensureGitRepo(cwd);
|
|
1007
|
-
if (await isLinkedWorktree(cwd)) throw new WorktreeNotAllowedError(root);
|
|
1008
|
-
const id = await repoId(root) ?? `path:${root}`;
|
|
1009
|
-
const already = await findCollectionById(id);
|
|
1010
|
-
if (already) throw new CollectionAlreadyAddedError(already.name);
|
|
1011
|
-
const docsRel = opts.docsDir ?? "docs";
|
|
1012
|
-
const contentDir = import_node_path5.default.join(root, docsRel);
|
|
1013
|
-
let name = await repoRemoteName(root) ?? import_node_path5.default.basename(root);
|
|
1014
|
-
if (await findCollection(name)) {
|
|
1015
|
-
let n = 2;
|
|
1016
|
-
while (await findCollection(`${name}-${n}`)) n += 1;
|
|
1017
|
-
name = `${name}-${n}`;
|
|
1018
|
-
}
|
|
1019
|
-
const entry = {
|
|
1020
|
-
name,
|
|
1021
|
-
type: "external",
|
|
1022
|
-
path: contentDir,
|
|
1023
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1024
|
-
id,
|
|
1025
|
-
repoRoot: root,
|
|
1026
|
-
docsDir: docsRel
|
|
1027
|
-
};
|
|
1028
|
-
await registerCollection(entry);
|
|
1029
|
-
return entry;
|
|
1030
|
-
}
|
|
1031
|
-
async function resolveCwdCollection(cwd) {
|
|
1032
|
-
const abs = import_node_path5.default.resolve(cwd);
|
|
1033
|
-
const root = await gitToplevel(abs);
|
|
1034
|
-
if (root) {
|
|
1035
|
-
const id = await repoId(root) ?? `path:${root}`;
|
|
1036
|
-
const byId = await findCollectionById(id);
|
|
1037
|
-
if (byId) return byId;
|
|
1038
|
-
}
|
|
1039
|
-
const within = (base) => abs === base || abs.startsWith(base + import_node_path5.default.sep);
|
|
1040
|
-
const all = await listCollections();
|
|
1041
|
-
return all.find((c) => within(c.path) || c.repoRoot !== void 0 && within(c.repoRoot));
|
|
1042
|
-
}
|
|
1043
|
-
async function collectionGitStatus(entry) {
|
|
1044
|
-
if (entry.type !== "external" || !entry.repoRoot) return void 0;
|
|
1045
|
-
const top = await gitToplevel(entry.repoRoot);
|
|
1046
|
-
if (!top) return void 0;
|
|
1047
|
-
const s = await upstreamStatus(entry.repoRoot);
|
|
1048
|
-
return { branch: s.branch, ahead: s.ahead, behind: s.behind, hasUpstream: s.hasUpstream };
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
// src/site.ts
|
|
1052
|
-
init_collections();
|
|
1053
911
|
|
|
1054
|
-
// src/
|
|
912
|
+
// src/query.ts
|
|
1055
913
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
1056
|
-
var
|
|
914
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1057
915
|
init_collections();
|
|
1058
916
|
init_errors();
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
let cur = root;
|
|
1067
|
-
segs.forEach((seg, i) => {
|
|
1068
|
-
if (i === segs.length - 1) {
|
|
1069
|
-
if (!(seg in cur)) cur[seg] = null;
|
|
1070
|
-
} else {
|
|
1071
|
-
if (cur[seg] === null || !(seg in cur)) cur[seg] = {};
|
|
1072
|
-
cur = cur[seg];
|
|
1073
|
-
}
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
const stripExt = (f) => f.replace(/\.(mdx?)$/, "");
|
|
1077
|
-
const walk = (trie, parents) => {
|
|
1078
|
-
const entries = Object.entries(trie);
|
|
1079
|
-
const branches = entries.filter(([, v]) => v !== null);
|
|
1080
|
-
const leaves = entries.filter(([, v]) => v === null).map(([k]) => k).filter((f) => !INDEX_RE.test(f));
|
|
1081
|
-
branches.sort(([a], [b]) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
1082
|
-
leaves.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
1083
|
-
const branchNodes = branches.map(([seg, sub]) => ({
|
|
1084
|
-
name: seg,
|
|
1085
|
-
title: seg,
|
|
1086
|
-
// Folders are navigable to their index page (an authored index.md/README,
|
|
1087
|
-
// else a generated listing).
|
|
1088
|
-
slug: [...parents, seg].join("/"),
|
|
1089
|
-
children: walk(sub, [...parents, seg])
|
|
1090
|
-
}));
|
|
1091
|
-
const leafNodes = leaves.map((file) => {
|
|
1092
|
-
const nameNoExt = stripExt(file);
|
|
1093
|
-
return { name: nameNoExt, title: nameNoExt, slug: [...parents, nameNoExt].join("/") };
|
|
1094
|
-
});
|
|
1095
|
-
return [...branchNodes, ...leafNodes];
|
|
1096
|
-
};
|
|
1097
|
-
return walk(root, []);
|
|
1098
|
-
}
|
|
1099
|
-
async function collectRelPaths(dir, rel = "") {
|
|
1100
|
-
let dirents;
|
|
917
|
+
init_logger();
|
|
918
|
+
init_host();
|
|
919
|
+
init_registry2();
|
|
920
|
+
init_types();
|
|
921
|
+
var log = getLogger("query");
|
|
922
|
+
async function collectMarkdownFiles(dir) {
|
|
923
|
+
let entries;
|
|
1101
924
|
try {
|
|
1102
|
-
|
|
925
|
+
entries = await import_promises7.default.readdir(dir, { withFileTypes: true });
|
|
1103
926
|
} catch {
|
|
1104
927
|
return [];
|
|
1105
928
|
}
|
|
1106
|
-
const
|
|
1107
|
-
for (const
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
out.push(childRel);
|
|
929
|
+
const files = [];
|
|
930
|
+
for (const entry of entries) {
|
|
931
|
+
const full = import_node_path5.default.join(dir, entry.name);
|
|
932
|
+
if (entry.isDirectory()) {
|
|
933
|
+
files.push(...await collectMarkdownFiles(full));
|
|
934
|
+
} else if (entry.isFile() && /\.mdx?$/.test(entry.name)) {
|
|
935
|
+
files.push(full);
|
|
1114
936
|
}
|
|
1115
937
|
}
|
|
1116
|
-
return
|
|
938
|
+
return files;
|
|
1117
939
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
940
|
+
var K1 = 1.5;
|
|
941
|
+
var B = 0.75;
|
|
942
|
+
var FIELD_WEIGHTS = { title: 3, tags: 2, collection: 1.5, body: 1 };
|
|
943
|
+
function tokenize(text) {
|
|
944
|
+
return text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 0);
|
|
1124
945
|
}
|
|
1125
|
-
function
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
};
|
|
1132
|
-
return names.filter((n) => INDEX_RE.test(n)).sort((a, b) => rank(a) - rank(b))[0];
|
|
946
|
+
function termFreqs(tokens) {
|
|
947
|
+
const freqs = /* @__PURE__ */ new Map();
|
|
948
|
+
for (const t of tokens) {
|
|
949
|
+
freqs.set(t, (freqs.get(t) ?? 0) + 1);
|
|
950
|
+
}
|
|
951
|
+
return freqs;
|
|
1133
952
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
const
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
953
|
+
function bm25FieldScore(queryTerms, fieldTokens, avgFieldLen, idf) {
|
|
954
|
+
const tf = termFreqs(fieldTokens);
|
|
955
|
+
const dl = fieldTokens.length;
|
|
956
|
+
const avgDl = avgFieldLen || 1;
|
|
957
|
+
let score = 0;
|
|
958
|
+
for (const term of queryTerms) {
|
|
959
|
+
const freq = tf.get(term) ?? 0;
|
|
960
|
+
if (freq === 0) continue;
|
|
961
|
+
const termIdf = idf.get(term) ?? 0;
|
|
962
|
+
const numerator = freq * (K1 + 1);
|
|
963
|
+
const denominator = freq + K1 * (1 - B + B * (dl / avgDl));
|
|
964
|
+
score += termIdf * (numerator / denominator);
|
|
1146
965
|
}
|
|
1147
|
-
return
|
|
966
|
+
return score;
|
|
1148
967
|
}
|
|
1149
|
-
async function
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
968
|
+
async function nativeSearch(term, collections, collection) {
|
|
969
|
+
let targets = collections;
|
|
970
|
+
if (collection) {
|
|
971
|
+
const one = collections.find((c) => c.name === collection);
|
|
972
|
+
if (!one) throw new CollectionNotFoundError(collection);
|
|
973
|
+
targets = [one];
|
|
974
|
+
}
|
|
975
|
+
const docs = [];
|
|
976
|
+
for (const entry of targets) {
|
|
977
|
+
for (const full of await collectMarkdownFiles(entry.path)) {
|
|
978
|
+
const fallbackTitle = import_node_path5.default.basename(full).replace(/\.mdx?$/, "");
|
|
979
|
+
let title = fallbackTitle;
|
|
980
|
+
let tags = [];
|
|
981
|
+
let body = "";
|
|
982
|
+
try {
|
|
983
|
+
const parsed = parseArticle(await import_promises7.default.readFile(full, "utf8"));
|
|
984
|
+
if (parsed.title) title = parsed.title;
|
|
985
|
+
tags = parsed.tags;
|
|
986
|
+
body = parsed.body;
|
|
987
|
+
} catch {
|
|
1165
988
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
const collDir = import_node_path6.default.resolve(entry.path);
|
|
1180
|
-
const normalized = slug.replace(/\\/g, "/");
|
|
1181
|
-
if (normalized.split("/").some((s) => s === "..")) {
|
|
1182
|
-
throw new InvalidTargetError(slug, "path traversal detected");
|
|
989
|
+
docs.push({
|
|
990
|
+
collectionName: entry.name,
|
|
991
|
+
filePath: full,
|
|
992
|
+
title,
|
|
993
|
+
tags,
|
|
994
|
+
fields: {
|
|
995
|
+
title: tokenize(title),
|
|
996
|
+
tags: tokenize(tags.join(" ")),
|
|
997
|
+
collection: tokenize(entry.name),
|
|
998
|
+
body: tokenize(body)
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1183
1002
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1003
|
+
if (!term.trim()) {
|
|
1004
|
+
return docs.map((d) => ({
|
|
1005
|
+
collection: d.collectionName,
|
|
1006
|
+
path: d.filePath,
|
|
1007
|
+
title: d.title,
|
|
1008
|
+
tags: d.tags
|
|
1009
|
+
}));
|
|
1010
|
+
}
|
|
1011
|
+
const queryTerms = tokenize(term);
|
|
1012
|
+
if (queryTerms.length === 0) {
|
|
1013
|
+
return docs.map((d) => ({
|
|
1014
|
+
collection: d.collectionName,
|
|
1015
|
+
path: d.filePath,
|
|
1016
|
+
title: d.title,
|
|
1017
|
+
tags: d.tags
|
|
1018
|
+
}));
|
|
1019
|
+
}
|
|
1020
|
+
const docTokenSets = docs.map(
|
|
1021
|
+
(doc) => /* @__PURE__ */ new Set([...doc.fields.title, ...doc.fields.tags, ...doc.fields.collection, ...doc.fields.body])
|
|
1022
|
+
);
|
|
1023
|
+
const N = docs.length;
|
|
1024
|
+
const idf = /* @__PURE__ */ new Map();
|
|
1025
|
+
for (const qt of queryTerms) {
|
|
1026
|
+
let docFreq = 0;
|
|
1027
|
+
for (const tokenSet of docTokenSets) {
|
|
1028
|
+
if (tokenSet.has(qt)) docFreq++;
|
|
1195
1029
|
}
|
|
1030
|
+
idf.set(qt, Math.log((N - docFreq + 0.5) / (docFreq + 0.5) + 1));
|
|
1196
1031
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1032
|
+
const avgLens = {
|
|
1033
|
+
title: docs.reduce((sum, d) => sum + d.fields.title.length, 0) / (N || 1),
|
|
1034
|
+
tags: docs.reduce((sum, d) => sum + d.fields.tags.length, 0) / (N || 1),
|
|
1035
|
+
collection: docs.reduce((sum, d) => sum + d.fields.collection.length, 0) / (N || 1),
|
|
1036
|
+
body: docs.reduce((sum, d) => sum + d.fields.body.length, 0) / (N || 1)
|
|
1037
|
+
};
|
|
1038
|
+
const scored = [];
|
|
1039
|
+
for (const doc of docs) {
|
|
1040
|
+
const titleScore = bm25FieldScore(queryTerms, doc.fields.title, avgLens.title, idf) * FIELD_WEIGHTS.title;
|
|
1041
|
+
const tagsScore = bm25FieldScore(queryTerms, doc.fields.tags, avgLens.tags, idf) * FIELD_WEIGHTS.tags;
|
|
1042
|
+
const collScore = bm25FieldScore(queryTerms, doc.fields.collection, avgLens.collection, idf) * FIELD_WEIGHTS.collection;
|
|
1043
|
+
const bodyScore = bm25FieldScore(queryTerms, doc.fields.body, avgLens.body, idf) * FIELD_WEIGHTS.body;
|
|
1044
|
+
const total = titleScore + tagsScore + collScore + bodyScore;
|
|
1045
|
+
if (total > 0) {
|
|
1046
|
+
scored.push({ doc, score: total });
|
|
1202
1047
|
}
|
|
1203
1048
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
var import_remark_parse = __toESM(require("remark-parse"), 1);
|
|
1213
|
-
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
1214
|
-
var import_remark_rehype = __toESM(require("remark-rehype"), 1);
|
|
1215
|
-
var import_rehype_slug = __toESM(require("rehype-slug"), 1);
|
|
1216
|
-
var import_rehype = __toESM(require("@shikijs/rehype"), 1);
|
|
1217
|
-
var import_rehype_stringify = __toESM(require("rehype-stringify"), 1);
|
|
1218
|
-
var import_unist_util_visit = require("unist-util-visit");
|
|
1219
|
-
var import_hast_util_to_string = require("hast-util-to-string");
|
|
1220
|
-
var LANG_ALIASES = {
|
|
1221
|
-
"c#": "csharp",
|
|
1222
|
-
cs: "csharp",
|
|
1223
|
-
"c++": "cpp",
|
|
1224
|
-
cxx: "cpp",
|
|
1225
|
-
hs: "haskell",
|
|
1226
|
-
ex: "elixir"
|
|
1227
|
-
};
|
|
1228
|
-
function rehypeCollectToc(toc) {
|
|
1229
|
-
return (tree) => {
|
|
1230
|
-
(0, import_unist_util_visit.visit)(tree, "element", (node) => {
|
|
1231
|
-
if (node.tagName !== "h2" && node.tagName !== "h3") return;
|
|
1232
|
-
const id = node.properties?.id;
|
|
1233
|
-
if (!id) return;
|
|
1234
|
-
toc.push({ slug: String(id), text: (0, import_hast_util_to_string.toString)(node), depth: node.tagName === "h2" ? 2 : 3 });
|
|
1235
|
-
});
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
function rehypeStripLeadingH1() {
|
|
1239
|
-
return (tree) => {
|
|
1240
|
-
let removed = false;
|
|
1241
|
-
(0, import_unist_util_visit.visit)(tree, "element", (node, index, parent) => {
|
|
1242
|
-
if (!removed && node.tagName === "h1" && parent && index != null) {
|
|
1243
|
-
parent.children.splice(index, 1);
|
|
1244
|
-
removed = true;
|
|
1245
|
-
return [import_unist_util_visit.SKIP, index];
|
|
1246
|
-
}
|
|
1247
|
-
});
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
function rehypeMarkMermaid() {
|
|
1251
|
-
return (tree) => {
|
|
1252
|
-
(0, import_unist_util_visit.visit)(tree, "element", (node) => {
|
|
1253
|
-
if (node.tagName !== "pre") return;
|
|
1254
|
-
const code = node.children.find((c) => c.type === "element" && c.tagName === "code");
|
|
1255
|
-
const cls = code?.properties?.className ?? [];
|
|
1256
|
-
if (!code || !cls.includes("language-mermaid")) return;
|
|
1257
|
-
const source = (0, import_hast_util_to_string.toString)(code);
|
|
1258
|
-
node.properties = { className: ["mermaid"] };
|
|
1259
|
-
node.children = [{ type: "text", value: source }];
|
|
1260
|
-
});
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
|
-
async function renderArticle(body) {
|
|
1264
|
-
const toc = [];
|
|
1265
|
-
const file = await (0, import_unified.unified)().use(import_remark_parse.default).use(import_remark_gfm.default).use(import_remark_rehype.default).use(import_rehype_slug.default).use(rehypeCollectToc, toc).use(rehypeStripLeadingH1).use(rehypeMarkMermaid).use(import_rehype.default, {
|
|
1266
|
-
themes: { light: "github-light", dark: "github-dark" },
|
|
1267
|
-
defaultColor: false,
|
|
1268
|
-
langAlias: LANG_ALIASES,
|
|
1269
|
-
fallbackLanguage: "plaintext"
|
|
1270
|
-
}).use(import_rehype_stringify.default).process(body);
|
|
1271
|
-
return { html: String(file), toc };
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
// src/site.ts
|
|
1275
|
-
init_errors();
|
|
1276
|
-
var isStatic = () => process.env.DIFFWIKI_STATIC === "1";
|
|
1277
|
-
function toTreeNodes(coll, nodes) {
|
|
1278
|
-
return nodes.map(
|
|
1279
|
-
(n) => n.children ? {
|
|
1280
|
-
name: n.name,
|
|
1281
|
-
title: n.title ?? n.name,
|
|
1282
|
-
path: n.slug ? `/${coll}/${n.slug}` : void 0,
|
|
1283
|
-
children: toTreeNodes(coll, n.children)
|
|
1284
|
-
} : { name: n.name, title: n.title ?? n.name, path: `/${coll}/${n.slug}` }
|
|
1285
|
-
);
|
|
1286
|
-
}
|
|
1287
|
-
async function gitInfo(e) {
|
|
1288
|
-
if (isStatic()) {
|
|
1289
|
-
if (e.type === "external") console.warn(`[diffwiki] static build: omitting branch info for "${e.name}"`);
|
|
1290
|
-
return {};
|
|
1291
|
-
}
|
|
1292
|
-
const s = await collectionGitStatus(e);
|
|
1293
|
-
return s ? { branch: s.branch, behind: s.hasUpstream ? s.behind : void 0 } : {};
|
|
1294
|
-
}
|
|
1295
|
-
async function buildCollections() {
|
|
1296
|
-
const entries = await listCollections();
|
|
1297
|
-
return Promise.all(
|
|
1298
|
-
entries.map(async (e) => ({
|
|
1299
|
-
name: e.name,
|
|
1300
|
-
type: e.type,
|
|
1301
|
-
path: e.path,
|
|
1302
|
-
...await gitInfo(e)
|
|
1303
|
-
}))
|
|
1304
|
-
);
|
|
1305
|
-
}
|
|
1306
|
-
async function buildNavTree() {
|
|
1307
|
-
const entries = await listCollections();
|
|
1308
|
-
return Promise.all(
|
|
1309
|
-
entries.map(async (e) => ({
|
|
1310
|
-
collection: { name: e.name, type: e.type, path: e.path, ...await gitInfo(e) },
|
|
1311
|
-
nodes: toTreeNodes(e.name, await listArticleTree(e.name))
|
|
1312
|
-
}))
|
|
1313
|
-
);
|
|
1314
|
-
}
|
|
1315
|
-
function findNode(nodes, slug) {
|
|
1316
|
-
for (const n of nodes) {
|
|
1317
|
-
if (n.slug === slug) return n;
|
|
1318
|
-
if (n.children) {
|
|
1319
|
-
const found = findNode(n.children, slug);
|
|
1320
|
-
if (found) return found;
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
return void 0;
|
|
1324
|
-
}
|
|
1325
|
-
async function resolvePage(coll, slug) {
|
|
1326
|
-
try {
|
|
1327
|
-
const art = await readArticle(coll, slug);
|
|
1328
|
-
const { html, toc } = await renderArticle(art.body);
|
|
1329
|
-
return {
|
|
1330
|
-
kind: "doc",
|
|
1331
|
-
coll: art.coll,
|
|
1332
|
-
slug: art.slug,
|
|
1333
|
-
title: art.title,
|
|
1334
|
-
tags: art.tags,
|
|
1335
|
-
html,
|
|
1336
|
-
toc,
|
|
1337
|
-
path: `/${art.coll}/${art.slug}`
|
|
1338
|
-
};
|
|
1339
|
-
} catch (err) {
|
|
1340
|
-
if (err instanceof CollectionNotFoundError) return null;
|
|
1341
|
-
if (!(err instanceof ArticleNotFoundError)) throw err;
|
|
1342
|
-
let nodes;
|
|
1343
|
-
try {
|
|
1344
|
-
nodes = await listArticleTree(coll);
|
|
1345
|
-
} catch (e) {
|
|
1346
|
-
if (e instanceof CollectionNotFoundError) return null;
|
|
1347
|
-
throw e;
|
|
1348
|
-
}
|
|
1349
|
-
const folder = slug ? findNode(nodes, slug) : { title: void 0, children: nodes };
|
|
1350
|
-
if (!folder?.children) return null;
|
|
1351
|
-
const entries = folder.children.map((n) => ({
|
|
1352
|
-
name: n.name,
|
|
1353
|
-
title: n.title ?? n.name,
|
|
1354
|
-
path: `/${coll}/${n.slug ?? n.name}`,
|
|
1355
|
-
isDir: Array.isArray(n.children)
|
|
1356
|
-
}));
|
|
1357
|
-
return {
|
|
1358
|
-
kind: "listing",
|
|
1359
|
-
coll,
|
|
1360
|
-
slug,
|
|
1361
|
-
title: folder.title ?? (slug ? slug.split("/").pop() ?? slug : coll),
|
|
1362
|
-
entries
|
|
1363
|
-
};
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
// src/query.ts
|
|
1368
|
-
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
1369
|
-
var import_node_path7 = __toESM(require("path"), 1);
|
|
1370
|
-
init_collections();
|
|
1371
|
-
init_errors();
|
|
1372
|
-
init_logger();
|
|
1373
|
-
init_host();
|
|
1374
|
-
init_registry2();
|
|
1375
|
-
init_types();
|
|
1376
|
-
|
|
1377
|
-
// src/bm25.ts
|
|
1378
|
-
var K1 = 1.5;
|
|
1379
|
-
var B = 0.75;
|
|
1380
|
-
var FIELD_WEIGHTS = { title: 3, tags: 2, collection: 1.5, body: 1 };
|
|
1381
|
-
function tokenize(text) {
|
|
1382
|
-
return text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 0);
|
|
1383
|
-
}
|
|
1384
|
-
function termFreqs(tokens) {
|
|
1385
|
-
const freqs = /* @__PURE__ */ new Map();
|
|
1386
|
-
for (const t of tokens) freqs.set(t, (freqs.get(t) ?? 0) + 1);
|
|
1387
|
-
return freqs;
|
|
1388
|
-
}
|
|
1389
|
-
function bm25FieldScore(queryTerms, fieldTokens, avgFieldLen, idf) {
|
|
1390
|
-
const tf = termFreqs(fieldTokens);
|
|
1391
|
-
const dl = fieldTokens.length;
|
|
1392
|
-
const avgDl = avgFieldLen || 1;
|
|
1393
|
-
let score = 0;
|
|
1394
|
-
for (const term of queryTerms) {
|
|
1395
|
-
const freq = tf.get(term) ?? 0;
|
|
1396
|
-
if (freq === 0) continue;
|
|
1397
|
-
const termIdf = idf.get(term) ?? 0;
|
|
1398
|
-
const numerator = freq * (K1 + 1);
|
|
1399
|
-
const denominator = freq + K1 * (1 - B + B * (dl / avgDl));
|
|
1400
|
-
score += termIdf * (numerator / denominator);
|
|
1401
|
-
}
|
|
1402
|
-
return score;
|
|
1403
|
-
}
|
|
1404
|
-
function rankDocs(term, docs) {
|
|
1405
|
-
const queryTerms = tokenize(term);
|
|
1406
|
-
if (queryTerms.length === 0) return docs.map((d) => ({ ...d }));
|
|
1407
|
-
const N = docs.length;
|
|
1408
|
-
const docTokenSets = docs.map(
|
|
1409
|
-
(d) => /* @__PURE__ */ new Set([...d.fields.title, ...d.fields.tags, ...d.fields.collection, ...d.fields.body])
|
|
1410
|
-
);
|
|
1411
|
-
const idf = /* @__PURE__ */ new Map();
|
|
1412
|
-
for (const qt of queryTerms) {
|
|
1413
|
-
let docFreq = 0;
|
|
1414
|
-
for (const set of docTokenSets) if (set.has(qt)) docFreq++;
|
|
1415
|
-
idf.set(qt, Math.log((N - docFreq + 0.5) / (docFreq + 0.5) + 1));
|
|
1416
|
-
}
|
|
1417
|
-
const avg = (sel) => docs.reduce((s, d) => s + sel(d), 0) / (N || 1);
|
|
1418
|
-
const avgLens = {
|
|
1419
|
-
title: avg((d) => d.fields.title.length),
|
|
1420
|
-
tags: avg((d) => d.fields.tags.length),
|
|
1421
|
-
collection: avg((d) => d.fields.collection.length),
|
|
1422
|
-
body: avg((d) => d.fields.body.length)
|
|
1423
|
-
};
|
|
1424
|
-
const scored = [];
|
|
1425
|
-
for (const d of docs) {
|
|
1426
|
-
const total = bm25FieldScore(queryTerms, d.fields.title, avgLens.title, idf) * FIELD_WEIGHTS.title + bm25FieldScore(queryTerms, d.fields.tags, avgLens.tags, idf) * FIELD_WEIGHTS.tags + bm25FieldScore(queryTerms, d.fields.collection, avgLens.collection, idf) * FIELD_WEIGHTS.collection + bm25FieldScore(queryTerms, d.fields.body, avgLens.body, idf) * FIELD_WEIGHTS.body;
|
|
1427
|
-
if (total > 0) scored.push({ ...d, score: total });
|
|
1428
|
-
}
|
|
1429
|
-
scored.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
1430
|
-
return scored;
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
// src/query.ts
|
|
1434
|
-
var log = getLogger("query");
|
|
1435
|
-
async function collectMarkdownFiles(dir) {
|
|
1436
|
-
let entries;
|
|
1437
|
-
try {
|
|
1438
|
-
entries = await import_promises8.default.readdir(dir, { withFileTypes: true });
|
|
1439
|
-
} catch {
|
|
1440
|
-
return [];
|
|
1441
|
-
}
|
|
1442
|
-
const files = [];
|
|
1443
|
-
for (const entry of entries) {
|
|
1444
|
-
const full = import_node_path7.default.join(dir, entry.name);
|
|
1445
|
-
if (entry.isDirectory()) {
|
|
1446
|
-
files.push(...await collectMarkdownFiles(full));
|
|
1447
|
-
} else if (entry.isFile() && /\.mdx?$/.test(entry.name)) {
|
|
1448
|
-
files.push(full);
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
return files;
|
|
1452
|
-
}
|
|
1453
|
-
async function nativeSearch(term, collections, collection) {
|
|
1454
|
-
let targets = collections;
|
|
1455
|
-
if (collection) {
|
|
1456
|
-
const one = collections.find((c) => c.name === collection);
|
|
1457
|
-
if (!one) throw new CollectionNotFoundError(collection);
|
|
1458
|
-
targets = [one];
|
|
1459
|
-
}
|
|
1460
|
-
const docs = [];
|
|
1461
|
-
for (const entry of targets) {
|
|
1462
|
-
for (const full of await collectMarkdownFiles(entry.path)) {
|
|
1463
|
-
const fallbackTitle = import_node_path7.default.basename(full).replace(/\.mdx?$/, "");
|
|
1464
|
-
let title = fallbackTitle;
|
|
1465
|
-
let tags = [];
|
|
1466
|
-
let body = "";
|
|
1467
|
-
try {
|
|
1468
|
-
const parsed = parseArticle(await import_promises8.default.readFile(full, "utf8"));
|
|
1469
|
-
if (parsed.title) title = parsed.title;
|
|
1470
|
-
tags = parsed.tags;
|
|
1471
|
-
body = parsed.body;
|
|
1472
|
-
} catch {
|
|
1473
|
-
}
|
|
1474
|
-
docs.push({
|
|
1475
|
-
collectionName: entry.name,
|
|
1476
|
-
filePath: full,
|
|
1477
|
-
title,
|
|
1478
|
-
tags,
|
|
1479
|
-
fields: {
|
|
1480
|
-
title: tokenize(title),
|
|
1481
|
-
tags: tokenize(tags.join(" ")),
|
|
1482
|
-
collection: tokenize(entry.name),
|
|
1483
|
-
body: tokenize(body)
|
|
1484
|
-
}
|
|
1485
|
-
});
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
return rankDocs(term, docs).map((d) => ({
|
|
1489
|
-
collection: d.collectionName,
|
|
1490
|
-
path: d.filePath,
|
|
1491
|
-
title: d.title,
|
|
1492
|
-
tags: d.tags,
|
|
1493
|
-
...d.score === void 0 ? {} : { score: d.score }
|
|
1494
|
-
}));
|
|
1049
|
+
scored.sort((a, b) => b.score - a.score);
|
|
1050
|
+
return scored.map((s) => ({
|
|
1051
|
+
collection: s.doc.collectionName,
|
|
1052
|
+
path: s.doc.filePath,
|
|
1053
|
+
title: s.doc.title,
|
|
1054
|
+
tags: s.doc.tags,
|
|
1055
|
+
score: s.score
|
|
1056
|
+
}));
|
|
1495
1057
|
}
|
|
1496
1058
|
async function resolveDefaultEngine() {
|
|
1497
1059
|
const config = await readConfig();
|
|
@@ -1547,64 +1109,15 @@ async function query(term, opts) {
|
|
|
1547
1109
|
return (await search(term, opts)).hits;
|
|
1548
1110
|
}
|
|
1549
1111
|
|
|
1550
|
-
// src/search.ts
|
|
1551
|
-
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
1552
|
-
var import_node_path8 = __toESM(require("path"), 1);
|
|
1553
|
-
init_collections();
|
|
1554
|
-
async function readArticleParts(collDir, slug) {
|
|
1555
|
-
for (const ext of [".mdx", ".md"]) {
|
|
1556
|
-
try {
|
|
1557
|
-
const parsed = parseArticle(await import_promises9.default.readFile(import_node_path8.default.join(collDir, `${slug}${ext}`), "utf8"));
|
|
1558
|
-
return { tags: parsed.tags, body: parsed.body };
|
|
1559
|
-
} catch {
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
return { tags: [], body: "" };
|
|
1563
|
-
}
|
|
1564
|
-
async function flatten(coll, collDir, nodes, out) {
|
|
1565
|
-
for (const n of nodes) {
|
|
1566
|
-
if (n.slug && !n.children) {
|
|
1567
|
-
const title = n.title ?? n.name;
|
|
1568
|
-
const { tags, body } = await readArticleParts(collDir, n.slug);
|
|
1569
|
-
out.push({
|
|
1570
|
-
collection: coll,
|
|
1571
|
-
slug: n.slug,
|
|
1572
|
-
title,
|
|
1573
|
-
tags,
|
|
1574
|
-
fields: {
|
|
1575
|
-
title: tokenize(title),
|
|
1576
|
-
tags: tokenize(tags.join(" ")),
|
|
1577
|
-
collection: tokenize(coll),
|
|
1578
|
-
body: tokenize(body)
|
|
1579
|
-
}
|
|
1580
|
-
});
|
|
1581
|
-
}
|
|
1582
|
-
if (n.children) await flatten(coll, collDir, n.children, out);
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
async function buildSearchIndex(collection) {
|
|
1586
|
-
const entries = collection ? (await listCollections()).filter((c) => c.name === collection) : await listCollections();
|
|
1587
|
-
const out = [];
|
|
1588
|
-
for (const e of entries) {
|
|
1589
|
-
try {
|
|
1590
|
-
const collEntry = await findCollection(e.name);
|
|
1591
|
-
const collDir = import_node_path8.default.resolve(collEntry?.path ?? e.path);
|
|
1592
|
-
await flatten(e.name, collDir, await listArticleTree(e.name), out);
|
|
1593
|
-
} catch {
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
return out;
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
1112
|
// src/doctor.ts
|
|
1600
|
-
var
|
|
1113
|
+
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
1601
1114
|
init_paths();
|
|
1602
1115
|
init_registry();
|
|
1603
1116
|
init_collections();
|
|
1604
1117
|
|
|
1605
1118
|
// src/plugins/manager.ts
|
|
1606
|
-
var
|
|
1607
|
-
var
|
|
1119
|
+
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
1120
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
1608
1121
|
init_paths();
|
|
1609
1122
|
init_errors();
|
|
1610
1123
|
init_collections();
|
|
@@ -1612,14 +1125,14 @@ init_registry2();
|
|
|
1612
1125
|
init_host();
|
|
1613
1126
|
|
|
1614
1127
|
// src/plugins/sdk.ts
|
|
1615
|
-
var
|
|
1616
|
-
var
|
|
1128
|
+
var import_node_child_process3 = require("child_process");
|
|
1129
|
+
var import_node_util2 = require("util");
|
|
1617
1130
|
var import_node_fs = require("fs");
|
|
1618
|
-
var
|
|
1131
|
+
var import_node_path6 = require("path");
|
|
1619
1132
|
var import_node_url = require("url");
|
|
1620
|
-
var
|
|
1133
|
+
var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process3.execFile);
|
|
1621
1134
|
async function runProcess(file, args, opts) {
|
|
1622
|
-
const { stdout, stderr } = await
|
|
1135
|
+
const { stdout, stderr } = await execFileAsync2(file, args, {
|
|
1623
1136
|
env: opts?.env,
|
|
1624
1137
|
timeout: opts?.timeout,
|
|
1625
1138
|
// Large: qmd emits multi-MB JSON search payloads that overflow the default 1 MB.
|
|
@@ -1631,7 +1144,7 @@ async function runProcess(file, args, opts) {
|
|
|
1631
1144
|
// src/plugins/manager.ts
|
|
1632
1145
|
async function readPackageJson(file) {
|
|
1633
1146
|
try {
|
|
1634
|
-
return JSON.parse(await
|
|
1147
|
+
return JSON.parse(await import_promises8.default.readFile(file, "utf8"));
|
|
1635
1148
|
} catch {
|
|
1636
1149
|
return null;
|
|
1637
1150
|
}
|
|
@@ -1647,7 +1160,7 @@ function binOf(manifest) {
|
|
|
1647
1160
|
async function pluginManifestDirs(nodeModules) {
|
|
1648
1161
|
let entries;
|
|
1649
1162
|
try {
|
|
1650
|
-
entries = await
|
|
1163
|
+
entries = await import_promises8.default.readdir(nodeModules);
|
|
1651
1164
|
} catch {
|
|
1652
1165
|
return [];
|
|
1653
1166
|
}
|
|
@@ -1657,39 +1170,39 @@ async function pluginManifestDirs(nodeModules) {
|
|
|
1657
1170
|
if (entry.startsWith("@")) {
|
|
1658
1171
|
let scoped;
|
|
1659
1172
|
try {
|
|
1660
|
-
scoped = await
|
|
1173
|
+
scoped = await import_promises8.default.readdir(import_node_path7.default.join(nodeModules, entry));
|
|
1661
1174
|
} catch {
|
|
1662
1175
|
continue;
|
|
1663
1176
|
}
|
|
1664
1177
|
for (const pkg of scoped) {
|
|
1665
1178
|
if (pkg.startsWith(".")) continue;
|
|
1666
|
-
dirs.push(
|
|
1179
|
+
dirs.push(import_node_path7.default.join(nodeModules, entry, pkg));
|
|
1667
1180
|
}
|
|
1668
1181
|
} else {
|
|
1669
|
-
dirs.push(
|
|
1182
|
+
dirs.push(import_node_path7.default.join(nodeModules, entry));
|
|
1670
1183
|
}
|
|
1671
1184
|
}
|
|
1672
1185
|
return dirs;
|
|
1673
1186
|
}
|
|
1674
1187
|
async function ensurePluginRoot() {
|
|
1675
1188
|
const dir = pluginsDir();
|
|
1676
|
-
await
|
|
1677
|
-
const pkgPath =
|
|
1189
|
+
await import_promises8.default.mkdir(dir, { recursive: true });
|
|
1190
|
+
const pkgPath = import_node_path7.default.join(dir, "package.json");
|
|
1678
1191
|
if (await readPackageJson(pkgPath) === null) {
|
|
1679
1192
|
const pkg = { name: "diffwiki-plugins", private: true, version: "0.0.0" };
|
|
1680
|
-
await
|
|
1193
|
+
await import_promises8.default.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
1681
1194
|
`, "utf8");
|
|
1682
1195
|
}
|
|
1683
1196
|
return dir;
|
|
1684
1197
|
}
|
|
1685
1198
|
async function discoverSearchPackage(dir) {
|
|
1686
|
-
const nodeModules =
|
|
1199
|
+
const nodeModules = import_node_path7.default.join(dir, "node_modules");
|
|
1687
1200
|
for (const pkgDir of await pluginManifestDirs(nodeModules)) {
|
|
1688
|
-
const manifest = await readPackageJson(
|
|
1201
|
+
const manifest = await readPackageJson(import_node_path7.default.join(pkgDir, "package.json"));
|
|
1689
1202
|
if (!manifest?.name || manifest.diffwiki?.kind !== "search") continue;
|
|
1690
1203
|
const bin = binOf(manifest);
|
|
1691
1204
|
if (!bin) continue;
|
|
1692
|
-
return { name: manifest.name, version: manifest.version, binAbs:
|
|
1205
|
+
return { name: manifest.name, version: manifest.version, binAbs: import_node_path7.default.resolve(pkgDir, bin) };
|
|
1693
1206
|
}
|
|
1694
1207
|
return null;
|
|
1695
1208
|
}
|
|
@@ -1812,7 +1325,7 @@ init_host();
|
|
|
1812
1325
|
init_types();
|
|
1813
1326
|
async function exists(target) {
|
|
1814
1327
|
try {
|
|
1815
|
-
await
|
|
1328
|
+
await import_promises9.default.access(target);
|
|
1816
1329
|
return true;
|
|
1817
1330
|
} catch {
|
|
1818
1331
|
return false;
|
|
@@ -1920,6 +1433,226 @@ async function appendPluginDiagnostics(out, config) {
|
|
|
1920
1433
|
// src/index.ts
|
|
1921
1434
|
init_logger();
|
|
1922
1435
|
|
|
1436
|
+
// src/browse.ts
|
|
1437
|
+
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
1438
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
1439
|
+
init_collections();
|
|
1440
|
+
init_errors();
|
|
1441
|
+
var INDEX_RE = /^(index|readme)\.mdx?$/i;
|
|
1442
|
+
function buildArticleTree(relPaths) {
|
|
1443
|
+
const root = {};
|
|
1444
|
+
for (const raw of relPaths) {
|
|
1445
|
+
const rel = raw.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1446
|
+
if (!rel) continue;
|
|
1447
|
+
const segs = rel.split("/");
|
|
1448
|
+
let cur = root;
|
|
1449
|
+
segs.forEach((seg, i) => {
|
|
1450
|
+
if (i === segs.length - 1) {
|
|
1451
|
+
if (!(seg in cur)) cur[seg] = null;
|
|
1452
|
+
} else {
|
|
1453
|
+
if (cur[seg] === null || !(seg in cur)) cur[seg] = {};
|
|
1454
|
+
cur = cur[seg];
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
const stripExt = (f) => f.replace(/\.(mdx?)$/, "");
|
|
1459
|
+
const walk = (trie, parents) => {
|
|
1460
|
+
const entries = Object.entries(trie);
|
|
1461
|
+
const branches = entries.filter(([, v]) => v !== null);
|
|
1462
|
+
const leaves = entries.filter(([, v]) => v === null).map(([k]) => k).filter((f) => !INDEX_RE.test(f));
|
|
1463
|
+
branches.sort(([a], [b]) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
1464
|
+
leaves.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
1465
|
+
const branchNodes = branches.map(([seg, sub]) => ({
|
|
1466
|
+
name: seg,
|
|
1467
|
+
title: seg,
|
|
1468
|
+
// Folders are navigable to their index page (an authored index.md/README,
|
|
1469
|
+
// else a generated listing).
|
|
1470
|
+
slug: [...parents, seg].join("/"),
|
|
1471
|
+
children: walk(sub, [...parents, seg])
|
|
1472
|
+
}));
|
|
1473
|
+
const leafNodes = leaves.map((file) => {
|
|
1474
|
+
const nameNoExt = stripExt(file);
|
|
1475
|
+
return { name: nameNoExt, title: nameNoExt, slug: [...parents, nameNoExt].join("/") };
|
|
1476
|
+
});
|
|
1477
|
+
return [...branchNodes, ...leafNodes];
|
|
1478
|
+
};
|
|
1479
|
+
return walk(root, []);
|
|
1480
|
+
}
|
|
1481
|
+
async function collectRelPaths(dir, rel = "") {
|
|
1482
|
+
let dirents;
|
|
1483
|
+
try {
|
|
1484
|
+
dirents = await import_promises10.default.readdir(dir, { withFileTypes: true });
|
|
1485
|
+
} catch {
|
|
1486
|
+
return [];
|
|
1487
|
+
}
|
|
1488
|
+
const out = [];
|
|
1489
|
+
for (const d of dirents) {
|
|
1490
|
+
if (d.name.startsWith(".")) continue;
|
|
1491
|
+
const childRel = rel ? `${rel}/${d.name}` : d.name;
|
|
1492
|
+
if (d.isDirectory()) {
|
|
1493
|
+
out.push(...await collectRelPaths(import_node_path8.default.join(dir, d.name), childRel));
|
|
1494
|
+
} else if (/\.(mdx?)$/.test(d.name)) {
|
|
1495
|
+
out.push(childRel);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
return out;
|
|
1499
|
+
}
|
|
1500
|
+
async function readdirSafe(dir) {
|
|
1501
|
+
try {
|
|
1502
|
+
return await import_promises10.default.readdir(dir);
|
|
1503
|
+
} catch {
|
|
1504
|
+
return [];
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
function pickIndexFile(names) {
|
|
1508
|
+
const rank = (n) => {
|
|
1509
|
+
const lower = n.toLowerCase();
|
|
1510
|
+
const base = lower.startsWith("index") ? 0 : 1;
|
|
1511
|
+
const ext = lower.endsWith(".mdx") ? 0 : 1;
|
|
1512
|
+
return base * 2 + ext;
|
|
1513
|
+
};
|
|
1514
|
+
return names.filter((n) => INDEX_RE.test(n)).sort((a, b) => rank(a) - rank(b))[0];
|
|
1515
|
+
}
|
|
1516
|
+
async function cheapTitle(absPath) {
|
|
1517
|
+
let handle;
|
|
1518
|
+
try {
|
|
1519
|
+
handle = await import_promises10.default.open(absPath, "r");
|
|
1520
|
+
const buf = Buffer.alloc(512);
|
|
1521
|
+
const { bytesRead } = await handle.read(buf, 0, 512, 0);
|
|
1522
|
+
const snippet = buf.subarray(0, bytesRead).toString("utf8");
|
|
1523
|
+
const m = snippet.match(/^---[\s\S]*?^title:\s*(.+)$/m);
|
|
1524
|
+
if (m) return m[1].trim().replace(/^["']|["']$/g, "");
|
|
1525
|
+
} catch {
|
|
1526
|
+
} finally {
|
|
1527
|
+
await handle?.close();
|
|
1528
|
+
}
|
|
1529
|
+
return void 0;
|
|
1530
|
+
}
|
|
1531
|
+
async function enrichTitles(nodes, collDir) {
|
|
1532
|
+
return Promise.all(
|
|
1533
|
+
nodes.map(async (node) => {
|
|
1534
|
+
if (node.children) {
|
|
1535
|
+
const children = await enrichTitles(node.children, collDir);
|
|
1536
|
+
let title = node.title;
|
|
1537
|
+
if (node.slug) {
|
|
1538
|
+
const dir = import_node_path8.default.join(collDir, node.slug);
|
|
1539
|
+
const idx = pickIndexFile(await readdirSafe(dir));
|
|
1540
|
+
if (idx) title = await cheapTitle(import_node_path8.default.join(dir, idx)) ?? title;
|
|
1541
|
+
}
|
|
1542
|
+
return { ...node, title, children };
|
|
1543
|
+
}
|
|
1544
|
+
for (const ext of [".mdx", ".md"]) {
|
|
1545
|
+
const title = await cheapTitle(import_node_path8.default.join(collDir, `${node.slug}${ext}`));
|
|
1546
|
+
if (title) return { ...node, title };
|
|
1547
|
+
}
|
|
1548
|
+
return node;
|
|
1549
|
+
})
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
async function listArticleTree(coll) {
|
|
1553
|
+
const entry = await findCollection(coll);
|
|
1554
|
+
if (!entry) throw new CollectionNotFoundError(coll);
|
|
1555
|
+
const rels = await collectRelPaths(entry.path);
|
|
1556
|
+
return enrichTitles(buildArticleTree(rels), import_node_path8.default.resolve(entry.path));
|
|
1557
|
+
}
|
|
1558
|
+
async function readArticle(coll, slug) {
|
|
1559
|
+
const entry = await findCollection(coll);
|
|
1560
|
+
if (!entry) throw new CollectionNotFoundError(coll);
|
|
1561
|
+
const collDir = import_node_path8.default.resolve(entry.path);
|
|
1562
|
+
const normalized = slug.replace(/\\/g, "/");
|
|
1563
|
+
if (normalized.split("/").some((s) => s === "..")) {
|
|
1564
|
+
throw new InvalidTargetError(slug, "path traversal detected");
|
|
1565
|
+
}
|
|
1566
|
+
const safeSlug = normalized.split("/").filter((s) => s !== "" && s !== ".").join("/");
|
|
1567
|
+
const inJail = (p) => p === collDir || p.startsWith(collDir + import_node_path8.default.sep);
|
|
1568
|
+
let abs;
|
|
1569
|
+
for (const rel of safeSlug ? [`${safeSlug}.mdx`, `${safeSlug}.md`] : []) {
|
|
1570
|
+
const candidate = import_node_path8.default.resolve(collDir, rel);
|
|
1571
|
+
if (!inJail(candidate)) throw new InvalidTargetError(slug, "path traversal detected");
|
|
1572
|
+
try {
|
|
1573
|
+
await import_promises10.default.access(candidate);
|
|
1574
|
+
abs = candidate;
|
|
1575
|
+
break;
|
|
1576
|
+
} catch {
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
if (!abs) {
|
|
1580
|
+
const dir = import_node_path8.default.resolve(collDir, safeSlug);
|
|
1581
|
+
if (inJail(dir)) {
|
|
1582
|
+
const idx = pickIndexFile(await readdirSafe(dir));
|
|
1583
|
+
if (idx) abs = import_node_path8.default.join(dir, idx);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
if (!abs) throw new ArticleNotFoundError(`${coll}/${safeSlug}`);
|
|
1587
|
+
const parsed = parseArticle(await import_promises10.default.readFile(abs, "utf8"));
|
|
1588
|
+
const title = parsed.title?.trim() || (safeSlug ? safeSlug.split("/").pop() ?? safeSlug : coll);
|
|
1589
|
+
return { coll, slug: safeSlug, title, tags: parsed.tags, body: parsed.body, path: abs };
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// src/render.ts
|
|
1593
|
+
var import_unified = require("unified");
|
|
1594
|
+
var import_remark_parse = __toESM(require("remark-parse"), 1);
|
|
1595
|
+
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
1596
|
+
var import_remark_rehype = __toESM(require("remark-rehype"), 1);
|
|
1597
|
+
var import_rehype_slug = __toESM(require("rehype-slug"), 1);
|
|
1598
|
+
var import_rehype = __toESM(require("@shikijs/rehype"), 1);
|
|
1599
|
+
var import_rehype_stringify = __toESM(require("rehype-stringify"), 1);
|
|
1600
|
+
var import_unist_util_visit = require("unist-util-visit");
|
|
1601
|
+
var import_hast_util_to_string = require("hast-util-to-string");
|
|
1602
|
+
var LANG_ALIASES = {
|
|
1603
|
+
"c#": "csharp",
|
|
1604
|
+
cs: "csharp",
|
|
1605
|
+
"c++": "cpp",
|
|
1606
|
+
cxx: "cpp",
|
|
1607
|
+
hs: "haskell",
|
|
1608
|
+
ex: "elixir"
|
|
1609
|
+
};
|
|
1610
|
+
function rehypeCollectToc(toc) {
|
|
1611
|
+
return (tree) => {
|
|
1612
|
+
(0, import_unist_util_visit.visit)(tree, "element", (node) => {
|
|
1613
|
+
if (node.tagName !== "h2" && node.tagName !== "h3") return;
|
|
1614
|
+
const id = node.properties?.id;
|
|
1615
|
+
if (!id) return;
|
|
1616
|
+
toc.push({ slug: String(id), text: (0, import_hast_util_to_string.toString)(node), depth: node.tagName === "h2" ? 2 : 3 });
|
|
1617
|
+
});
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
function rehypeStripLeadingH1() {
|
|
1621
|
+
return (tree) => {
|
|
1622
|
+
let removed = false;
|
|
1623
|
+
(0, import_unist_util_visit.visit)(tree, "element", (node, index, parent) => {
|
|
1624
|
+
if (!removed && node.tagName === "h1" && parent && index != null) {
|
|
1625
|
+
parent.children.splice(index, 1);
|
|
1626
|
+
removed = true;
|
|
1627
|
+
return [import_unist_util_visit.SKIP, index];
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
function rehypeMarkMermaid() {
|
|
1633
|
+
return (tree) => {
|
|
1634
|
+
(0, import_unist_util_visit.visit)(tree, "element", (node) => {
|
|
1635
|
+
if (node.tagName !== "pre") return;
|
|
1636
|
+
const code = node.children.find((c) => c.type === "element" && c.tagName === "code");
|
|
1637
|
+
const cls = code?.properties?.className ?? [];
|
|
1638
|
+
if (!code || !cls.includes("language-mermaid")) return;
|
|
1639
|
+
const source = (0, import_hast_util_to_string.toString)(code);
|
|
1640
|
+
node.properties = { className: ["mermaid"] };
|
|
1641
|
+
node.children = [{ type: "text", value: source }];
|
|
1642
|
+
});
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
async function renderArticle(body) {
|
|
1646
|
+
const toc = [];
|
|
1647
|
+
const file = await (0, import_unified.unified)().use(import_remark_parse.default).use(import_remark_gfm.default).use(import_remark_rehype.default).use(import_rehype_slug.default).use(rehypeCollectToc, toc).use(rehypeStripLeadingH1).use(rehypeMarkMermaid).use(import_rehype.default, {
|
|
1648
|
+
themes: { light: "github-light", dark: "github-dark" },
|
|
1649
|
+
defaultColor: false,
|
|
1650
|
+
langAlias: LANG_ALIASES,
|
|
1651
|
+
fallbackLanguage: "plaintext"
|
|
1652
|
+
}).use(import_rehype_stringify.default).process(body);
|
|
1653
|
+
return { html: String(file), toc };
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1923
1656
|
// src/plugins/index.ts
|
|
1924
1657
|
init_host();
|
|
1925
1658
|
init_events();
|
|
@@ -1950,7 +1683,6 @@ init_registry2();
|
|
|
1950
1683
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1951
1684
|
0 && (module.exports = {
|
|
1952
1685
|
ArticleNotFoundError,
|
|
1953
|
-
CollectionAlreadyAddedError,
|
|
1954
1686
|
CollectionExistsError,
|
|
1955
1687
|
CollectionNotFoundError,
|
|
1956
1688
|
DiffwikiError,
|
|
@@ -1959,35 +1691,24 @@ init_registry2();
|
|
|
1959
1691
|
NoDefaultCollectionError,
|
|
1960
1692
|
PluginError,
|
|
1961
1693
|
REPO_CONFIG_FILE,
|
|
1962
|
-
WorktreeNotAllowedError,
|
|
1963
|
-
addExternalCollection,
|
|
1964
1694
|
addTags,
|
|
1965
1695
|
buildArticleTree,
|
|
1966
|
-
buildCollections,
|
|
1967
|
-
buildNavTree,
|
|
1968
|
-
buildSearchIndex,
|
|
1969
1696
|
collectionDir,
|
|
1970
|
-
collectionGitStatus,
|
|
1971
1697
|
collectionsDir,
|
|
1972
1698
|
configPath,
|
|
1973
1699
|
createArticle,
|
|
1974
1700
|
createCollection,
|
|
1975
|
-
currentBranch,
|
|
1976
1701
|
deregisterPlugin,
|
|
1977
1702
|
doctor,
|
|
1978
1703
|
emitPluginEvent,
|
|
1979
|
-
ensureGitRepo,
|
|
1980
1704
|
ensurePluginRoot,
|
|
1981
1705
|
findCollection,
|
|
1982
|
-
findCollectionById,
|
|
1983
1706
|
findEnabledPlugin,
|
|
1984
1707
|
findPluginRecord,
|
|
1985
1708
|
getConfigValue,
|
|
1986
1709
|
getLogger,
|
|
1987
|
-
gitToplevel,
|
|
1988
1710
|
initRepoWiki,
|
|
1989
1711
|
installPlugin,
|
|
1990
|
-
isLinkedWorktree,
|
|
1991
1712
|
listArticleTree,
|
|
1992
1713
|
listAvailablePlugins,
|
|
1993
1714
|
listCollections,
|
|
@@ -2002,7 +1723,6 @@ init_registry2();
|
|
|
2002
1723
|
pluginsDir,
|
|
2003
1724
|
pluginsRegistryPath,
|
|
2004
1725
|
query,
|
|
2005
|
-
rankDocs,
|
|
2006
1726
|
readArticle,
|
|
2007
1727
|
readConfig,
|
|
2008
1728
|
readPluginRegistry,
|
|
@@ -2016,24 +1736,17 @@ init_registry2();
|
|
|
2016
1736
|
removePlugin,
|
|
2017
1737
|
removeTags,
|
|
2018
1738
|
renderArticle,
|
|
2019
|
-
repoId,
|
|
2020
|
-
repoRemoteName,
|
|
2021
|
-
resolveCwdCollection,
|
|
2022
1739
|
resolveDefaultSearchMode,
|
|
2023
1740
|
resolveHome,
|
|
2024
1741
|
resolveLogLevel,
|
|
2025
|
-
resolvePage,
|
|
2026
1742
|
search,
|
|
2027
1743
|
serializeArticle,
|
|
2028
1744
|
setConfigValue,
|
|
2029
1745
|
setTags,
|
|
2030
1746
|
slugify,
|
|
2031
|
-
toTreeNodes,
|
|
2032
|
-
tokenize,
|
|
2033
1747
|
unregisterCollection,
|
|
2034
1748
|
updateArticleBody,
|
|
2035
1749
|
upsertPlugin,
|
|
2036
|
-
upstreamStatus,
|
|
2037
1750
|
writeConfig,
|
|
2038
1751
|
writePluginRegistry,
|
|
2039
1752
|
writeRegistry
|