diffwiki-core 0.14.0 → 0.15.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/bm25.cjs +6 -0
- package/dist/bm25.js +1 -1
- package/dist/chunk-6MW6KSS4.js +278 -0
- package/dist/{chunk-FTUF6IXS.js → chunk-TK2373AM.js} +6 -0
- package/dist/{chunk-7V2DIQNL.js → chunk-TXM4OGBA.js} +12 -3
- package/dist/{events-AVD3G5AX.js → events-K3MKWACA.js} +1 -1
- package/dist/frontmatter-ghMCpLNf.d.cts +585 -0
- package/dist/frontmatter-ghMCpLNf.d.ts +585 -0
- package/dist/index.cjs +303 -195
- package/dist/index.d.cts +69 -359
- package/dist/index.d.ts +69 -359
- package/dist/index.js +200 -189
- package/dist/plugin.cjs +134 -2
- package/dist/plugin.d.cts +54 -177
- package/dist/plugin.d.ts +54 -177
- package/dist/plugin.js +9 -3
- package/package.json +1 -1
- package/dist/chunk-EEETAETA.js +0 -145
package/dist/index.cjs
CHANGED
|
@@ -110,6 +110,9 @@ function configPath() {
|
|
|
110
110
|
function collectionsDir() {
|
|
111
111
|
return import_node_path.default.join(resolveHome(), "collections");
|
|
112
112
|
}
|
|
113
|
+
function templatesDir() {
|
|
114
|
+
return import_node_path.default.join(resolveHome(), "templates");
|
|
115
|
+
}
|
|
113
116
|
function collectionDir(name) {
|
|
114
117
|
return import_node_path.default.join(collectionsDir(), name);
|
|
115
118
|
}
|
|
@@ -134,7 +137,7 @@ function isMissing(err) {
|
|
|
134
137
|
}
|
|
135
138
|
async function readRegistry() {
|
|
136
139
|
try {
|
|
137
|
-
const parsed = JSON.parse(await
|
|
140
|
+
const parsed = JSON.parse(await import_promises2.default.readFile(registryPath(), "utf8"));
|
|
138
141
|
return { version: parsed.version ?? 1, collections: parsed.collections ?? [] };
|
|
139
142
|
} catch (err) {
|
|
140
143
|
if (isMissing(err)) return { version: 1, collections: [] };
|
|
@@ -142,8 +145,8 @@ async function readRegistry() {
|
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
147
|
async function writeRegistry(registry) {
|
|
145
|
-
await
|
|
146
|
-
await
|
|
148
|
+
await import_promises2.default.mkdir(resolveHome(), { recursive: true });
|
|
149
|
+
await import_promises2.default.writeFile(registryPath(), `${JSON.stringify(registry, null, 2)}
|
|
147
150
|
`, "utf8");
|
|
148
151
|
}
|
|
149
152
|
async function registerCollection(entry) {
|
|
@@ -161,11 +164,11 @@ async function unregisterCollection(name) {
|
|
|
161
164
|
registry.collections = registry.collections.filter((c) => c.name !== name);
|
|
162
165
|
await writeRegistry(registry);
|
|
163
166
|
}
|
|
164
|
-
var
|
|
167
|
+
var import_promises2;
|
|
165
168
|
var init_registry = __esm({
|
|
166
169
|
"src/registry.ts"() {
|
|
167
170
|
"use strict";
|
|
168
|
-
|
|
171
|
+
import_promises2 = __toESM(require("fs/promises"), 1);
|
|
169
172
|
init_paths();
|
|
170
173
|
}
|
|
171
174
|
});
|
|
@@ -176,7 +179,7 @@ function isMissing2(err) {
|
|
|
176
179
|
}
|
|
177
180
|
async function readPluginRegistry() {
|
|
178
181
|
try {
|
|
179
|
-
const parsed = JSON.parse(await
|
|
182
|
+
const parsed = JSON.parse(await import_promises3.default.readFile(pluginsRegistryPath(), "utf8"));
|
|
180
183
|
return { version: parsed.version ?? 1, plugins: parsed.plugins ?? [] };
|
|
181
184
|
} catch (err) {
|
|
182
185
|
if (isMissing2(err)) return { version: 1, plugins: [] };
|
|
@@ -184,8 +187,8 @@ async function readPluginRegistry() {
|
|
|
184
187
|
}
|
|
185
188
|
}
|
|
186
189
|
async function writePluginRegistry(registry) {
|
|
187
|
-
await
|
|
188
|
-
await
|
|
190
|
+
await import_promises3.default.mkdir(resolveHome(), { recursive: true });
|
|
191
|
+
await import_promises3.default.writeFile(pluginsRegistryPath(), `${JSON.stringify(registry, null, 2)}
|
|
189
192
|
`, "utf8");
|
|
190
193
|
}
|
|
191
194
|
async function upsertPlugin(record) {
|
|
@@ -216,11 +219,11 @@ async function findPluginRecord(name) {
|
|
|
216
219
|
const registry = await readPluginRegistry();
|
|
217
220
|
return registry.plugins.find((p) => p.name === name);
|
|
218
221
|
}
|
|
219
|
-
var
|
|
222
|
+
var import_promises3;
|
|
220
223
|
var init_registry2 = __esm({
|
|
221
224
|
"src/plugins/registry.ts"() {
|
|
222
225
|
"use strict";
|
|
223
|
-
|
|
226
|
+
import_promises3 = __toESM(require("fs/promises"), 1);
|
|
224
227
|
init_paths();
|
|
225
228
|
}
|
|
226
229
|
});
|
|
@@ -247,7 +250,7 @@ var init_logger = __esm({
|
|
|
247
250
|
// src/plugins/host.ts
|
|
248
251
|
async function invokePlugin(command, op, params, opts) {
|
|
249
252
|
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
250
|
-
const scope = opts?.name ?? (0,
|
|
253
|
+
const scope = opts?.name ?? (0, import_node_path3.basename)(command[1] ?? command[0] ?? "plugin");
|
|
251
254
|
return new Promise((resolve, reject) => {
|
|
252
255
|
const child = (0, import_node_child_process.spawn)(command[0], command.slice(1), {
|
|
253
256
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -351,7 +354,7 @@ function mapHits(result, collections) {
|
|
|
351
354
|
if (typeof h.collection !== "string" || typeof h.relPath !== "string") continue;
|
|
352
355
|
const title = typeof h.title === "string" ? h.title : h.relPath;
|
|
353
356
|
const coll = collections.find((c) => c.name === h.collection);
|
|
354
|
-
const abs = coll ?
|
|
357
|
+
const abs = coll ? import_node_path3.default.join(coll.path, h.relPath) : h.relPath;
|
|
355
358
|
out.push({
|
|
356
359
|
collection: h.collection,
|
|
357
360
|
path: abs,
|
|
@@ -359,7 +362,11 @@ function mapHits(result, collections) {
|
|
|
359
362
|
tags: Array.isArray(h.tags) ? h.tags.filter((t) => typeof t === "string") : [],
|
|
360
363
|
snippet: typeof h.snippet === "string" ? h.snippet : void 0,
|
|
361
364
|
score: typeof h.score === "number" ? h.score : void 0,
|
|
362
|
-
docid: typeof h.docid === "string" ? h.docid : void 0
|
|
365
|
+
docid: typeof h.docid === "string" ? h.docid : void 0,
|
|
366
|
+
rawChunk: typeof h.rawChunk === "string" ? h.rawChunk : void 0,
|
|
367
|
+
cleanedChunk: typeof h.cleanedChunk === "string" ? h.cleanedChunk : void 0,
|
|
368
|
+
line: typeof h.line === "number" ? h.line : void 0,
|
|
369
|
+
snippetFromBody: h.snippetFromBody === true ? true : void 0
|
|
363
370
|
});
|
|
364
371
|
}
|
|
365
372
|
return out;
|
|
@@ -389,7 +396,8 @@ async function loadSearchProvider(name) {
|
|
|
389
396
|
collections: toWireCollections(collections),
|
|
390
397
|
collection: opts?.collection,
|
|
391
398
|
type: opts?.type,
|
|
392
|
-
limit: opts?.limit
|
|
399
|
+
limit: opts?.limit,
|
|
400
|
+
expansions: opts?.expansions
|
|
393
401
|
},
|
|
394
402
|
{ timeoutMs: SEARCH_TIMEOUT_MS, name: record.name }
|
|
395
403
|
);
|
|
@@ -447,12 +455,12 @@ async function listSearchModes() {
|
|
|
447
455
|
}
|
|
448
456
|
return modes;
|
|
449
457
|
}
|
|
450
|
-
var import_node_child_process,
|
|
458
|
+
var import_node_child_process, import_node_path3, LEVEL_METHOD, DEFAULT_TIMEOUT_MS, SEARCH_TIMEOUT_MS, LONG_TIMEOUT_MS;
|
|
451
459
|
var init_host = __esm({
|
|
452
460
|
"src/plugins/host.ts"() {
|
|
453
461
|
"use strict";
|
|
454
462
|
import_node_child_process = require("child_process");
|
|
455
|
-
|
|
463
|
+
import_node_path3 = __toESM(require("path"), 1);
|
|
456
464
|
init_logger();
|
|
457
465
|
init_types();
|
|
458
466
|
init_registry2();
|
|
@@ -526,7 +534,7 @@ async function findCollectionById(id) {
|
|
|
526
534
|
async function createCollection(name, opts) {
|
|
527
535
|
if (await findCollection(name)) throw new CollectionExistsError(name);
|
|
528
536
|
const dir = collectionDir(name);
|
|
529
|
-
await
|
|
537
|
+
await import_promises4.default.mkdir(dir, { recursive: true });
|
|
530
538
|
const entry = {
|
|
531
539
|
name,
|
|
532
540
|
type: "global",
|
|
@@ -543,16 +551,16 @@ async function removeCollection(name) {
|
|
|
543
551
|
if (!entry) throw new CollectionNotFoundError(name);
|
|
544
552
|
await unregisterCollection(name);
|
|
545
553
|
if (entry.type === "global") {
|
|
546
|
-
await
|
|
554
|
+
await import_promises4.default.rm(entry.path, { recursive: true, force: true });
|
|
547
555
|
}
|
|
548
556
|
void fireHook("collection-removed", name);
|
|
549
557
|
return entry;
|
|
550
558
|
}
|
|
551
|
-
var
|
|
559
|
+
var import_promises4;
|
|
552
560
|
var init_collections = __esm({
|
|
553
561
|
"src/collections.ts"() {
|
|
554
562
|
"use strict";
|
|
555
|
-
|
|
563
|
+
import_promises4 = __toESM(require("fs/promises"), 1);
|
|
556
564
|
init_paths();
|
|
557
565
|
init_registry();
|
|
558
566
|
init_errors();
|
|
@@ -616,11 +624,14 @@ __export(index_exports, {
|
|
|
616
624
|
listEnabledPlugins: () => listEnabledPlugins,
|
|
617
625
|
listPlugins: () => listPlugins,
|
|
618
626
|
listSearchModes: () => listSearchModes,
|
|
627
|
+
listTemplateShapes: () => listTemplateShapes,
|
|
628
|
+
listTemplates: () => listTemplates,
|
|
619
629
|
loadSearchProvider: () => loadSearchProvider,
|
|
620
630
|
localGraph: () => localGraph,
|
|
621
631
|
nativeSearch: () => nativeSearch,
|
|
622
632
|
parseAddTarget: () => parseAddTarget,
|
|
623
633
|
parseArticle: () => parseArticle,
|
|
634
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
624
635
|
parsePathTarget: () => parsePathTarget,
|
|
625
636
|
pluginsDir: () => pluginsDir,
|
|
626
637
|
pluginsRegistryPath: () => pluginsRegistryPath,
|
|
@@ -642,6 +653,7 @@ __export(index_exports, {
|
|
|
642
653
|
removePlugin: () => removePlugin,
|
|
643
654
|
removeTags: () => removeTags,
|
|
644
655
|
renderArticle: () => renderArticle,
|
|
656
|
+
repairPlugins: () => repairPlugins,
|
|
645
657
|
repoId: () => repoId,
|
|
646
658
|
repoRemoteName: () => repoRemoteName,
|
|
647
659
|
resolveCollectionSelection: () => resolveCollectionSelection,
|
|
@@ -655,13 +667,17 @@ __export(index_exports, {
|
|
|
655
667
|
resolveProjectCollections: () => resolveProjectCollections,
|
|
656
668
|
search: () => search,
|
|
657
669
|
seedProjectHome: () => seedProjectHome,
|
|
670
|
+
seedTemplates: () => seedTemplates,
|
|
658
671
|
serializeArticle: () => serializeArticle,
|
|
659
672
|
setArticleMeta: () => setArticleMeta,
|
|
660
673
|
setConfigValue: () => setConfigValue,
|
|
674
|
+
setContextCollections: () => setContextCollections,
|
|
661
675
|
setTags: () => setTags,
|
|
662
676
|
showSystemEnabled: () => showSystemEnabled,
|
|
663
677
|
slugify: () => slugify,
|
|
664
678
|
slugifyPath: () => slugifyPath,
|
|
679
|
+
stripFrontmatter: () => stripFrontmatter,
|
|
680
|
+
templatesDir: () => templatesDir,
|
|
665
681
|
toTreeNodes: () => toTreeNodes,
|
|
666
682
|
tokenize: () => tokenize,
|
|
667
683
|
unregisterCollection: () => unregisterCollection,
|
|
@@ -677,70 +693,10 @@ init_types();
|
|
|
677
693
|
init_errors();
|
|
678
694
|
init_paths();
|
|
679
695
|
|
|
680
|
-
// src/
|
|
681
|
-
var
|
|
696
|
+
// src/templates.ts
|
|
697
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
698
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
682
699
|
init_paths();
|
|
683
|
-
init_collections();
|
|
684
|
-
init_errors();
|
|
685
|
-
init_registry2();
|
|
686
|
-
init_types();
|
|
687
|
-
function isMissing3(err) {
|
|
688
|
-
return err?.code === "ENOENT";
|
|
689
|
-
}
|
|
690
|
-
async function readConfig() {
|
|
691
|
-
try {
|
|
692
|
-
return JSON.parse(await import_promises4.default.readFile(configPath(), "utf8"));
|
|
693
|
-
} catch (err) {
|
|
694
|
-
if (isMissing3(err)) return {};
|
|
695
|
-
throw err;
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
async function writeConfig(config) {
|
|
699
|
-
await import_promises4.default.mkdir(resolveHome(), { recursive: true });
|
|
700
|
-
await import_promises4.default.writeFile(configPath(), `${JSON.stringify(config, null, 2)}
|
|
701
|
-
`, "utf8");
|
|
702
|
-
}
|
|
703
|
-
async function setConfigValue(key, value) {
|
|
704
|
-
if (key === "defaultCollection" && !await findCollection(value)) {
|
|
705
|
-
throw new CollectionNotFoundError(value);
|
|
706
|
-
}
|
|
707
|
-
if (key === "defaultSearch") {
|
|
708
|
-
const engine = value.split(":")[0];
|
|
709
|
-
if (engine !== NATIVE_ENGINE) {
|
|
710
|
-
const enabled = await listEnabledPlugins("search");
|
|
711
|
-
if (!enabled.some((p) => p.name === engine)) {
|
|
712
|
-
console.warn(
|
|
713
|
-
`! defaultSearch "${value}" names an engine that is not installed/enabled \u2014 native will be used until it is`
|
|
714
|
-
);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
const config = await readConfig();
|
|
719
|
-
config[key] = value;
|
|
720
|
-
await writeConfig(config);
|
|
721
|
-
}
|
|
722
|
-
async function getConfigValue(key) {
|
|
723
|
-
const config = await readConfig();
|
|
724
|
-
const value = config[key];
|
|
725
|
-
return typeof value === "string" ? value : void 0;
|
|
726
|
-
}
|
|
727
|
-
async function showSystemEnabled() {
|
|
728
|
-
const config = await readConfig();
|
|
729
|
-
return config.showSystem === true || config.showSystem === "true";
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
// src/index.ts
|
|
733
|
-
init_registry();
|
|
734
|
-
|
|
735
|
-
// src/slugify.ts
|
|
736
|
-
function slugify(input) {
|
|
737
|
-
const slug = input.toLowerCase().replace(/^#+\s*/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/g, "");
|
|
738
|
-
return slug.length > 0 ? slug : "untitled";
|
|
739
|
-
}
|
|
740
|
-
function slugifyPath(input) {
|
|
741
|
-
const segs = input.split("/").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => slugify(s));
|
|
742
|
-
return segs.length > 0 ? segs.join("/") : "untitled";
|
|
743
|
-
}
|
|
744
700
|
|
|
745
701
|
// src/frontmatter.ts
|
|
746
702
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
@@ -787,6 +743,18 @@ function parseFallback(raw) {
|
|
|
787
743
|
}
|
|
788
744
|
return { title, tags: [], audience, status, body: body.replace(/^\n+/, "") };
|
|
789
745
|
}
|
|
746
|
+
var FRONTMATTER_BLOCK_RE = /^\uFEFF?[ \t]*---\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/;
|
|
747
|
+
function stripFrontmatter(raw) {
|
|
748
|
+
return raw.replace(FRONTMATTER_BLOCK_RE, "");
|
|
749
|
+
}
|
|
750
|
+
function parseFrontmatter(raw) {
|
|
751
|
+
try {
|
|
752
|
+
const { data, content } = (0, import_gray_matter.default)(raw, MATTER_OPTS);
|
|
753
|
+
return { data: data ?? {}, body: content };
|
|
754
|
+
} catch {
|
|
755
|
+
return { data: {}, body: raw };
|
|
756
|
+
}
|
|
757
|
+
}
|
|
790
758
|
function parseArticle(raw) {
|
|
791
759
|
try {
|
|
792
760
|
const { data, content } = (0, import_gray_matter.default)(raw, MATTER_OPTS);
|
|
@@ -807,12 +775,118 @@ function serializeArticle(article) {
|
|
|
807
775
|
return import_gray_matter.default.stringify(article.body, front, MATTER_OPTS);
|
|
808
776
|
}
|
|
809
777
|
|
|
778
|
+
// src/templates.ts
|
|
779
|
+
async function seedTemplates(srcDir) {
|
|
780
|
+
const dir = templatesDir();
|
|
781
|
+
await import_promises.default.mkdir(dir, { recursive: true });
|
|
782
|
+
const files = (await import_promises.default.readdir(srcDir)).filter((f) => f.endsWith(".md")).sort();
|
|
783
|
+
const seeded = [];
|
|
784
|
+
const skipped = [];
|
|
785
|
+
for (const file of files) {
|
|
786
|
+
const dest = import_node_path2.default.join(dir, file);
|
|
787
|
+
try {
|
|
788
|
+
await import_promises.default.access(dest);
|
|
789
|
+
skipped.push(file);
|
|
790
|
+
continue;
|
|
791
|
+
} catch {
|
|
792
|
+
}
|
|
793
|
+
await import_promises.default.copyFile(import_node_path2.default.join(srcDir, file), dest);
|
|
794
|
+
seeded.push(file);
|
|
795
|
+
}
|
|
796
|
+
return { seeded, skipped, dir };
|
|
797
|
+
}
|
|
798
|
+
async function listTemplateShapes(srcDir) {
|
|
799
|
+
const files = await import_promises.default.readdir(srcDir);
|
|
800
|
+
return files.filter((f) => f.endsWith("-template.md")).map((f) => f.replace(/-template\.md$/, "")).sort();
|
|
801
|
+
}
|
|
802
|
+
async function listTemplates(srcDir) {
|
|
803
|
+
const files = (await import_promises.default.readdir(srcDir)).filter((f) => f.endsWith("-template.md")).sort();
|
|
804
|
+
const out = [];
|
|
805
|
+
for (const file of files) {
|
|
806
|
+
let data = {};
|
|
807
|
+
try {
|
|
808
|
+
({ data } = parseFrontmatter(await import_promises.default.readFile(import_node_path2.default.join(srcDir, file), "utf8")));
|
|
809
|
+
} catch {
|
|
810
|
+
}
|
|
811
|
+
const shape = typeof data.shape === "string" && data.shape ? data.shape : file.replace(/-template\.md$/, "");
|
|
812
|
+
const purpose = typeof data.purpose === "string" ? data.purpose : "";
|
|
813
|
+
const budget = Array.isArray(data.budget) && data.budget.length === 2 ? [Number(data.budget[0]), Number(data.budget[1])] : void 0;
|
|
814
|
+
out.push({ shape, purpose, budget, file });
|
|
815
|
+
}
|
|
816
|
+
return out;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/config.ts
|
|
820
|
+
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
821
|
+
init_paths();
|
|
822
|
+
init_collections();
|
|
823
|
+
init_errors();
|
|
824
|
+
init_registry2();
|
|
825
|
+
init_types();
|
|
826
|
+
function isMissing3(err) {
|
|
827
|
+
return err?.code === "ENOENT";
|
|
828
|
+
}
|
|
829
|
+
async function readConfig() {
|
|
830
|
+
try {
|
|
831
|
+
return JSON.parse(await import_promises5.default.readFile(configPath(), "utf8"));
|
|
832
|
+
} catch (err) {
|
|
833
|
+
if (isMissing3(err)) return {};
|
|
834
|
+
throw err;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
async function writeConfig(config) {
|
|
838
|
+
await import_promises5.default.mkdir(resolveHome(), { recursive: true });
|
|
839
|
+
await import_promises5.default.writeFile(configPath(), `${JSON.stringify(config, null, 2)}
|
|
840
|
+
`, "utf8");
|
|
841
|
+
}
|
|
842
|
+
async function setConfigValue(key, value) {
|
|
843
|
+
if (key === "defaultCollection" && !await findCollection(value)) {
|
|
844
|
+
throw new CollectionNotFoundError(value);
|
|
845
|
+
}
|
|
846
|
+
if (key === "defaultSearch") {
|
|
847
|
+
const engine = value.split(":")[0];
|
|
848
|
+
if (engine !== NATIVE_ENGINE) {
|
|
849
|
+
const enabled = await listEnabledPlugins("search");
|
|
850
|
+
if (!enabled.some((p) => p.name === engine)) {
|
|
851
|
+
console.warn(
|
|
852
|
+
`! defaultSearch "${value}" names an engine that is not installed/enabled \u2014 native will be used until it is`
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
const config = await readConfig();
|
|
858
|
+
config[key] = value;
|
|
859
|
+
await writeConfig(config);
|
|
860
|
+
}
|
|
861
|
+
async function getConfigValue(key) {
|
|
862
|
+
const config = await readConfig();
|
|
863
|
+
const value = config[key];
|
|
864
|
+
return typeof value === "string" ? value : void 0;
|
|
865
|
+
}
|
|
866
|
+
async function showSystemEnabled() {
|
|
867
|
+
const config = await readConfig();
|
|
868
|
+
return config.showSystem === true || config.showSystem === "true";
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// src/index.ts
|
|
872
|
+
init_registry();
|
|
873
|
+
|
|
874
|
+
// src/slugify.ts
|
|
875
|
+
function slugify(input) {
|
|
876
|
+
const slug = input.toLowerCase().replace(/^#+\s*/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/g, "");
|
|
877
|
+
return slug.length > 0 ? slug : "untitled";
|
|
878
|
+
}
|
|
879
|
+
function slugifyPath(input) {
|
|
880
|
+
const segs = input.split("/").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => slugify(s));
|
|
881
|
+
return segs.length > 0 ? segs.join("/") : "untitled";
|
|
882
|
+
}
|
|
883
|
+
|
|
810
884
|
// src/index.ts
|
|
811
885
|
init_collections();
|
|
812
886
|
|
|
813
887
|
// src/articles.ts
|
|
814
|
-
var
|
|
815
|
-
var
|
|
888
|
+
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
889
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
816
890
|
init_collections();
|
|
817
891
|
init_errors();
|
|
818
892
|
async function fireHook2(event, collection, relPath) {
|
|
@@ -859,24 +933,24 @@ function ensureMdPath(file) {
|
|
|
859
933
|
async function createArticle(opts) {
|
|
860
934
|
const { collection, title } = parseAddTarget(opts.target);
|
|
861
935
|
const { name, dir } = await resolveCollectionDir(collection);
|
|
862
|
-
const filePath =
|
|
936
|
+
const filePath = import_node_path4.default.join(dir, `${slugifyPath(title)}.md`);
|
|
863
937
|
const body = opts.body ?? `# ${title}
|
|
864
938
|
`;
|
|
865
|
-
await
|
|
866
|
-
await
|
|
939
|
+
await import_promises6.default.mkdir(import_node_path4.default.dirname(filePath), { recursive: true });
|
|
940
|
+
await import_promises6.default.writeFile(
|
|
867
941
|
filePath,
|
|
868
942
|
serializeArticle({ title, tags: opts.tags, body, audience: opts.audience, status: opts.status }),
|
|
869
943
|
"utf8"
|
|
870
944
|
);
|
|
871
|
-
void fireHook2("article-created", name,
|
|
945
|
+
void fireHook2("article-created", name, import_node_path4.default.relative(dir, filePath));
|
|
872
946
|
return { title, tags: opts.tags, path: filePath, collection: name };
|
|
873
947
|
}
|
|
874
948
|
async function loadArticle(target) {
|
|
875
949
|
const { collection, file } = parsePathTarget(target);
|
|
876
950
|
const { dir } = await resolveCollectionDir(collection);
|
|
877
|
-
const filePath =
|
|
951
|
+
const filePath = import_node_path4.default.join(dir, ensureMdPath(file));
|
|
878
952
|
try {
|
|
879
|
-
return { filePath, dir, raw: await
|
|
953
|
+
return { filePath, dir, raw: await import_promises6.default.readFile(filePath, "utf8"), collection };
|
|
880
954
|
} catch (err) {
|
|
881
955
|
if (err.code === "ENOENT") throw new ArticleNotFoundError(target);
|
|
882
956
|
throw err;
|
|
@@ -885,7 +959,7 @@ async function loadArticle(target) {
|
|
|
885
959
|
async function updateArticleBody(target, body) {
|
|
886
960
|
const { filePath, dir, raw, collection } = await loadArticle(target);
|
|
887
961
|
const parsed = parseArticle(raw);
|
|
888
|
-
await
|
|
962
|
+
await import_promises6.default.writeFile(
|
|
889
963
|
filePath,
|
|
890
964
|
serializeArticle({
|
|
891
965
|
title: parsed.title,
|
|
@@ -896,14 +970,14 @@ async function updateArticleBody(target, body) {
|
|
|
896
970
|
}),
|
|
897
971
|
"utf8"
|
|
898
972
|
);
|
|
899
|
-
void fireHook2("article-updated", collection,
|
|
973
|
+
void fireHook2("article-updated", collection, import_node_path4.default.relative(dir, filePath));
|
|
900
974
|
return { title: parsed.title, tags: parsed.tags, path: filePath, collection };
|
|
901
975
|
}
|
|
902
976
|
async function mutateTags(target, fn) {
|
|
903
977
|
const { filePath, dir, raw, collection } = await loadArticle(target);
|
|
904
978
|
const parsed = parseArticle(raw);
|
|
905
979
|
const tags = fn(parsed.tags);
|
|
906
|
-
await
|
|
980
|
+
await import_promises6.default.writeFile(
|
|
907
981
|
filePath,
|
|
908
982
|
serializeArticle({
|
|
909
983
|
title: parsed.title,
|
|
@@ -914,7 +988,7 @@ async function mutateTags(target, fn) {
|
|
|
914
988
|
}),
|
|
915
989
|
"utf8"
|
|
916
990
|
);
|
|
917
|
-
void fireHook2("article-updated", collection,
|
|
991
|
+
void fireHook2("article-updated", collection, import_node_path4.default.relative(dir, filePath));
|
|
918
992
|
return { title: parsed.title, tags, path: filePath, collection };
|
|
919
993
|
}
|
|
920
994
|
function addTags(target, tags) {
|
|
@@ -932,24 +1006,24 @@ async function setArticleMeta(target, meta) {
|
|
|
932
1006
|
const parsed = parseArticle(raw);
|
|
933
1007
|
const audience = meta.audience ?? parsed.audience;
|
|
934
1008
|
const status = meta.status ?? parsed.status;
|
|
935
|
-
await
|
|
1009
|
+
await import_promises6.default.writeFile(
|
|
936
1010
|
filePath,
|
|
937
1011
|
serializeArticle({ title: parsed.title, tags: parsed.tags, audience, status, body: parsed.body }),
|
|
938
1012
|
"utf8"
|
|
939
1013
|
);
|
|
940
|
-
void fireHook2("article-updated", collection,
|
|
1014
|
+
void fireHook2("article-updated", collection, import_node_path4.default.relative(dir, filePath));
|
|
941
1015
|
return { title: parsed.title, tags: parsed.tags, path: filePath, collection };
|
|
942
1016
|
}
|
|
943
1017
|
async function removeArticle(target) {
|
|
944
1018
|
const { filePath, dir, collection } = await loadArticle(target);
|
|
945
|
-
await
|
|
946
|
-
void fireHook2("article-removed", collection,
|
|
1019
|
+
await import_promises6.default.rm(filePath);
|
|
1020
|
+
void fireHook2("article-removed", collection, import_node_path4.default.relative(dir, filePath));
|
|
947
1021
|
return filePath;
|
|
948
1022
|
}
|
|
949
1023
|
|
|
950
1024
|
// src/repo.ts
|
|
951
|
-
var
|
|
952
|
-
var
|
|
1025
|
+
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
1026
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
953
1027
|
var import_node_child_process3 = require("child_process");
|
|
954
1028
|
var import_node_util2 = require("util");
|
|
955
1029
|
var import_yaml2 = require("yaml");
|
|
@@ -957,8 +1031,8 @@ init_collections();
|
|
|
957
1031
|
init_registry();
|
|
958
1032
|
|
|
959
1033
|
// src/git.ts
|
|
960
|
-
var
|
|
961
|
-
var
|
|
1034
|
+
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
1035
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
962
1036
|
var import_node_child_process2 = require("child_process");
|
|
963
1037
|
var import_node_util = require("util");
|
|
964
1038
|
init_logger();
|
|
@@ -984,8 +1058,8 @@ async function isLinkedWorktree(cwd) {
|
|
|
984
1058
|
const gitDir = await git(cwd, ["rev-parse", "--absolute-git-dir"]);
|
|
985
1059
|
const commonDir = await git(cwd, ["rev-parse", "--git-common-dir"]);
|
|
986
1060
|
if (!gitDir || !commonDir) return false;
|
|
987
|
-
const commonAbs =
|
|
988
|
-
return
|
|
1061
|
+
const commonAbs = import_node_path5.default.isAbsolute(commonDir) ? commonDir : import_node_path5.default.resolve(cwd, commonDir);
|
|
1062
|
+
return import_node_path5.default.resolve(gitDir) !== import_node_path5.default.resolve(commonAbs);
|
|
989
1063
|
}
|
|
990
1064
|
async function repoRemoteName(cwd) {
|
|
991
1065
|
const url = await git(cwd, ["remote", "get-url", "origin"]);
|
|
@@ -1027,8 +1101,8 @@ var timestampCache = /* @__PURE__ */ new Map();
|
|
|
1027
1101
|
async function fileTimestamps(absPath) {
|
|
1028
1102
|
const cached2 = timestampCache.get(absPath);
|
|
1029
1103
|
if (cached2) return cached2;
|
|
1030
|
-
const dir =
|
|
1031
|
-
const base =
|
|
1104
|
+
const dir = import_node_path5.default.dirname(absPath);
|
|
1105
|
+
const base = import_node_path5.default.basename(absPath);
|
|
1032
1106
|
const [addLog, lastLog] = await Promise.all([
|
|
1033
1107
|
git(dir, ["log", "--follow", "--diff-filter=A", "--format=%aI", "--", base]),
|
|
1034
1108
|
git(dir, ["log", "-1", "--format=%aI", "--", base])
|
|
@@ -1039,7 +1113,7 @@ async function fileTimestamps(absPath) {
|
|
|
1039
1113
|
let updated = gitUpdated;
|
|
1040
1114
|
if (!created || !updated) {
|
|
1041
1115
|
try {
|
|
1042
|
-
const st = await
|
|
1116
|
+
const st = await import_promises7.default.stat(absPath);
|
|
1043
1117
|
if (!updated) updated = st.mtime.toISOString();
|
|
1044
1118
|
if (!created) created = isEpochish(st.birthtime) ? st.mtime.toISOString() : st.birthtime.toISOString();
|
|
1045
1119
|
} catch {
|
|
@@ -1057,18 +1131,18 @@ var REPO_CONFIG_FILE = "diffwiki.yaml";
|
|
|
1057
1131
|
async function detectRepoName(cwd) {
|
|
1058
1132
|
try {
|
|
1059
1133
|
const { stdout } = await execFileAsync2("git", ["rev-parse", "--show-toplevel"], { cwd });
|
|
1060
|
-
return
|
|
1134
|
+
return import_node_path6.default.basename(stdout.trim());
|
|
1061
1135
|
} catch {
|
|
1062
|
-
return
|
|
1136
|
+
return import_node_path6.default.basename(import_node_path6.default.resolve(cwd));
|
|
1063
1137
|
}
|
|
1064
1138
|
}
|
|
1065
1139
|
async function readRepoConfig(cwd) {
|
|
1066
1140
|
try {
|
|
1067
|
-
const raw = await
|
|
1141
|
+
const raw = await import_promises8.default.readFile(import_node_path6.default.join(cwd, REPO_CONFIG_FILE), "utf8");
|
|
1068
1142
|
const parsed = (0, import_yaml2.parse)(raw) ?? {};
|
|
1069
1143
|
if (!parsed.path) return void 0;
|
|
1070
1144
|
return {
|
|
1071
|
-
collection: parsed.collection ??
|
|
1145
|
+
collection: parsed.collection ?? import_node_path6.default.basename(import_node_path6.default.resolve(cwd)),
|
|
1072
1146
|
path: parsed.path
|
|
1073
1147
|
};
|
|
1074
1148
|
} catch (err) {
|
|
@@ -1077,9 +1151,9 @@ async function readRepoConfig(cwd) {
|
|
|
1077
1151
|
}
|
|
1078
1152
|
}
|
|
1079
1153
|
async function initRepoWiki(opts) {
|
|
1080
|
-
const cwd =
|
|
1154
|
+
const cwd = import_node_path6.default.resolve(opts.cwd);
|
|
1081
1155
|
const wikiPath = opts.wikiPath ?? "wiki";
|
|
1082
|
-
const absWiki =
|
|
1156
|
+
const absWiki = import_node_path6.default.join(cwd, wikiPath);
|
|
1083
1157
|
let name = opts.collection ?? await detectRepoName(cwd);
|
|
1084
1158
|
const existing = await findCollection(name);
|
|
1085
1159
|
if (existing && existing.path !== absWiki) {
|
|
@@ -1094,9 +1168,9 @@ async function initRepoWiki(opts) {
|
|
|
1094
1168
|
n += 1;
|
|
1095
1169
|
}
|
|
1096
1170
|
}
|
|
1097
|
-
await
|
|
1171
|
+
await import_promises8.default.mkdir(absWiki, { recursive: true });
|
|
1098
1172
|
const config = { collection: name, path: wikiPath };
|
|
1099
|
-
await
|
|
1173
|
+
await import_promises8.default.writeFile(import_node_path6.default.join(cwd, REPO_CONFIG_FILE), (0, import_yaml2.stringify)(config), "utf8");
|
|
1100
1174
|
const entry = {
|
|
1101
1175
|
name,
|
|
1102
1176
|
type: "repo",
|
|
@@ -1107,15 +1181,15 @@ async function initRepoWiki(opts) {
|
|
|
1107
1181
|
return entry;
|
|
1108
1182
|
}
|
|
1109
1183
|
async function addExternalCollection(opts) {
|
|
1110
|
-
const cwd =
|
|
1184
|
+
const cwd = import_node_path6.default.resolve(opts.cwd);
|
|
1111
1185
|
const root = await ensureGitRepo(cwd);
|
|
1112
1186
|
if (await isLinkedWorktree(cwd)) throw new WorktreeNotAllowedError(root);
|
|
1113
1187
|
const id = await repoId(root) ?? `path:${root}`;
|
|
1114
1188
|
const already = await findCollectionById(id);
|
|
1115
1189
|
if (already) throw new CollectionAlreadyAddedError(already.name);
|
|
1116
1190
|
const docsRel = opts.docsDir ?? "docs";
|
|
1117
|
-
const contentDir =
|
|
1118
|
-
let name = await repoRemoteName(root) ??
|
|
1191
|
+
const contentDir = import_node_path6.default.join(root, docsRel);
|
|
1192
|
+
let name = await repoRemoteName(root) ?? import_node_path6.default.basename(root);
|
|
1119
1193
|
if (await findCollection(name)) {
|
|
1120
1194
|
let n = 2;
|
|
1121
1195
|
while (await findCollection(`${name}-${n}`)) n += 1;
|
|
@@ -1134,14 +1208,14 @@ async function addExternalCollection(opts) {
|
|
|
1134
1208
|
return entry;
|
|
1135
1209
|
}
|
|
1136
1210
|
async function resolveCwdCollection(cwd) {
|
|
1137
|
-
const abs =
|
|
1211
|
+
const abs = import_node_path6.default.resolve(cwd);
|
|
1138
1212
|
const root = await gitToplevel(abs);
|
|
1139
1213
|
if (root) {
|
|
1140
1214
|
const id = await repoId(root) ?? `path:${root}`;
|
|
1141
1215
|
const byId = await findCollectionById(id);
|
|
1142
1216
|
if (byId) return byId;
|
|
1143
1217
|
}
|
|
1144
|
-
const within = (base) => abs === base || abs.startsWith(base +
|
|
1218
|
+
const within = (base) => abs === base || abs.startsWith(base + import_node_path6.default.sep);
|
|
1145
1219
|
const all = await listCollections();
|
|
1146
1220
|
let best;
|
|
1147
1221
|
let bestLen = -1;
|
|
@@ -1165,9 +1239,9 @@ async function collectionGitStatus(entry) {
|
|
|
1165
1239
|
}
|
|
1166
1240
|
|
|
1167
1241
|
// src/project.ts
|
|
1168
|
-
var
|
|
1242
|
+
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
1169
1243
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
1170
|
-
var
|
|
1244
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
1171
1245
|
var import_yaml3 = require("yaml");
|
|
1172
1246
|
var PROJECT_CONFIG_FILE = "diffwiki.yaml";
|
|
1173
1247
|
function normaliseSite(raw) {
|
|
@@ -1222,7 +1296,7 @@ function normaliseContext(raw) {
|
|
|
1222
1296
|
async function readProjectConfig(dir) {
|
|
1223
1297
|
let raw;
|
|
1224
1298
|
try {
|
|
1225
|
-
raw = await
|
|
1299
|
+
raw = await import_promises9.default.readFile(import_node_path7.default.join(dir, PROJECT_CONFIG_FILE), "utf8");
|
|
1226
1300
|
} catch (err) {
|
|
1227
1301
|
if (err.code === "ENOENT") return void 0;
|
|
1228
1302
|
throw err;
|
|
@@ -1243,7 +1317,7 @@ async function readProjectConfig(dir) {
|
|
|
1243
1317
|
}
|
|
1244
1318
|
collections.sort((a, b) => (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER));
|
|
1245
1319
|
} else if (typeof parsed.path === "string") {
|
|
1246
|
-
const name = typeof parsed.collection === "string" ? parsed.collection :
|
|
1320
|
+
const name = typeof parsed.collection === "string" ? parsed.collection : import_node_path7.default.basename(import_node_path7.default.resolve(dir));
|
|
1247
1321
|
collections.push({ name, path: parsed.path });
|
|
1248
1322
|
}
|
|
1249
1323
|
const site = normaliseSite(parsed.site);
|
|
@@ -1253,15 +1327,28 @@ async function readProjectConfig(dir) {
|
|
|
1253
1327
|
async function readContextCollections(dir) {
|
|
1254
1328
|
return (await readProjectConfig(dir))?.context?.collections ?? [];
|
|
1255
1329
|
}
|
|
1330
|
+
async function setContextCollections(dir, collections) {
|
|
1331
|
+
const file = import_node_path7.default.join(dir, PROJECT_CONFIG_FILE);
|
|
1332
|
+
let raw = "";
|
|
1333
|
+
try {
|
|
1334
|
+
raw = await import_promises9.default.readFile(file, "utf8");
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
if (err.code !== "ENOENT") throw err;
|
|
1337
|
+
}
|
|
1338
|
+
const doc = (0, import_yaml3.parseDocument)(raw);
|
|
1339
|
+
doc.setIn(["context", "collections"], collections);
|
|
1340
|
+
await import_promises9.default.writeFile(file, doc.toString(), "utf8");
|
|
1341
|
+
return file;
|
|
1342
|
+
}
|
|
1256
1343
|
async function resolveProjectCollections(dir) {
|
|
1257
1344
|
const config = await readProjectConfig(dir);
|
|
1258
1345
|
if (!config) return [];
|
|
1259
|
-
const root =
|
|
1346
|
+
const root = import_node_path7.default.resolve(dir);
|
|
1260
1347
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1261
1348
|
return config.collections.map((c) => ({
|
|
1262
1349
|
name: c.name,
|
|
1263
1350
|
type: "repo",
|
|
1264
|
-
path:
|
|
1351
|
+
path: import_node_path7.default.resolve(root, c.path),
|
|
1265
1352
|
createdAt
|
|
1266
1353
|
}));
|
|
1267
1354
|
}
|
|
@@ -1271,11 +1358,11 @@ async function readSiteConfig(dir) {
|
|
|
1271
1358
|
async function seedProjectHome(dir) {
|
|
1272
1359
|
const entries = await resolveProjectCollections(dir);
|
|
1273
1360
|
if (entries.length === 0) {
|
|
1274
|
-
throw new Error(`No collections to render from diffwiki.yaml in ${
|
|
1361
|
+
throw new Error(`No collections to render from diffwiki.yaml in ${import_node_path7.default.resolve(dir)}`);
|
|
1275
1362
|
}
|
|
1276
|
-
const home = await
|
|
1277
|
-
await
|
|
1278
|
-
|
|
1363
|
+
const home = await import_promises9.default.mkdtemp(import_node_path7.default.join(import_node_os2.default.tmpdir(), "diffwiki-project-"));
|
|
1364
|
+
await import_promises9.default.writeFile(
|
|
1365
|
+
import_node_path7.default.join(home, "registry.json"),
|
|
1279
1366
|
`${JSON.stringify({ version: 1, collections: entries }, null, 2)}
|
|
1280
1367
|
`,
|
|
1281
1368
|
"utf8"
|
|
@@ -1287,8 +1374,8 @@ async function seedProjectHome(dir) {
|
|
|
1287
1374
|
init_collections();
|
|
1288
1375
|
|
|
1289
1376
|
// src/browse.ts
|
|
1290
|
-
var
|
|
1291
|
-
var
|
|
1377
|
+
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
1378
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
1292
1379
|
init_collections();
|
|
1293
1380
|
init_errors();
|
|
1294
1381
|
var INDEX_RE = /^(index|readme)\.mdx?$/i;
|
|
@@ -1334,7 +1421,7 @@ function buildArticleTree(relPaths) {
|
|
|
1334
1421
|
async function collectRelPaths(dir, rel = "") {
|
|
1335
1422
|
let dirents;
|
|
1336
1423
|
try {
|
|
1337
|
-
dirents = await
|
|
1424
|
+
dirents = await import_promises10.default.readdir(dir, { withFileTypes: true });
|
|
1338
1425
|
} catch {
|
|
1339
1426
|
return [];
|
|
1340
1427
|
}
|
|
@@ -1343,7 +1430,7 @@ async function collectRelPaths(dir, rel = "") {
|
|
|
1343
1430
|
if (d.name.startsWith(".")) continue;
|
|
1344
1431
|
const childRel = rel ? `${rel}/${d.name}` : d.name;
|
|
1345
1432
|
if (d.isDirectory()) {
|
|
1346
|
-
out.push(...await collectRelPaths(
|
|
1433
|
+
out.push(...await collectRelPaths(import_node_path8.default.join(dir, d.name), childRel));
|
|
1347
1434
|
} else if (/\.(mdx?)$/.test(d.name)) {
|
|
1348
1435
|
out.push(childRel);
|
|
1349
1436
|
}
|
|
@@ -1352,7 +1439,7 @@ async function collectRelPaths(dir, rel = "") {
|
|
|
1352
1439
|
}
|
|
1353
1440
|
async function readdirSafe(dir) {
|
|
1354
1441
|
try {
|
|
1355
|
-
return await
|
|
1442
|
+
return await import_promises10.default.readdir(dir);
|
|
1356
1443
|
} catch {
|
|
1357
1444
|
return [];
|
|
1358
1445
|
}
|
|
@@ -1370,7 +1457,7 @@ var CHEAP_META_BYTES = 8192;
|
|
|
1370
1457
|
async function cheapMeta(absPath) {
|
|
1371
1458
|
let handle;
|
|
1372
1459
|
try {
|
|
1373
|
-
handle = await
|
|
1460
|
+
handle = await import_promises10.default.open(absPath, "r");
|
|
1374
1461
|
const buf = Buffer.alloc(CHEAP_META_BYTES);
|
|
1375
1462
|
const { bytesRead } = await handle.read(buf, 0, CHEAP_META_BYTES, 0);
|
|
1376
1463
|
const snippet = buf.subarray(0, bytesRead).toString("utf8");
|
|
@@ -1404,10 +1491,10 @@ async function enrichTitles(nodes, collDir) {
|
|
|
1404
1491
|
let status = node.status;
|
|
1405
1492
|
let order = node.order;
|
|
1406
1493
|
if (node.slug) {
|
|
1407
|
-
const dir =
|
|
1494
|
+
const dir = import_node_path8.default.join(collDir, node.slug);
|
|
1408
1495
|
const idx = pickIndexFile(await readdirSafe(dir));
|
|
1409
1496
|
if (idx) {
|
|
1410
|
-
const meta = await cheapMeta(
|
|
1497
|
+
const meta = await cheapMeta(import_node_path8.default.join(dir, idx));
|
|
1411
1498
|
title = meta.title ?? title;
|
|
1412
1499
|
audience = meta.audience ?? audience;
|
|
1413
1500
|
status = meta.status ?? status;
|
|
@@ -1417,7 +1504,7 @@ async function enrichTitles(nodes, collDir) {
|
|
|
1417
1504
|
return { ...node, title, audience, status, order, children };
|
|
1418
1505
|
}
|
|
1419
1506
|
for (const ext of [".mdx", ".md"]) {
|
|
1420
|
-
const meta = await cheapMeta(
|
|
1507
|
+
const meta = await cheapMeta(import_node_path8.default.join(collDir, `${node.slug}${ext}`));
|
|
1421
1508
|
if (meta.title || meta.audience || meta.status || meta.order != null) {
|
|
1422
1509
|
return {
|
|
1423
1510
|
...node,
|
|
@@ -1436,49 +1523,49 @@ async function enrichTitles(nodes, collDir) {
|
|
|
1436
1523
|
async function collectionMeta(collDir) {
|
|
1437
1524
|
const idx = pickIndexFile(await readdirSafe(collDir));
|
|
1438
1525
|
if (!idx) return {};
|
|
1439
|
-
const meta = await cheapMeta(
|
|
1526
|
+
const meta = await cheapMeta(import_node_path8.default.join(collDir, idx));
|
|
1440
1527
|
return { title: meta.title, audience: meta.audience, status: meta.status };
|
|
1441
1528
|
}
|
|
1442
1529
|
async function listArticleTree(coll) {
|
|
1443
1530
|
const entry = await findCollection(coll);
|
|
1444
1531
|
if (!entry) throw new CollectionNotFoundError(coll);
|
|
1445
1532
|
const rels = await collectRelPaths(entry.path);
|
|
1446
|
-
return enrichTitles(buildArticleTree(rels),
|
|
1533
|
+
return enrichTitles(buildArticleTree(rels), import_node_path8.default.resolve(entry.path));
|
|
1447
1534
|
}
|
|
1448
1535
|
async function readArticle(coll, slug) {
|
|
1449
1536
|
const entry = await findCollection(coll);
|
|
1450
1537
|
if (!entry) throw new CollectionNotFoundError(coll);
|
|
1451
|
-
const collDir =
|
|
1538
|
+
const collDir = import_node_path8.default.resolve(entry.path);
|
|
1452
1539
|
const normalized = slug.replace(/\\/g, "/");
|
|
1453
1540
|
if (normalized.split("/").some((s) => s === "..")) {
|
|
1454
1541
|
throw new InvalidTargetError(slug, "path traversal detected");
|
|
1455
1542
|
}
|
|
1456
1543
|
const safeSlug = normalized.split("/").filter((s) => s !== "" && s !== ".").join("/");
|
|
1457
|
-
const inJail = (p) => p === collDir || p.startsWith(collDir +
|
|
1544
|
+
const inJail = (p) => p === collDir || p.startsWith(collDir + import_node_path8.default.sep);
|
|
1458
1545
|
let abs;
|
|
1459
1546
|
let isIndex = false;
|
|
1460
1547
|
for (const rel of safeSlug ? [`${safeSlug}.mdx`, `${safeSlug}.md`] : []) {
|
|
1461
|
-
const candidate =
|
|
1548
|
+
const candidate = import_node_path8.default.resolve(collDir, rel);
|
|
1462
1549
|
if (!inJail(candidate)) throw new InvalidTargetError(slug, "path traversal detected");
|
|
1463
1550
|
try {
|
|
1464
|
-
await
|
|
1551
|
+
await import_promises10.default.access(candidate);
|
|
1465
1552
|
abs = candidate;
|
|
1466
1553
|
break;
|
|
1467
1554
|
} catch {
|
|
1468
1555
|
}
|
|
1469
1556
|
}
|
|
1470
1557
|
if (!abs) {
|
|
1471
|
-
const dir =
|
|
1558
|
+
const dir = import_node_path8.default.resolve(collDir, safeSlug);
|
|
1472
1559
|
if (inJail(dir)) {
|
|
1473
1560
|
const idx = pickIndexFile(await readdirSafe(dir));
|
|
1474
1561
|
if (idx) {
|
|
1475
|
-
abs =
|
|
1562
|
+
abs = import_node_path8.default.join(dir, idx);
|
|
1476
1563
|
isIndex = true;
|
|
1477
1564
|
}
|
|
1478
1565
|
}
|
|
1479
1566
|
}
|
|
1480
1567
|
if (!abs) throw new ArticleNotFoundError(`${coll}/${safeSlug}`);
|
|
1481
|
-
const parsed = parseArticle(await
|
|
1568
|
+
const parsed = parseArticle(await import_promises10.default.readFile(abs, "utf8"));
|
|
1482
1569
|
const title = parsed.title?.trim() || (safeSlug ? safeSlug.split("/").pop() ?? safeSlug : coll);
|
|
1483
1570
|
return {
|
|
1484
1571
|
coll,
|
|
@@ -1494,7 +1581,7 @@ async function readArticle(coll, slug) {
|
|
|
1494
1581
|
}
|
|
1495
1582
|
|
|
1496
1583
|
// src/render.ts
|
|
1497
|
-
var
|
|
1584
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
1498
1585
|
var import_unified = require("unified");
|
|
1499
1586
|
var import_remark_parse = __toESM(require("remark-parse"), 1);
|
|
1500
1587
|
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
@@ -1511,7 +1598,7 @@ function isNonRelativeHref(href) {
|
|
|
1511
1598
|
return /^[a-z][a-z0-9+.-]*:/i.test(href);
|
|
1512
1599
|
}
|
|
1513
1600
|
function rehypeRewriteLinks(ctx) {
|
|
1514
|
-
const slugDir = ctx.isIndex ? ctx.slug || "." :
|
|
1601
|
+
const slugDir = ctx.isIndex ? ctx.slug || "." : import_node_path9.default.posix.dirname(ctx.slug || ".");
|
|
1515
1602
|
return (tree) => {
|
|
1516
1603
|
(0, import_unist_util_visit.visit)(tree, "element", (node) => {
|
|
1517
1604
|
if (node.tagName !== "a") return;
|
|
@@ -1521,8 +1608,8 @@ function rehypeRewriteLinks(ctx) {
|
|
|
1521
1608
|
const suffix = suffixMatch ? suffixMatch[0] : "";
|
|
1522
1609
|
const pathPart = suffix ? raw.slice(0, raw.length - suffix.length) : raw;
|
|
1523
1610
|
if (pathPart === "") return;
|
|
1524
|
-
const joined =
|
|
1525
|
-
const normalized =
|
|
1611
|
+
const joined = import_node_path9.default.posix.join(slugDir === "." ? "" : slugDir, pathPart);
|
|
1612
|
+
const normalized = import_node_path9.default.posix.normalize(joined);
|
|
1526
1613
|
const toRoute = (p) => p.replace(/\.(mdx?)$/i, "").replace(/(^|\/)(index|readme)$/i, "$1").replace(/\/+$/, "").replace(/^\/+/, "");
|
|
1527
1614
|
if (normalized.startsWith("../")) {
|
|
1528
1615
|
const sibling = normalized.slice(3);
|
|
@@ -1925,8 +2012,8 @@ function resolveCollectionSelection(all, sel = {}) {
|
|
|
1925
2012
|
}
|
|
1926
2013
|
|
|
1927
2014
|
// src/query.ts
|
|
1928
|
-
var
|
|
1929
|
-
var
|
|
2015
|
+
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
2016
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
1930
2017
|
init_collections();
|
|
1931
2018
|
init_errors();
|
|
1932
2019
|
init_logger();
|
|
@@ -1987,6 +2074,12 @@ function rankDocs(term, docs) {
|
|
|
1987
2074
|
if (total > 0) scored.push({ ...d, score: total });
|
|
1988
2075
|
}
|
|
1989
2076
|
scored.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
2077
|
+
const max = scored[0]?.score ?? 0;
|
|
2078
|
+
if (max > 0) {
|
|
2079
|
+
for (const d of scored) {
|
|
2080
|
+
if (typeof d.score === "number") d.score = Number((d.score / max).toFixed(4));
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
1990
2083
|
return scored;
|
|
1991
2084
|
}
|
|
1992
2085
|
|
|
@@ -1995,13 +2088,13 @@ var log2 = getLogger("query");
|
|
|
1995
2088
|
async function collectMarkdownFiles(dir) {
|
|
1996
2089
|
let entries;
|
|
1997
2090
|
try {
|
|
1998
|
-
entries = await
|
|
2091
|
+
entries = await import_promises11.default.readdir(dir, { withFileTypes: true });
|
|
1999
2092
|
} catch {
|
|
2000
2093
|
return [];
|
|
2001
2094
|
}
|
|
2002
2095
|
const files = [];
|
|
2003
2096
|
for (const entry of entries) {
|
|
2004
|
-
const full =
|
|
2097
|
+
const full = import_node_path10.default.join(dir, entry.name);
|
|
2005
2098
|
if (entry.isDirectory()) {
|
|
2006
2099
|
files.push(...await collectMarkdownFiles(full));
|
|
2007
2100
|
} else if (entry.isFile() && /\.mdx?$/.test(entry.name)) {
|
|
@@ -2028,12 +2121,12 @@ async function nativeSearch(term, collections, collection, hideSystem = false) {
|
|
|
2028
2121
|
const docs = [];
|
|
2029
2122
|
for (const entry of targets) {
|
|
2030
2123
|
for (const full of await collectMarkdownFiles(entry.path)) {
|
|
2031
|
-
const fallbackTitle =
|
|
2124
|
+
const fallbackTitle = import_node_path10.default.basename(full).replace(/\.mdx?$/, "");
|
|
2032
2125
|
let title = fallbackTitle;
|
|
2033
2126
|
let tags = [];
|
|
2034
2127
|
let body = "";
|
|
2035
2128
|
try {
|
|
2036
|
-
const parsed = parseArticle(await
|
|
2129
|
+
const parsed = parseArticle(await import_promises11.default.readFile(full, "utf8"));
|
|
2037
2130
|
if (hideSystem && parsed.audience === "system") continue;
|
|
2038
2131
|
if (parsed.title) title = parsed.title;
|
|
2039
2132
|
tags = parsed.tags;
|
|
@@ -2091,7 +2184,7 @@ async function dropSystemHits(hits) {
|
|
|
2091
2184
|
const kept = [];
|
|
2092
2185
|
for (const hit of hits) {
|
|
2093
2186
|
try {
|
|
2094
|
-
if (parseArticle(await
|
|
2187
|
+
if (parseArticle(await import_promises11.default.readFile(hit.path, "utf8")).audience === "system") continue;
|
|
2095
2188
|
} catch {
|
|
2096
2189
|
}
|
|
2097
2190
|
kept.push(hit);
|
|
@@ -2107,6 +2200,7 @@ async function search(term, opts) {
|
|
|
2107
2200
|
const showSystem = opts?.showSystem ?? await showSystemEnabled();
|
|
2108
2201
|
const hideSystem = !showSystem && wanted.length === 0;
|
|
2109
2202
|
const searchable = hideSystem ? collections.filter((c) => c.audience !== "system") : collections;
|
|
2203
|
+
const systemCollections = new Set(collections.filter((c) => c.audience === "system").map((c) => c.name));
|
|
2110
2204
|
const filterHits = (hits) => wanted.length > 0 ? hits.filter((h) => wanted.includes(h.collection)) : hits;
|
|
2111
2205
|
const engine = opts?.engine ?? await resolveDefaultEngine();
|
|
2112
2206
|
log2.debug(`resolved search engine "${engine}"`);
|
|
@@ -2124,7 +2218,7 @@ async function search(term, opts) {
|
|
|
2124
2218
|
try {
|
|
2125
2219
|
const providerOpts = { ...opts, collection: wanted.length === 1 ? wanted[0] : void 0 };
|
|
2126
2220
|
const raw = filterHits(await provider.handleSearch(term, searchable, providerOpts));
|
|
2127
|
-
const hits = hideSystem ? await dropSystemHits(raw) : raw;
|
|
2221
|
+
const hits = hideSystem ? await dropSystemHits(raw.filter((h) => !systemCollections.has(h.collection))) : raw;
|
|
2128
2222
|
return { hits, engine, fellBackToNative: false };
|
|
2129
2223
|
} catch (err) {
|
|
2130
2224
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -2138,14 +2232,14 @@ async function query(term, opts) {
|
|
|
2138
2232
|
}
|
|
2139
2233
|
|
|
2140
2234
|
// src/search.ts
|
|
2141
|
-
var
|
|
2142
|
-
var
|
|
2235
|
+
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
2236
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
2143
2237
|
init_collections();
|
|
2144
2238
|
var isStatic2 = () => process.env.DIFFWIKI_STATIC === "1";
|
|
2145
2239
|
async function readArticleParts(collDir, slug) {
|
|
2146
2240
|
for (const ext of [".mdx", ".md"]) {
|
|
2147
2241
|
try {
|
|
2148
|
-
const parsed = parseArticle(await
|
|
2242
|
+
const parsed = parseArticle(await import_promises12.default.readFile(import_node_path11.default.join(collDir, `${slug}${ext}`), "utf8"));
|
|
2149
2243
|
return { tags: parsed.tags, body: parsed.body };
|
|
2150
2244
|
} catch {
|
|
2151
2245
|
}
|
|
@@ -2181,7 +2275,7 @@ async function buildSearchIndex(collection) {
|
|
|
2181
2275
|
for (const e of entries) {
|
|
2182
2276
|
try {
|
|
2183
2277
|
const collEntry = await findCollection(e.name);
|
|
2184
|
-
const collDir =
|
|
2278
|
+
const collDir = import_node_path11.default.resolve(collEntry?.path ?? e.path);
|
|
2185
2279
|
if (collEntry?.audience === "system") continue;
|
|
2186
2280
|
if (isStatic2()) {
|
|
2187
2281
|
const cm = await collectionMeta(collDir);
|
|
@@ -2195,15 +2289,15 @@ async function buildSearchIndex(collection) {
|
|
|
2195
2289
|
}
|
|
2196
2290
|
|
|
2197
2291
|
// src/doctor.ts
|
|
2198
|
-
var
|
|
2292
|
+
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
2199
2293
|
init_paths();
|
|
2200
2294
|
init_registry();
|
|
2201
2295
|
init_collections();
|
|
2202
2296
|
|
|
2203
2297
|
// src/plugins/manager.ts
|
|
2204
|
-
var
|
|
2298
|
+
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
2205
2299
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
2206
|
-
var
|
|
2300
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
2207
2301
|
init_paths();
|
|
2208
2302
|
init_errors();
|
|
2209
2303
|
init_collections();
|
|
@@ -2214,7 +2308,7 @@ init_host();
|
|
|
2214
2308
|
var import_node_child_process4 = require("child_process");
|
|
2215
2309
|
var import_node_util3 = require("util");
|
|
2216
2310
|
var import_node_fs = require("fs");
|
|
2217
|
-
var
|
|
2311
|
+
var import_node_path12 = require("path");
|
|
2218
2312
|
var import_node_url = require("url");
|
|
2219
2313
|
var execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process4.execFile);
|
|
2220
2314
|
async function runProcess(file, args, opts) {
|
|
@@ -2230,7 +2324,7 @@ async function runProcess(file, args, opts) {
|
|
|
2230
2324
|
// src/plugins/manager.ts
|
|
2231
2325
|
async function readPackageJson(file) {
|
|
2232
2326
|
try {
|
|
2233
|
-
return JSON.parse(await
|
|
2327
|
+
return JSON.parse(await import_promises13.default.readFile(file, "utf8"));
|
|
2234
2328
|
} catch {
|
|
2235
2329
|
return null;
|
|
2236
2330
|
}
|
|
@@ -2246,7 +2340,7 @@ function binOf(manifest) {
|
|
|
2246
2340
|
async function pluginManifestDirs(nodeModules) {
|
|
2247
2341
|
let entries;
|
|
2248
2342
|
try {
|
|
2249
|
-
entries = await
|
|
2343
|
+
entries = await import_promises13.default.readdir(nodeModules);
|
|
2250
2344
|
} catch {
|
|
2251
2345
|
return [];
|
|
2252
2346
|
}
|
|
@@ -2256,44 +2350,44 @@ async function pluginManifestDirs(nodeModules) {
|
|
|
2256
2350
|
if (entry.startsWith("@")) {
|
|
2257
2351
|
let scoped;
|
|
2258
2352
|
try {
|
|
2259
|
-
scoped = await
|
|
2353
|
+
scoped = await import_promises13.default.readdir(import_node_path13.default.join(nodeModules, entry));
|
|
2260
2354
|
} catch {
|
|
2261
2355
|
continue;
|
|
2262
2356
|
}
|
|
2263
2357
|
for (const pkg of scoped) {
|
|
2264
2358
|
if (pkg.startsWith(".")) continue;
|
|
2265
|
-
dirs.push(
|
|
2359
|
+
dirs.push(import_node_path13.default.join(nodeModules, entry, pkg));
|
|
2266
2360
|
}
|
|
2267
2361
|
} else {
|
|
2268
|
-
dirs.push(
|
|
2362
|
+
dirs.push(import_node_path13.default.join(nodeModules, entry));
|
|
2269
2363
|
}
|
|
2270
2364
|
}
|
|
2271
2365
|
return dirs;
|
|
2272
2366
|
}
|
|
2273
2367
|
async function ensurePluginRoot() {
|
|
2274
2368
|
const dir = pluginsDir();
|
|
2275
|
-
await
|
|
2276
|
-
const pkgPath =
|
|
2369
|
+
await import_promises13.default.mkdir(dir, { recursive: true });
|
|
2370
|
+
const pkgPath = import_node_path13.default.join(dir, "package.json");
|
|
2277
2371
|
if (await readPackageJson(pkgPath) === null) {
|
|
2278
2372
|
const pkg = { name: "diffwiki-plugins", private: true, version: "0.0.0" };
|
|
2279
|
-
await
|
|
2373
|
+
await import_promises13.default.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
2280
2374
|
`, "utf8");
|
|
2281
2375
|
}
|
|
2282
2376
|
return dir;
|
|
2283
2377
|
}
|
|
2284
2378
|
async function asSearchPackage(pkgDir) {
|
|
2285
|
-
const manifest = await readPackageJson(
|
|
2379
|
+
const manifest = await readPackageJson(import_node_path13.default.join(pkgDir, "package.json"));
|
|
2286
2380
|
if (!manifest?.name || manifest.diffwiki?.kind !== "search") return null;
|
|
2287
2381
|
const bin = binOf(manifest);
|
|
2288
2382
|
if (!bin) return null;
|
|
2289
|
-
return { name: manifest.name, version: manifest.version, binAbs:
|
|
2383
|
+
return { name: manifest.name, version: manifest.version, binAbs: import_node_path13.default.resolve(pkgDir, bin) };
|
|
2290
2384
|
}
|
|
2291
2385
|
async function packageNameFromSpec(spec) {
|
|
2292
2386
|
const looksLikePath = spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("~") || spec.startsWith("file:");
|
|
2293
2387
|
if (looksLikePath) {
|
|
2294
2388
|
const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
|
|
2295
|
-
const abs =
|
|
2296
|
-
return (await readPackageJson(
|
|
2389
|
+
const abs = import_node_path13.default.resolve(raw.replace(/^~(?=$|\/)/, import_node_os3.default.homedir()));
|
|
2390
|
+
return (await readPackageJson(import_node_path13.default.join(abs, "package.json")))?.name ?? null;
|
|
2297
2391
|
}
|
|
2298
2392
|
if (/^(git\+|git:|https?:|ssh:)/.test(spec)) return null;
|
|
2299
2393
|
if (spec.startsWith("@")) {
|
|
@@ -2304,10 +2398,10 @@ async function packageNameFromSpec(spec) {
|
|
|
2304
2398
|
return at <= 0 ? spec : spec.slice(0, at);
|
|
2305
2399
|
}
|
|
2306
2400
|
async function resolveSearchPackage(dir, name) {
|
|
2307
|
-
return asSearchPackage(
|
|
2401
|
+
return asSearchPackage(import_node_path13.default.join(dir, "node_modules", ...name.split("/")));
|
|
2308
2402
|
}
|
|
2309
2403
|
async function discoverSearchPackage(dir) {
|
|
2310
|
-
const nodeModules =
|
|
2404
|
+
const nodeModules = import_node_path13.default.join(dir, "node_modules");
|
|
2311
2405
|
for (const pkgDir of await pluginManifestDirs(nodeModules)) {
|
|
2312
2406
|
const found = await asSearchPackage(pkgDir);
|
|
2313
2407
|
if (found) return found;
|
|
@@ -2404,6 +2498,14 @@ async function registerPlugin(name, command) {
|
|
|
2404
2498
|
await runSetup(command, name);
|
|
2405
2499
|
return record;
|
|
2406
2500
|
}
|
|
2501
|
+
async function repairPlugins() {
|
|
2502
|
+
const enabled = (await readPluginRegistry()).plugins.filter((p) => p.enabled && p.kind === "search");
|
|
2503
|
+
const out = [];
|
|
2504
|
+
for (const p of enabled) {
|
|
2505
|
+
out.push({ name: p.name, setup: await runSetup(p.command, p.name) });
|
|
2506
|
+
}
|
|
2507
|
+
return out;
|
|
2508
|
+
}
|
|
2407
2509
|
async function removePlugin(name) {
|
|
2408
2510
|
const record = (await readPluginRegistry()).plugins.find((p) => p.name === name);
|
|
2409
2511
|
if (!record) throw new PluginError(`plugin "${name}" is not registered`);
|
|
@@ -2439,7 +2541,7 @@ init_host();
|
|
|
2439
2541
|
init_types();
|
|
2440
2542
|
async function exists(target) {
|
|
2441
2543
|
try {
|
|
2442
|
-
await
|
|
2544
|
+
await import_promises14.default.access(target);
|
|
2443
2545
|
return true;
|
|
2444
2546
|
} catch {
|
|
2445
2547
|
return false;
|
|
@@ -2545,17 +2647,16 @@ async function appendPluginDiagnostics(out, config) {
|
|
|
2545
2647
|
}
|
|
2546
2648
|
|
|
2547
2649
|
// src/lint.ts
|
|
2548
|
-
var
|
|
2549
|
-
var
|
|
2650
|
+
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
2651
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
2550
2652
|
init_collections();
|
|
2551
2653
|
init_errors();
|
|
2552
2654
|
var BUDGETS = {
|
|
2553
2655
|
recipe: { min: 300, max: 1e3 },
|
|
2554
2656
|
"recipe-steps": { min: 500, max: 1500 },
|
|
2555
2657
|
guide: { min: 1500, max: 5e3 },
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
// Fallback for a bare `architecture` tag when system vs component isn't declared.
|
|
2658
|
+
reference: { min: 300, max: 2e3 },
|
|
2659
|
+
// Generic fallback budget for a bare `architecture` tag (no dedicated template).
|
|
2559
2660
|
architecture: { min: 1e3, max: 6e3 }
|
|
2560
2661
|
};
|
|
2561
2662
|
function estimateTokens(body) {
|
|
@@ -2564,8 +2665,7 @@ function estimateTokens(body) {
|
|
|
2564
2665
|
function inferShape(tags, body) {
|
|
2565
2666
|
const t = new Set(tags.map((x) => x.toLowerCase()));
|
|
2566
2667
|
if (t.has("guide")) return "guide";
|
|
2567
|
-
if (t.has("
|
|
2568
|
-
if (t.has("system-design") || t.has("system")) return "system-design";
|
|
2668
|
+
if (t.has("reference")) return "reference";
|
|
2569
2669
|
if (t.has("architecture")) return "architecture";
|
|
2570
2670
|
if (/^###\s+Step\b/im.test(body)) return "recipe-steps";
|
|
2571
2671
|
return "recipe";
|
|
@@ -2636,13 +2736,13 @@ function lintArticle(article) {
|
|
|
2636
2736
|
async function walkMarkdown(dir) {
|
|
2637
2737
|
let entries;
|
|
2638
2738
|
try {
|
|
2639
|
-
entries = await
|
|
2739
|
+
entries = await import_promises15.default.readdir(dir, { withFileTypes: true });
|
|
2640
2740
|
} catch {
|
|
2641
2741
|
return [];
|
|
2642
2742
|
}
|
|
2643
2743
|
const out = [];
|
|
2644
2744
|
for (const e of entries) {
|
|
2645
|
-
const full =
|
|
2745
|
+
const full = import_node_path14.default.join(dir, e.name);
|
|
2646
2746
|
if (e.isDirectory()) out.push(...await walkMarkdown(full));
|
|
2647
2747
|
else if (e.isFile() && /\.mdx?$/.test(e.name) && !/-template\.mdx?$/.test(e.name)) out.push(full);
|
|
2648
2748
|
}
|
|
@@ -2672,11 +2772,11 @@ async function lintCollections(scope) {
|
|
|
2672
2772
|
let warnCount = 0;
|
|
2673
2773
|
for (const coll of collections) {
|
|
2674
2774
|
for (const full of await walkMarkdown(coll.path)) {
|
|
2675
|
-
const rel =
|
|
2775
|
+
const rel = import_node_path14.default.relative(coll.path, full);
|
|
2676
2776
|
const label = `${coll.name}/${rel}`;
|
|
2677
2777
|
let findings = [];
|
|
2678
2778
|
try {
|
|
2679
|
-
const parsed = parseArticle(await
|
|
2779
|
+
const parsed = parseArticle(await import_promises15.default.readFile(full, "utf8"));
|
|
2680
2780
|
findings = lintArticle(parsed);
|
|
2681
2781
|
} catch (err) {
|
|
2682
2782
|
findings = [{ level: "error", rule: "parse", message: `could not parse: ${err.message}` }];
|
|
@@ -2803,11 +2903,14 @@ init_registry2();
|
|
|
2803
2903
|
listEnabledPlugins,
|
|
2804
2904
|
listPlugins,
|
|
2805
2905
|
listSearchModes,
|
|
2906
|
+
listTemplateShapes,
|
|
2907
|
+
listTemplates,
|
|
2806
2908
|
loadSearchProvider,
|
|
2807
2909
|
localGraph,
|
|
2808
2910
|
nativeSearch,
|
|
2809
2911
|
parseAddTarget,
|
|
2810
2912
|
parseArticle,
|
|
2913
|
+
parseFrontmatter,
|
|
2811
2914
|
parsePathTarget,
|
|
2812
2915
|
pluginsDir,
|
|
2813
2916
|
pluginsRegistryPath,
|
|
@@ -2829,6 +2932,7 @@ init_registry2();
|
|
|
2829
2932
|
removePlugin,
|
|
2830
2933
|
removeTags,
|
|
2831
2934
|
renderArticle,
|
|
2935
|
+
repairPlugins,
|
|
2832
2936
|
repoId,
|
|
2833
2937
|
repoRemoteName,
|
|
2834
2938
|
resolveCollectionSelection,
|
|
@@ -2842,13 +2946,17 @@ init_registry2();
|
|
|
2842
2946
|
resolveProjectCollections,
|
|
2843
2947
|
search,
|
|
2844
2948
|
seedProjectHome,
|
|
2949
|
+
seedTemplates,
|
|
2845
2950
|
serializeArticle,
|
|
2846
2951
|
setArticleMeta,
|
|
2847
2952
|
setConfigValue,
|
|
2953
|
+
setContextCollections,
|
|
2848
2954
|
setTags,
|
|
2849
2955
|
showSystemEnabled,
|
|
2850
2956
|
slugify,
|
|
2851
2957
|
slugifyPath,
|
|
2958
|
+
stripFrontmatter,
|
|
2959
|
+
templatesDir,
|
|
2852
2960
|
toTreeNodes,
|
|
2853
2961
|
tokenize,
|
|
2854
2962
|
unregisterCollection,
|