@riebeckite/core 0.0.16 → 0.0.17
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/README.md +1 -1
- package/README_ja.md +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +284 -208
- package/dist/src/content/content_build_coordinator.d.ts +1 -1
- package/dist/src/content/content_build_state.d.ts +1 -1
- package/dist/src/content/content_dependency_tracker.d.ts +2 -0
- package/dist/src/content/content_language.d.ts +3 -0
- package/dist/src/content/content_stable_id.d.ts +1 -4
- package/dist/src/content/file_system_content_source.d.ts +10 -1
- package/dist/src/pipeline.d.ts +1 -0
- package/dist/src/plugin/plugin_lifecycle.d.ts +6 -4
- package/dist/src/plugin/plugin_runtime.d.ts +5 -2
- package/dist/src/types/content_manifest.d.ts +6 -4
- package/dist/src/types/plugin.d.ts +0 -2
- package/dist/src/types/plugin_page.d.ts +2 -0
- package/dist/src/types/plugin_seo.d.ts +3 -2
- package/dist/src/types/post_content.d.ts +0 -2
- package/dist/src/types/resolved_riebeckite_config.d.ts +7 -8
- package/dist/src/types/riebeckite_config.d.ts +0 -7
- package/package.json +2 -2
- package/dist/src/types/navigation_config.d.ts +0 -10
package/README.md
CHANGED
package/README_ja.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -10,16 +10,19 @@ export { buildContentCollections } from "./src/content/content_collection.js";
|
|
|
10
10
|
export { fingerprintContentEntries } from "./src/content/content_fingerprint.js";
|
|
11
11
|
export type { ContentGraph, ContentGraphNeighbors, } from "./src/content/content_graph.js";
|
|
12
12
|
export { createContentGraph } from "./src/content/content_graph.js";
|
|
13
|
+
export { getEntryLanguage, selectEntriesByLanguage, } from "./src/content/content_language.js";
|
|
13
14
|
export { resolveDefaultContentLocation } from "./src/content/content_location.js";
|
|
14
15
|
export type { ContentBuildOptions, ContentInspection, } from "./src/content/content_manager.js";
|
|
15
16
|
export { ContentManager } from "./src/content/content_manager.js";
|
|
16
17
|
export { extractFrontmatterAliases } from "./src/content/content_metadata.js";
|
|
18
|
+
export { computePipelineFingerprint, isPersistentlyCacheable, } from "./src/content/content_persistent_cache.js";
|
|
17
19
|
export type { ContentQueryDateFilter, ContentQueryDateGranularity, ContentQueryFilter, ContentQueryFrontmatterFilter, ContentQueryGroup, ContentQueryGroupBy, ContentQueryGroupOptions, ContentQueryPage, ContentQueryPagination, ContentQueryScalar, ContentQuerySort, ContentQuerySortOrder, ContentQuerySpec, ContentQueryTagFilter, } from "./src/content/content_query.js";
|
|
18
20
|
export { groupContentEntries, queryContentEntries, queryContentPage, resolveContentQueryPagination, } from "./src/content/content_query.js";
|
|
19
21
|
export type { ContentSource, ContentSourceContent, ContentSourceEntry, ContentSourceMetadata, } from "./src/content/content_source.js";
|
|
20
22
|
export { getContentSourceEntry, readContentSourceEntry, } from "./src/content/content_source.js";
|
|
21
23
|
export { resolveContentStableId } from "./src/content/content_stable_id.js";
|
|
22
|
-
export {
|
|
24
|
+
export type { ContentSourceExclusion, ContentSourceScan, } from "./src/content/file_system_content_source.js";
|
|
25
|
+
export { FileSystemContentSource, INTERNAL_CONTENT_IGNORE_PATTERNS, isIgnoredContentPath, matchContentExcludePattern, } from "./src/content/file_system_content_source.js";
|
|
23
26
|
export type { FolderEntryCandidate, FolderEntryKind, FolderEntryResolution, FolderEntryScope, FolderLocationResolution, ResolveFolderEntryOptions, } from "./src/content/folder_entry.js";
|
|
24
27
|
export { resolveFolderEntry, resolveFolderLocation, resolveGeneratedFolderLocation, resolvePublicFolderLocation, } from "./src/content/folder_entry.js";
|
|
25
28
|
export type { ForceGraphLayoutOptions, GraphEdge, GraphLayoutNode, LinkableGraphNode, RadialGraphLayoutOptions, } from "./src/content/graph_layout.js";
|
|
@@ -46,7 +49,6 @@ export type { Diagnostic, DiagnosticCode, DiagnosticSeverity, } from "./src/type
|
|
|
46
49
|
export type { ContentAssetOutputInput, GeneratedOutput, GeneratedOutputContent, GeneratedOutputInput, GeneratedOutputSink, } from "./src/types/generated_output.js";
|
|
47
50
|
export { createUnavailableGeneratedOutputSink, normalizeContentAssetOutputPath, normalizeGeneratedOutputPath, } from "./src/types/generated_output.js";
|
|
48
51
|
export type { JsonValue } from "./src/types/json_value.js";
|
|
49
|
-
export type { NavigationConfig, NavigationItem, } from "./src/types/navigation_config.js";
|
|
50
52
|
export type { OutputDependency } from "./src/types/output_dependency.js";
|
|
51
53
|
export type { PluginInput, ResolvedPluginMetadata, RiebeckitePlugin, } from "./src/types/plugin.js";
|
|
52
54
|
export { definePlugin, getResolvedPluginMetadata, resolvePlugins, } from "./src/types/plugin.js";
|
package/dist/index.js
CHANGED
|
@@ -18,55 +18,12 @@ function validateConfigIssues(config) {
|
|
|
18
18
|
return [{ path: "config", message: "Expected an object." }];
|
|
19
19
|
}
|
|
20
20
|
validateSite(value.site, issues);
|
|
21
|
-
validateNavigation(value.navigation, issues);
|
|
22
21
|
validateContent(value.content, issues);
|
|
22
|
+
validateCache(value.cache, issues);
|
|
23
23
|
validateTheme(value.theme, issues);
|
|
24
24
|
validatePlugins(value.plugins, issues);
|
|
25
25
|
return issues;
|
|
26
26
|
}
|
|
27
|
-
function validateNavigation(value, issues) {
|
|
28
|
-
if (value === void 0) return;
|
|
29
|
-
if (!isRecord(value)) {
|
|
30
|
-
issues.push({ path: "navigation", message: "Expected an object." });
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
validateNavigationItems(value.header, "navigation.header", issues, /* @__PURE__ */ new Set());
|
|
34
|
-
validateNavigationItems(value.footer, "navigation.footer", issues, /* @__PURE__ */ new Set());
|
|
35
|
-
}
|
|
36
|
-
function validateNavigationItems(value, path5, issues, ancestors) {
|
|
37
|
-
if (value === void 0) return;
|
|
38
|
-
if (!Array.isArray(value)) {
|
|
39
|
-
issues.push({ path: path5, message: "Expected an array." });
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
for (const [index, item] of value.entries()) {
|
|
43
|
-
const itemPath = `${path5}[${index}]`;
|
|
44
|
-
if (!isRecord(item)) {
|
|
45
|
-
issues.push({ path: itemPath, message: "Expected an object." });
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
if (ancestors.has(item)) {
|
|
49
|
-
issues.push({
|
|
50
|
-
path: itemPath,
|
|
51
|
-
message: "Navigation children must not be recursive."
|
|
52
|
-
});
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
validateRequiredString(item.label, `${itemPath}.label`, issues);
|
|
56
|
-
validateRequiredString(item.href, `${itemPath}.href`, issues);
|
|
57
|
-
validateOptionalBoolean(item.external, `${itemPath}.external`, issues);
|
|
58
|
-
if (item.children !== void 0) {
|
|
59
|
-
const nextAncestors = new Set(ancestors);
|
|
60
|
-
nextAncestors.add(item);
|
|
61
|
-
validateNavigationItems(
|
|
62
|
-
item.children,
|
|
63
|
-
`${itemPath}.children`,
|
|
64
|
-
issues,
|
|
65
|
-
nextAncestors
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
27
|
function validateSite(value, issues) {
|
|
71
28
|
if (!isRecord(value)) {
|
|
72
29
|
issues.push({ path: "site", message: "Expected an object." });
|
|
@@ -137,6 +94,15 @@ function validatePublishStrategy(value, issues) {
|
|
|
137
94
|
});
|
|
138
95
|
}
|
|
139
96
|
}
|
|
97
|
+
function validateCache(value, issues) {
|
|
98
|
+
if (value === void 0) return;
|
|
99
|
+
if (!isRecord(value)) {
|
|
100
|
+
issues.push({ path: "cache", message: "Expected an object." });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
validateOptionalBoolean(value.enabled, "cache.enabled", issues);
|
|
104
|
+
validateOptionalString(value.directory, "cache.directory", issues);
|
|
105
|
+
}
|
|
140
106
|
function validateTheme(value, issues) {
|
|
141
107
|
if (value === void 0) return;
|
|
142
108
|
if (!isRecord(value)) {
|
|
@@ -669,23 +635,14 @@ function resolveConfig(config) {
|
|
|
669
635
|
language: config.site?.feed?.language ?? config.site?.locale ?? "en"
|
|
670
636
|
}
|
|
671
637
|
},
|
|
672
|
-
navigation: {
|
|
673
|
-
header: config.navigation?.header ?? [],
|
|
674
|
-
footer: config.navigation?.footer ?? []
|
|
675
|
-
},
|
|
676
638
|
content: {
|
|
677
|
-
directory: config.content?.directory ?? "
|
|
639
|
+
directory: config.content?.directory ?? "content",
|
|
678
640
|
source: config.content?.source,
|
|
679
641
|
exclude: config.content?.exclude ?? [],
|
|
680
642
|
filters: {
|
|
681
643
|
publishStrategy: config.content?.filters?.publishStrategy ?? "explicit"
|
|
682
644
|
}
|
|
683
645
|
},
|
|
684
|
-
markdown: {
|
|
685
|
-
syntaxHighlight: {
|
|
686
|
-
theme: config.markdown?.syntaxHighlight?.theme ?? ""
|
|
687
|
-
}
|
|
688
|
-
},
|
|
689
646
|
theme,
|
|
690
647
|
plugins: resolvePlugins(config.plugins),
|
|
691
648
|
cache: {
|
|
@@ -853,7 +810,7 @@ import fs from "node:fs/promises";
|
|
|
853
810
|
import path from "node:path";
|
|
854
811
|
|
|
855
812
|
// src/content/content_build_state.ts
|
|
856
|
-
var CONTENT_BUILD_STATE_VERSION =
|
|
813
|
+
var CONTENT_BUILD_STATE_VERSION = 7;
|
|
857
814
|
var CONTENT_BUILD_STATE_DIRECTORY = ".riebeckite";
|
|
858
815
|
var CONTENT_BUILD_STATE_EXCLUDE = `${CONTENT_BUILD_STATE_DIRECTORY}/**`;
|
|
859
816
|
|
|
@@ -1370,6 +1327,23 @@ function isResolvedNoteLink(link) {
|
|
|
1370
1327
|
return link.kind === "note" && link.slug !== null;
|
|
1371
1328
|
}
|
|
1372
1329
|
|
|
1330
|
+
// src/content/content_language.ts
|
|
1331
|
+
function getEntryLanguage(entry) {
|
|
1332
|
+
return entry.publicLocation.language;
|
|
1333
|
+
}
|
|
1334
|
+
function selectEntriesByLanguage(entries, language) {
|
|
1335
|
+
if (!language) {
|
|
1336
|
+
return entries;
|
|
1337
|
+
}
|
|
1338
|
+
const localized = entries.filter(
|
|
1339
|
+
(entry) => getEntryLanguage(entry) !== void 0
|
|
1340
|
+
);
|
|
1341
|
+
if (localized.length === 0) {
|
|
1342
|
+
return entries;
|
|
1343
|
+
}
|
|
1344
|
+
return localized.filter((entry) => getEntryLanguage(entry) === language);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1373
1347
|
// src/content/content_location.ts
|
|
1374
1348
|
function resolveDefaultContentLocation(content) {
|
|
1375
1349
|
return {
|
|
@@ -1527,6 +1501,8 @@ import { matter as matter2 } from "vfile-matter";
|
|
|
1527
1501
|
|
|
1528
1502
|
// src/content/content_dependency_tracker.ts
|
|
1529
1503
|
import { createHash as createHash2 } from "node:crypto";
|
|
1504
|
+
var LINK_INDEX_PREFIX = "index:";
|
|
1505
|
+
var LINK_LOCATION_PREFIX = "location:";
|
|
1530
1506
|
function createContentDependencyTracker(source) {
|
|
1531
1507
|
const dependencies = /* @__PURE__ */ new Map();
|
|
1532
1508
|
const record = (identity, content) => {
|
|
@@ -1572,6 +1548,30 @@ function dependencyKey(dependency) {
|
|
|
1572
1548
|
return `${normalized.kind}:${normalized.id}`;
|
|
1573
1549
|
}
|
|
1574
1550
|
|
|
1551
|
+
// src/content/content_links.ts
|
|
1552
|
+
var WIKILINK_PATTERN = /(!)?\[\[([^\]|#^]+)(?:[#^][^\]|]+)?(?:\|[^\]]+)?\]\]/g;
|
|
1553
|
+
function extractContentLinks(markdown, contentIndex) {
|
|
1554
|
+
WIKILINK_PATTERN.lastIndex = 0;
|
|
1555
|
+
const links = [];
|
|
1556
|
+
for (let match = WIKILINK_PATTERN.exec(markdown); match !== null; match = WIKILINK_PATTERN.exec(markdown)) {
|
|
1557
|
+
const rawTarget = match[2]?.trim();
|
|
1558
|
+
if (!rawTarget) continue;
|
|
1559
|
+
const resolved = contentIndex.get(rawTarget.toLowerCase()) ?? null;
|
|
1560
|
+
links.push({
|
|
1561
|
+
raw: rawTarget,
|
|
1562
|
+
slug: resolved,
|
|
1563
|
+
kind: resolved ? linkKind(resolved) : "unresolved",
|
|
1564
|
+
embed: match[1] === "!"
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
return links;
|
|
1568
|
+
}
|
|
1569
|
+
function linkKind(value) {
|
|
1570
|
+
if (isImagePath(value)) return "image";
|
|
1571
|
+
if (isAttachmentPath(value)) return "attachment";
|
|
1572
|
+
return "note";
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
1575
|
// src/content/content_persistent_cache.ts
|
|
1576
1576
|
import { createHash as createHash4 } from "node:crypto";
|
|
1577
1577
|
import fs2 from "node:fs/promises";
|
|
@@ -1768,7 +1768,6 @@ function computePipelineFingerprint(config) {
|
|
|
1768
1768
|
const fingerprintData = {
|
|
1769
1769
|
compatibilityVersion: CONTENT_CACHE_COMPATIBILITY_VERSION,
|
|
1770
1770
|
plugins: plugins.map((p) => pluginFingerprint(p)),
|
|
1771
|
-
markdown: config.markdown,
|
|
1772
1771
|
content: {
|
|
1773
1772
|
filters: config.content.filters
|
|
1774
1773
|
}
|
|
@@ -1933,6 +1932,7 @@ async function writeAtomically2(targetPath, versionDirectory2, serialized) {
|
|
|
1933
1932
|
}
|
|
1934
1933
|
function resolvePluginCacheDirectory(config) {
|
|
1935
1934
|
if (!config) return path3.resolve(process.cwd(), ".riebeckite", "cache");
|
|
1935
|
+
if (config.cache?.directory) return config.cache.directory;
|
|
1936
1936
|
if (config.buildDirectory) return path3.join(config.buildDirectory, "cache");
|
|
1937
1937
|
return path3.resolve(config.content.directory, "..", ".riebeckite", "cache");
|
|
1938
1938
|
}
|
|
@@ -2201,6 +2201,9 @@ var Pipeline = class {
|
|
|
2201
2201
|
frontmatter: file.data.matter || {},
|
|
2202
2202
|
html: String(file.value)
|
|
2203
2203
|
};
|
|
2204
|
+
if (embedDepth === 0 && sourceSlug && dependencyTracker) {
|
|
2205
|
+
this.recordNoteLinkDependencies(markDownContent, dependencyTracker);
|
|
2206
|
+
}
|
|
2204
2207
|
if (sourceSlug && dependencyTracker) {
|
|
2205
2208
|
this.reportContentDependencies(
|
|
2206
2209
|
sourceSlug,
|
|
@@ -2250,6 +2253,25 @@ var Pipeline = class {
|
|
|
2250
2253
|
this.options.isRoutable
|
|
2251
2254
|
);
|
|
2252
2255
|
}
|
|
2256
|
+
recordNoteLinkDependencies(markdown, dependencyTracker) {
|
|
2257
|
+
for (const link of extractContentLinks(markdown, this.contentIndex)) {
|
|
2258
|
+
if (link.slug !== null && link.kind === "note") {
|
|
2259
|
+
const id = `${LINK_LOCATION_PREFIX}${link.slug}`;
|
|
2260
|
+
dependencyTracker.recordLinkResolution(
|
|
2261
|
+
id,
|
|
2262
|
+
this.resolveLinkDependency(id)
|
|
2263
|
+
);
|
|
2264
|
+
continue;
|
|
2265
|
+
}
|
|
2266
|
+
if (link.kind === "unresolved") {
|
|
2267
|
+
const id = `${LINK_INDEX_PREFIX}${link.raw.toLowerCase()}`;
|
|
2268
|
+
dependencyTracker.recordLinkResolution(
|
|
2269
|
+
id,
|
|
2270
|
+
this.resolveLinkDependency(id)
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2253
2275
|
use(processor, plugin, options) {
|
|
2254
2276
|
const register = processor.use.bind(processor);
|
|
2255
2277
|
if (options === void 0) {
|
|
@@ -2353,8 +2375,6 @@ function normalizeMarkdownLinks(context) {
|
|
|
2353
2375
|
});
|
|
2354
2376
|
};
|
|
2355
2377
|
}
|
|
2356
|
-
var LINK_INDEX_PREFIX = "index:";
|
|
2357
|
-
var LINK_LOCATION_PREFIX = "location:";
|
|
2358
2378
|
function resolveLinkDependencyValue(id, contentIndex, lookupPermalink, isRoutable) {
|
|
2359
2379
|
if (id.startsWith(LINK_INDEX_PREFIX)) {
|
|
2360
2380
|
return contentIndex.get(id.slice(LINK_INDEX_PREFIX.length)) ?? "";
|
|
@@ -2565,12 +2585,26 @@ var GeneratedOutputRegistry = class {
|
|
|
2565
2585
|
};
|
|
2566
2586
|
|
|
2567
2587
|
// src/plugin/plugin_lifecycle.ts
|
|
2568
|
-
var
|
|
2588
|
+
var PluginHookError = class extends Error {
|
|
2569
2589
|
constructor(pluginName, hookName, cause) {
|
|
2570
2590
|
super(`Plugin "${pluginName}" failed during "${hookName}"`, { cause });
|
|
2571
|
-
this.name = "
|
|
2591
|
+
this.name = "PluginHookError";
|
|
2572
2592
|
}
|
|
2573
2593
|
};
|
|
2594
|
+
async function runPluginHook(plugin, hookName, context, hook) {
|
|
2595
|
+
try {
|
|
2596
|
+
return await context.tracer.span(
|
|
2597
|
+
`plugin.${hookName}`,
|
|
2598
|
+
{
|
|
2599
|
+
plugin: plugin.name,
|
|
2600
|
+
hook: hookName
|
|
2601
|
+
},
|
|
2602
|
+
() => hook(context)
|
|
2603
|
+
);
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
throw new PluginHookError(plugin.name, hookName, error);
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2574
2608
|
async function runSetup(plugins, createContext) {
|
|
2575
2609
|
await runLifecycleHook(
|
|
2576
2610
|
plugins,
|
|
@@ -2607,19 +2641,7 @@ async function runLifecycleHook(plugins, hookName, getHook, createContext) {
|
|
|
2607
2641
|
for (const plugin of plugins) {
|
|
2608
2642
|
const hook = getHook(plugin);
|
|
2609
2643
|
if (!hook) continue;
|
|
2610
|
-
|
|
2611
|
-
const context = createContext(plugin);
|
|
2612
|
-
await context.tracer.span(
|
|
2613
|
-
`plugin.${hookName}`,
|
|
2614
|
-
{
|
|
2615
|
-
plugin: plugin.name,
|
|
2616
|
-
hook: hookName
|
|
2617
|
-
},
|
|
2618
|
-
() => hook(context)
|
|
2619
|
-
);
|
|
2620
|
-
} catch (error) {
|
|
2621
|
-
throw new PluginLifecycleError(plugin.name, hookName, error);
|
|
2622
|
-
}
|
|
2644
|
+
await runPluginHook(plugin, hookName, createContext(plugin), hook);
|
|
2623
2645
|
}
|
|
2624
2646
|
}
|
|
2625
2647
|
|
|
@@ -2637,6 +2659,7 @@ var PluginRuntime = class {
|
|
|
2637
2659
|
generatedOutputs = new GeneratedOutputRegistry();
|
|
2638
2660
|
isBuildTime = false;
|
|
2639
2661
|
resolvedPlugins = null;
|
|
2662
|
+
pageDeclarations = /* @__PURE__ */ new WeakMap();
|
|
2640
2663
|
getDiagnostics() {
|
|
2641
2664
|
return this.diagnostics;
|
|
2642
2665
|
}
|
|
@@ -2647,7 +2670,7 @@ var PluginRuntime = class {
|
|
|
2647
2670
|
* Starts the plugin build lifecycle exactly once, regardless of which public
|
|
2648
2671
|
* entry point (content processing or location resolution) reaches it first.
|
|
2649
2672
|
* Concurrent callers await the same run, so the ordered hooks
|
|
2650
|
-
* (`setup` → `buildStart` → `
|
|
2673
|
+
* (`setup` → `buildStart` → `onConfigResolved`) are never
|
|
2651
2674
|
* duplicated and no caller proceeds before the lifecycle completes.
|
|
2652
2675
|
*/
|
|
2653
2676
|
startBuild(contentIndex) {
|
|
@@ -2655,7 +2678,7 @@ var PluginRuntime = class {
|
|
|
2655
2678
|
return this.buildLifecycle;
|
|
2656
2679
|
}
|
|
2657
2680
|
async runContentLoaded(slug, markdown, contentIndex) {
|
|
2658
|
-
await this.runHook((plugin) => plugin.onContentLoaded, {
|
|
2681
|
+
await this.runHook("onContentLoaded", (plugin) => plugin.onContentLoaded, {
|
|
2659
2682
|
...this.createContext(contentIndex),
|
|
2660
2683
|
slug,
|
|
2661
2684
|
markdown
|
|
@@ -2667,22 +2690,30 @@ var PluginRuntime = class {
|
|
|
2667
2690
|
for (const plugin of this.plugins()) {
|
|
2668
2691
|
const resolver = plugin.resolveContentLocations;
|
|
2669
2692
|
if (!resolver) continue;
|
|
2670
|
-
const
|
|
2671
|
-
|
|
2693
|
+
const pluginContext = this.createPluginContext(plugin, context);
|
|
2694
|
+
const resolved = await runPluginHook(
|
|
2695
|
+
plugin,
|
|
2696
|
+
"resolveContentLocations",
|
|
2697
|
+
pluginContext,
|
|
2698
|
+
resolver
|
|
2672
2699
|
);
|
|
2673
2700
|
locations.push(...resolved);
|
|
2674
2701
|
}
|
|
2675
2702
|
return locations;
|
|
2676
2703
|
}
|
|
2677
2704
|
async extendContentLocations(entries, locations, contentIndex) {
|
|
2678
|
-
await this.runHook(
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2705
|
+
await this.runHook(
|
|
2706
|
+
"extendContentLocations",
|
|
2707
|
+
(plugin) => plugin.extendContentLocations,
|
|
2708
|
+
{
|
|
2709
|
+
...this.createContext(contentIndex),
|
|
2710
|
+
entries,
|
|
2711
|
+
locations
|
|
2712
|
+
}
|
|
2713
|
+
);
|
|
2683
2714
|
}
|
|
2684
2715
|
async runPostHook(hookName, slug, markdown, content, contentIndex) {
|
|
2685
|
-
await this.runHook((plugin) => plugin[hookName], {
|
|
2716
|
+
await this.runHook(hookName, (plugin) => plugin[hookName], {
|
|
2686
2717
|
...this.createContext(contentIndex),
|
|
2687
2718
|
slug,
|
|
2688
2719
|
markdown,
|
|
@@ -2690,16 +2721,24 @@ var PluginRuntime = class {
|
|
|
2690
2721
|
});
|
|
2691
2722
|
}
|
|
2692
2723
|
async runGraphHook(entries, contentIndex) {
|
|
2693
|
-
await this.runHook(
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2724
|
+
await this.runHook(
|
|
2725
|
+
"extendContentGraph",
|
|
2726
|
+
(plugin) => plugin.extendContentGraph,
|
|
2727
|
+
{
|
|
2728
|
+
...this.createContext(contentIndex),
|
|
2729
|
+
entries
|
|
2730
|
+
}
|
|
2731
|
+
);
|
|
2697
2732
|
}
|
|
2698
2733
|
async runManifestCreated(manifest, contentIndex) {
|
|
2699
|
-
await this.runHook(
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2734
|
+
await this.runHook(
|
|
2735
|
+
"onManifestCreated",
|
|
2736
|
+
(plugin) => plugin.onManifestCreated,
|
|
2737
|
+
{
|
|
2738
|
+
...this.createContext(contentIndex),
|
|
2739
|
+
manifest
|
|
2740
|
+
}
|
|
2741
|
+
);
|
|
2703
2742
|
}
|
|
2704
2743
|
async runBuildEnd(manifest, contentIndex) {
|
|
2705
2744
|
const context = {
|
|
@@ -2710,10 +2749,6 @@ var PluginRuntime = class {
|
|
|
2710
2749
|
this.plugins(),
|
|
2711
2750
|
(plugin) => this.createPluginContext(plugin, context)
|
|
2712
2751
|
);
|
|
2713
|
-
await this.runHook((plugin) => plugin.onBuildEnd, {
|
|
2714
|
-
...this.createContext(contentIndex),
|
|
2715
|
-
manifest
|
|
2716
|
-
});
|
|
2717
2752
|
}
|
|
2718
2753
|
enableBuildTime() {
|
|
2719
2754
|
this.isBuildTime = true;
|
|
@@ -2795,63 +2830,74 @@ var PluginRuntime = class {
|
|
|
2795
2830
|
return highest[0].page;
|
|
2796
2831
|
}
|
|
2797
2832
|
async getPagePaths(manifest, contentIndex) {
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
for (const rawPath of resolved) {
|
|
2806
|
-
paths.push(normalizePageTypePath(rawPath, pageType));
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
|
-
}
|
|
2810
|
-
return [...new Set(paths)];
|
|
2833
|
+
return [
|
|
2834
|
+
...new Set(
|
|
2835
|
+
(await this.getPageDeclarations(manifest, contentIndex)).map(
|
|
2836
|
+
(declaration) => declaration.pathname
|
|
2837
|
+
)
|
|
2838
|
+
)
|
|
2839
|
+
];
|
|
2811
2840
|
}
|
|
2812
2841
|
async getPageRoutes(manifest, contentIndex) {
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
for (const pathname of paths) {
|
|
2821
|
-
routes.push({
|
|
2822
|
-
pathname: normalizePageTypePath(pathname, pageType),
|
|
2823
|
-
pluginName: plugin.name,
|
|
2824
|
-
pageType: pageType.id
|
|
2825
|
-
});
|
|
2826
|
-
}
|
|
2827
|
-
}
|
|
2828
|
-
}
|
|
2829
|
-
return routes;
|
|
2842
|
+
return (await this.getPageDeclarations(manifest, contentIndex)).map(
|
|
2843
|
+
({ pathname, plugin, pageType }) => ({
|
|
2844
|
+
pathname,
|
|
2845
|
+
pluginName: plugin.name,
|
|
2846
|
+
pageType: pageType.id
|
|
2847
|
+
})
|
|
2848
|
+
);
|
|
2830
2849
|
}
|
|
2831
2850
|
async getPageOutputs(manifest, contentIndex) {
|
|
2832
|
-
const outputs =
|
|
2851
|
+
const outputs = await Promise.all(
|
|
2852
|
+
(await this.getPageDeclarations(manifest, contentIndex)).map(
|
|
2853
|
+
async ({ pathname, plugin, pageType }) => {
|
|
2854
|
+
const context = {
|
|
2855
|
+
...this.createContext(contentIndex),
|
|
2856
|
+
manifest,
|
|
2857
|
+
pathname
|
|
2858
|
+
};
|
|
2859
|
+
const dependencies = pageType.outputDependencies ? typeof pageType.outputDependencies === "function" ? await pageType.outputDependencies(
|
|
2860
|
+
this.createPluginContext(plugin, context)
|
|
2861
|
+
) : pageType.outputDependencies : [{ type: "unknown" }];
|
|
2862
|
+
return {
|
|
2863
|
+
output: {
|
|
2864
|
+
kind: "plugin-page",
|
|
2865
|
+
path: pathname,
|
|
2866
|
+
producer: `plugin:${plugin.name}:page:${pageType.id}`,
|
|
2867
|
+
dependencies
|
|
2868
|
+
},
|
|
2869
|
+
priority: pageType.priority ?? 0
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2872
|
+
)
|
|
2873
|
+
);
|
|
2874
|
+
return uniqueOutputs(outputs);
|
|
2875
|
+
}
|
|
2876
|
+
async getPageDeclarations(manifest, contentIndex) {
|
|
2877
|
+
const existing = this.pageDeclarations.get(manifest);
|
|
2878
|
+
if (existing) return await existing;
|
|
2879
|
+
const declarations = this.resolvePageDeclarations(manifest, contentIndex);
|
|
2880
|
+
this.pageDeclarations.set(manifest, declarations);
|
|
2881
|
+
return await declarations;
|
|
2882
|
+
}
|
|
2883
|
+
async resolvePageDeclarations(manifest, contentIndex) {
|
|
2884
|
+
const declarations = [];
|
|
2833
2885
|
const context = { ...this.createContext(contentIndex), manifest };
|
|
2834
2886
|
for (const plugin of this.plugins()) {
|
|
2835
2887
|
for (const pageType of plugin.pageTypes ?? []) {
|
|
2836
|
-
const
|
|
2837
|
-
if (!
|
|
2838
|
-
const
|
|
2839
|
-
for (const
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
) : pageType.outputDependencies : [{ type: "unknown" }];
|
|
2845
|
-
outputs.push({
|
|
2846
|
-
kind: "plugin-page",
|
|
2847
|
-
path: pathname,
|
|
2848
|
-
producer: `plugin:${plugin.name}:page:${pageType.id}`,
|
|
2849
|
-
dependencies
|
|
2888
|
+
const paths = pageType.paths;
|
|
2889
|
+
if (!paths) continue;
|
|
2890
|
+
const resolved = typeof paths === "function" ? await paths(this.createPluginContext(plugin, context)) : paths;
|
|
2891
|
+
for (const pathname of resolved) {
|
|
2892
|
+
declarations.push({
|
|
2893
|
+
pathname: normalizePageTypePath(pathname, pageType),
|
|
2894
|
+
plugin,
|
|
2895
|
+
pageType
|
|
2850
2896
|
});
|
|
2851
2897
|
}
|
|
2852
2898
|
}
|
|
2853
2899
|
}
|
|
2854
|
-
return
|
|
2900
|
+
return declarations;
|
|
2855
2901
|
}
|
|
2856
2902
|
getContentOutputDependencies() {
|
|
2857
2903
|
return this.plugins().flatMap((plugin) => plugin.outputDependencies ?? []);
|
|
@@ -2862,9 +2908,13 @@ var PluginRuntime = class {
|
|
|
2862
2908
|
const results = [];
|
|
2863
2909
|
const context = this.createContext(contentIndex);
|
|
2864
2910
|
for (const plugin of this.plugins()) {
|
|
2865
|
-
const
|
|
2866
|
-
|
|
2867
|
-
|
|
2911
|
+
const hook = plugin.addDiagnostics;
|
|
2912
|
+
const diagnostics = hook ? await runPluginHook(
|
|
2913
|
+
plugin,
|
|
2914
|
+
"addDiagnostics",
|
|
2915
|
+
this.createPluginContext(plugin, context),
|
|
2916
|
+
hook
|
|
2917
|
+
) : void 0;
|
|
2868
2918
|
for (const diagnostic of diagnostics ?? []) {
|
|
2869
2919
|
results.push({
|
|
2870
2920
|
...diagnostic,
|
|
@@ -2893,13 +2943,13 @@ var PluginRuntime = class {
|
|
|
2893
2943
|
stage: "buildStart",
|
|
2894
2944
|
run: () => runBuildStart(this.plugins(), createPluginContext)
|
|
2895
2945
|
},
|
|
2896
|
-
{
|
|
2897
|
-
stage: "onBuildStart",
|
|
2898
|
-
run: () => this.runHook((plugin) => plugin.onBuildStart, context)
|
|
2899
|
-
},
|
|
2900
2946
|
{
|
|
2901
2947
|
stage: "onConfigResolved",
|
|
2902
|
-
run: () => this.runHook(
|
|
2948
|
+
run: () => this.runHook(
|
|
2949
|
+
"onConfigResolved",
|
|
2950
|
+
(plugin) => plugin.onConfigResolved,
|
|
2951
|
+
context
|
|
2952
|
+
)
|
|
2903
2953
|
}
|
|
2904
2954
|
];
|
|
2905
2955
|
for (const { stage, run } of stages) {
|
|
@@ -2944,18 +2994,12 @@ var PluginRuntime = class {
|
|
|
2944
2994
|
this.pluginCaches.set(plugin.name, cache);
|
|
2945
2995
|
return cache;
|
|
2946
2996
|
}
|
|
2947
|
-
async runHook(hook, context) {
|
|
2997
|
+
async runHook(hookName, hook, context) {
|
|
2948
2998
|
for (const plugin of this.plugins()) {
|
|
2949
2999
|
const pluginHook = hook(plugin);
|
|
2950
3000
|
if (!pluginHook) continue;
|
|
2951
3001
|
const pluginContext = this.createPluginContext(plugin, context);
|
|
2952
|
-
await pluginContext
|
|
2953
|
-
"plugin.hook",
|
|
2954
|
-
{
|
|
2955
|
-
plugin: plugin.name
|
|
2956
|
-
},
|
|
2957
|
-
() => pluginHook(pluginContext)
|
|
2958
|
-
);
|
|
3002
|
+
await runPluginHook(plugin, hookName, pluginContext, pluginHook);
|
|
2959
3003
|
}
|
|
2960
3004
|
}
|
|
2961
3005
|
observability() {
|
|
@@ -3041,10 +3085,20 @@ function countSeverity(diagnostics, severity) {
|
|
|
3041
3085
|
}
|
|
3042
3086
|
function uniqueOutputs(outputs) {
|
|
3043
3087
|
const byPath = /* @__PURE__ */ new Map();
|
|
3044
|
-
for (const output of outputs)
|
|
3045
|
-
|
|
3046
|
-
(
|
|
3047
|
-
|
|
3088
|
+
for (const output of outputs) {
|
|
3089
|
+
const previous = byPath.get(output.output.path);
|
|
3090
|
+
if (!previous || output.priority > previous.priority) {
|
|
3091
|
+
byPath.set(output.output.path, output);
|
|
3092
|
+
continue;
|
|
3093
|
+
}
|
|
3094
|
+
if (output.output.producer === previous.output.producer) continue;
|
|
3095
|
+
if (output.priority === previous.priority) {
|
|
3096
|
+
throw new Error(
|
|
3097
|
+
`Multiple plugin page types declare ${output.output.path} at priority ${output.priority}: ${previous.output.producer}, ${output.output.producer}`
|
|
3098
|
+
);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
return [...byPath.values()].map(({ output }) => output).sort((left, right) => left.path.localeCompare(right.path));
|
|
3048
3102
|
}
|
|
3049
3103
|
|
|
3050
3104
|
// src/content/affected_content.ts
|
|
@@ -3459,8 +3513,8 @@ function collectDependencies2(manifestEntry, trackedDependencies) {
|
|
|
3459
3513
|
kind: "file",
|
|
3460
3514
|
id: asset.path.replace(/\\/g, "/")
|
|
3461
3515
|
})),
|
|
3462
|
-
...trackedDependencies.filter(
|
|
3463
|
-
(dependency) => dependency
|
|
3516
|
+
...trackedDependencies.map(toBuildDependency).filter(
|
|
3517
|
+
(dependency) => dependency !== null
|
|
3464
3518
|
).map((dependency) => ({
|
|
3465
3519
|
kind: dependency.kind,
|
|
3466
3520
|
id: dependency.id.replace(/\\/g, "/")
|
|
@@ -3474,6 +3528,18 @@ function collectDependencies2(manifestEntry, trackedDependencies) {
|
|
|
3474
3528
|
(left, right) => `${left.kind}:${left.id}`.localeCompare(`${right.kind}:${right.id}`)
|
|
3475
3529
|
);
|
|
3476
3530
|
}
|
|
3531
|
+
function toBuildDependency(dependency) {
|
|
3532
|
+
if (dependency.kind === "content" || dependency.kind === "file") {
|
|
3533
|
+
return { kind: dependency.kind, id: dependency.id };
|
|
3534
|
+
}
|
|
3535
|
+
if (dependency.id.startsWith(LINK_LOCATION_PREFIX)) {
|
|
3536
|
+
return {
|
|
3537
|
+
kind: "content",
|
|
3538
|
+
id: dependency.id.slice(LINK_LOCATION_PREFIX.length)
|
|
3539
|
+
};
|
|
3540
|
+
}
|
|
3541
|
+
return null;
|
|
3542
|
+
}
|
|
3477
3543
|
function collectLinkTargets(manifestEntry) {
|
|
3478
3544
|
if (!manifestEntry) return [];
|
|
3479
3545
|
return [
|
|
@@ -3663,8 +3729,17 @@ var FileSystemContentSource = class {
|
|
|
3663
3729
|
contentDirectory;
|
|
3664
3730
|
exclude;
|
|
3665
3731
|
async scan() {
|
|
3732
|
+
return (await this.scanWithExclusions()).entries;
|
|
3733
|
+
}
|
|
3734
|
+
async scanWithExclusions() {
|
|
3735
|
+
const exclusions = [];
|
|
3666
3736
|
try {
|
|
3667
|
-
|
|
3737
|
+
const entries = await this.scanDirectory(
|
|
3738
|
+
this.contentDirectory,
|
|
3739
|
+
"",
|
|
3740
|
+
exclusions
|
|
3741
|
+
);
|
|
3742
|
+
return { entries, exclusions };
|
|
3668
3743
|
} catch (error) {
|
|
3669
3744
|
if (isMissingDirectoryError(error, this.contentDirectory)) {
|
|
3670
3745
|
throw missingContentDirectoryError(this.contentDirectory);
|
|
@@ -3680,7 +3755,7 @@ var FileSystemContentSource = class {
|
|
|
3680
3755
|
}
|
|
3681
3756
|
return await fs4.readFile(filePath);
|
|
3682
3757
|
}
|
|
3683
|
-
async scanDirectory(directory, parentPath2) {
|
|
3758
|
+
async scanDirectory(directory, parentPath2, exclusions) {
|
|
3684
3759
|
const directoryEntries = await fs4.readdir(directory, {
|
|
3685
3760
|
withFileTypes: true
|
|
3686
3761
|
});
|
|
@@ -3691,9 +3766,16 @@ var FileSystemContentSource = class {
|
|
|
3691
3766
|
parentPath2 ? `${parentPath2}/${directoryEntry.name}` : directoryEntry.name
|
|
3692
3767
|
);
|
|
3693
3768
|
const filePath = path4.join(directory, directoryEntry.name);
|
|
3694
|
-
if (
|
|
3769
|
+
if (isExcluded(INTERNAL_CONTENT_IGNORE_PATTERNS, logicalPath)) continue;
|
|
3770
|
+
const pattern = matchContentExcludePattern(logicalPath, this.exclude);
|
|
3771
|
+
if (pattern !== void 0) {
|
|
3772
|
+
exclusions.push({ path: logicalPath, pattern });
|
|
3773
|
+
continue;
|
|
3774
|
+
}
|
|
3695
3775
|
if (directoryEntry.isDirectory()) {
|
|
3696
|
-
entries.push(
|
|
3776
|
+
entries.push(
|
|
3777
|
+
...await this.scanDirectory(filePath, logicalPath, exclusions)
|
|
3778
|
+
);
|
|
3697
3779
|
continue;
|
|
3698
3780
|
}
|
|
3699
3781
|
if (!directoryEntry.isFile()) continue;
|
|
@@ -3708,9 +3790,6 @@ var FileSystemContentSource = class {
|
|
|
3708
3790
|
}
|
|
3709
3791
|
return entries;
|
|
3710
3792
|
}
|
|
3711
|
-
isExcluded(logicalPath) {
|
|
3712
|
-
return isIgnoredContentPath(logicalPath, this.exclude);
|
|
3713
|
-
}
|
|
3714
3793
|
resolveFilePath(logicalPath) {
|
|
3715
3794
|
const normalizedPath = normalizeLogicalPath(logicalPath);
|
|
3716
3795
|
const filePath = path4.resolve(this.contentDirectory, normalizedPath);
|
|
@@ -3723,8 +3802,14 @@ var FileSystemContentSource = class {
|
|
|
3723
3802
|
};
|
|
3724
3803
|
function isIgnoredContentPath(logicalPath, exclude = []) {
|
|
3725
3804
|
if (isExcluded(INTERNAL_CONTENT_IGNORE_PATTERNS, logicalPath)) return true;
|
|
3726
|
-
|
|
3727
|
-
|
|
3805
|
+
return matchContentExcludePattern(logicalPath, exclude) !== void 0;
|
|
3806
|
+
}
|
|
3807
|
+
function matchContentExcludePattern(logicalPath, exclude = []) {
|
|
3808
|
+
const direct = exclude.find((pattern) => isExcluded([pattern], logicalPath));
|
|
3809
|
+
if (direct !== void 0) return direct;
|
|
3810
|
+
if (!logicalPath.endsWith(".md")) return void 0;
|
|
3811
|
+
const withoutExtension = logicalPath.slice(0, -3);
|
|
3812
|
+
return exclude.find((pattern) => isExcluded([pattern], withoutExtension));
|
|
3728
3813
|
}
|
|
3729
3814
|
function normalizeLogicalPath(logicalPath) {
|
|
3730
3815
|
const normalizedPath = normalizeContentPath(logicalPath);
|
|
@@ -3748,53 +3833,22 @@ function missingContentDirectoryError(directory) {
|
|
|
3748
3833
|
return error;
|
|
3749
3834
|
}
|
|
3750
3835
|
|
|
3751
|
-
// src/content/content_links.ts
|
|
3752
|
-
var WIKILINK_PATTERN = /(!)?\[\[([^\]|#^]+)(?:[#^][^\]|]+)?(?:\|[^\]]+)?\]\]/g;
|
|
3753
|
-
function extractContentLinks(markdown, contentIndex) {
|
|
3754
|
-
WIKILINK_PATTERN.lastIndex = 0;
|
|
3755
|
-
const links = [];
|
|
3756
|
-
for (let match = WIKILINK_PATTERN.exec(markdown); match !== null; match = WIKILINK_PATTERN.exec(markdown)) {
|
|
3757
|
-
const rawTarget = match[2]?.trim();
|
|
3758
|
-
if (!rawTarget) continue;
|
|
3759
|
-
const resolved = contentIndex.get(rawTarget.toLowerCase()) ?? null;
|
|
3760
|
-
links.push({
|
|
3761
|
-
raw: rawTarget,
|
|
3762
|
-
slug: resolved,
|
|
3763
|
-
kind: resolved ? linkKind(resolved) : "unresolved",
|
|
3764
|
-
embed: match[1] === "!"
|
|
3765
|
-
});
|
|
3766
|
-
}
|
|
3767
|
-
return links;
|
|
3768
|
-
}
|
|
3769
|
-
function linkKind(value) {
|
|
3770
|
-
if (isImagePath(value)) return "image";
|
|
3771
|
-
if (isAttachmentPath(value)) return "attachment";
|
|
3772
|
-
return "note";
|
|
3773
|
-
}
|
|
3774
|
-
|
|
3775
3836
|
// src/content/content_stable_id.ts
|
|
3776
3837
|
var MAX_STABLE_CONTENT_ID_LENGTH = 160;
|
|
3777
3838
|
function resolveContentStableId(frontmatter) {
|
|
3778
|
-
|
|
3779
|
-
const uid = readOptionalStableId(frontmatter.uid, "uid");
|
|
3780
|
-
if (id !== void 0 && uid !== void 0 && id !== uid) {
|
|
3781
|
-
throw new Error(
|
|
3782
|
-
'Content frontmatter fields "id" and "uid" must have the same value.'
|
|
3783
|
-
);
|
|
3784
|
-
}
|
|
3785
|
-
return id ?? uid;
|
|
3839
|
+
return readOptionalStableId(frontmatter.id);
|
|
3786
3840
|
}
|
|
3787
|
-
function readOptionalStableId(value
|
|
3841
|
+
function readOptionalStableId(value) {
|
|
3788
3842
|
if (value === void 0) return void 0;
|
|
3789
3843
|
if (typeof value !== "string") {
|
|
3790
|
-
throw new Error(`Content frontmatter field "
|
|
3844
|
+
throw new Error(`Content frontmatter field "id" must be a string.`);
|
|
3791
3845
|
}
|
|
3792
3846
|
if (value.length === 0 || value.length > MAX_STABLE_CONTENT_ID_LENGTH || value.trim() !== value || [...value].some((character) => {
|
|
3793
3847
|
const code = character.codePointAt(0) ?? 0;
|
|
3794
3848
|
return code <= 31 || code === 127;
|
|
3795
3849
|
})) {
|
|
3796
3850
|
throw new Error(
|
|
3797
|
-
`Content frontmatter field "
|
|
3851
|
+
`Content frontmatter field "id" must be a non-empty, trimmed string of at most ${MAX_STABLE_CONTENT_ID_LENGTH} characters without control characters.`
|
|
3798
3852
|
);
|
|
3799
3853
|
}
|
|
3800
3854
|
return value;
|
|
@@ -4101,8 +4155,20 @@ function linkTargets(entry) {
|
|
|
4101
4155
|
).map((link) => link.slug);
|
|
4102
4156
|
}
|
|
4103
4157
|
function addOutput(outputs, output) {
|
|
4158
|
+
const existing = outputs.get(output.path);
|
|
4159
|
+
if (existing) {
|
|
4160
|
+
assertNoGeneratedOutputCollision(existing, output);
|
|
4161
|
+
}
|
|
4104
4162
|
outputs.set(output.path, output);
|
|
4105
4163
|
}
|
|
4164
|
+
function assertNoGeneratedOutputCollision(existing, incoming) {
|
|
4165
|
+
if (existing.kind !== "generated" && incoming.kind !== "generated") return;
|
|
4166
|
+
if (existing.kind === incoming.kind && existing.producer === incoming.producer)
|
|
4167
|
+
return;
|
|
4168
|
+
throw new Error(
|
|
4169
|
+
`Generated output path "${incoming.path}" collides with ${existing.kind} output owned by "${existing.producer}" and ${incoming.kind} output owned by "${incoming.producer}".`
|
|
4170
|
+
);
|
|
4171
|
+
}
|
|
4106
4172
|
function normalizePublicPath(pathname) {
|
|
4107
4173
|
const path5 = `/${pathname.split("/").filter(Boolean).join("/")}`;
|
|
4108
4174
|
return path5 === "/" ? path5 : path5.replace(/\/$/, "");
|
|
@@ -4182,9 +4248,14 @@ var CONTENT_PROCESSING_CONCURRENCY = 16;
|
|
|
4182
4248
|
var ContentManager = class {
|
|
4183
4249
|
constructor(content, exclude = [], pipelineOptions = {}) {
|
|
4184
4250
|
this.pipelineOptions = pipelineOptions;
|
|
4251
|
+
const config = pipelineOptions.config ? {
|
|
4252
|
+
...pipelineOptions.config,
|
|
4253
|
+
plugins: pipelineOptions.plugins ?? pipelineOptions.config.plugins
|
|
4254
|
+
} : void 0;
|
|
4185
4255
|
this.pipelineOptions = {
|
|
4186
4256
|
...pipelineOptions,
|
|
4187
|
-
|
|
4257
|
+
config,
|
|
4258
|
+
plugins: pipelineOptions.plugins ?? config?.plugins,
|
|
4188
4259
|
isRoutable: (slug) => this.isRoutable(slug)
|
|
4189
4260
|
};
|
|
4190
4261
|
this.publishingBuildTime = resolvePublishingBuildTime(
|
|
@@ -5077,6 +5148,7 @@ export {
|
|
|
5077
5148
|
buildOutputInventory,
|
|
5078
5149
|
calculateReadingTime,
|
|
5079
5150
|
collectConfigDeprecationDiagnostics,
|
|
5151
|
+
computePipelineFingerprint,
|
|
5080
5152
|
createClientEntry,
|
|
5081
5153
|
createContentGraph,
|
|
5082
5154
|
createDeprecationDiagnostic,
|
|
@@ -5095,6 +5167,7 @@ export {
|
|
|
5095
5167
|
fingerprintContentEntries,
|
|
5096
5168
|
formatDeprecationMessage,
|
|
5097
5169
|
getContentSourceEntry,
|
|
5170
|
+
getEntryLanguage,
|
|
5098
5171
|
getExtension,
|
|
5099
5172
|
getResolvedPluginMetadata,
|
|
5100
5173
|
groupContentEntries,
|
|
@@ -5104,11 +5177,13 @@ export {
|
|
|
5104
5177
|
isIgnoredContentPath,
|
|
5105
5178
|
isImagePath,
|
|
5106
5179
|
isMarkdownPath,
|
|
5180
|
+
isPersistentlyCacheable,
|
|
5107
5181
|
isPublishable,
|
|
5108
5182
|
isPublished,
|
|
5109
5183
|
layoutForceGraph,
|
|
5110
5184
|
layoutRadialGraph,
|
|
5111
5185
|
loadContentBuildState,
|
|
5186
|
+
matchContentExcludePattern,
|
|
5112
5187
|
normalizeContentAssetOutputPath,
|
|
5113
5188
|
normalizeContentPath,
|
|
5114
5189
|
normalizeGeneratedOutputPath,
|
|
@@ -5131,6 +5206,7 @@ export {
|
|
|
5131
5206
|
resolvePublicFolderLocation,
|
|
5132
5207
|
resolvePublishingBuildTime,
|
|
5133
5208
|
resolvePublishingState,
|
|
5209
|
+
selectEntriesByLanguage,
|
|
5134
5210
|
serializePublicClientConfig,
|
|
5135
5211
|
stableStringify,
|
|
5136
5212
|
stripHtml,
|
|
@@ -3,7 +3,7 @@ import type { ContentManifest, ContentManifestEntry } from "../types/content_man
|
|
|
3
3
|
import { determineAffectedContent } from "./affected_content.js";
|
|
4
4
|
import { type ContentBuildState, type FingerprintedContentEntry } from "./content_build_state.js";
|
|
5
5
|
import { type ContentChangeSet } from "./content_change_set.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type CachedContentDependency } from "./content_dependency_tracker.js";
|
|
7
7
|
import type { ContentSourceEntry } from "./content_source.js";
|
|
8
8
|
import type { OutputDescriptor } from "./output_dependency.js";
|
|
9
9
|
export type ContentBuildPreparation = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ContentManifestEntry } from "../types/content_manifest.js";
|
|
2
2
|
import type { ContentSourceEntry } from "./content_source.js";
|
|
3
3
|
import type { OutputDescriptor } from "./output_dependency.js";
|
|
4
|
-
export declare const CONTENT_BUILD_STATE_VERSION =
|
|
4
|
+
export declare const CONTENT_BUILD_STATE_VERSION = 7;
|
|
5
5
|
/**
|
|
6
6
|
* Build state lives under `<content directory>/.riebeckite`. That directory is
|
|
7
7
|
* build-time state, not content, so content sources must exclude it from scans
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ContentSource, ContentSourceContent } from "./content_source.js";
|
|
2
|
+
export declare const LINK_INDEX_PREFIX = "index:";
|
|
3
|
+
export declare const LINK_LOCATION_PREFIX = "location:";
|
|
2
4
|
export type CachedContentDependency = {
|
|
3
5
|
readonly kind: "content" | "file" | "link";
|
|
4
6
|
readonly id: string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ContentManifestEntry } from "../types/content_manifest.js";
|
|
2
|
+
export declare function getEntryLanguage(entry: ContentManifestEntry): string | undefined;
|
|
3
|
+
export declare function selectEntriesByLanguage(entries: readonly ContentManifestEntry[], language: string | undefined): readonly ContentManifestEntry[];
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { PostFrontmatter } from "../types/post_content.js";
|
|
2
2
|
/**
|
|
3
|
-
* Reads the optional, source-authored stable content ID.
|
|
4
|
-
*
|
|
5
|
-
* `id` is the canonical frontmatter field. `uid` is accepted only for
|
|
6
|
-
* compatibility with existing content that used it before `id` was standard.
|
|
3
|
+
* Reads the optional, source-authored stable content ID from frontmatter.
|
|
7
4
|
*/
|
|
8
5
|
export declare function resolveContentStableId(frontmatter: PostFrontmatter): string | undefined;
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { ContentSource, ContentSourceContent, ContentSourceEntry } from "./content_source.js";
|
|
2
2
|
export declare const INTERNAL_CONTENT_IGNORE_PATTERNS: readonly [".git", ".git/**", ".github", ".github/**", ".obsidian", ".obsidian/**", "node_modules", "node_modules/**", "**/.DS_Store", "**/Thumbs.db", "**/desktop.ini"];
|
|
3
|
+
export type ContentSourceExclusion = {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly pattern: string;
|
|
6
|
+
};
|
|
7
|
+
export type ContentSourceScan = {
|
|
8
|
+
readonly entries: readonly ContentSourceEntry[];
|
|
9
|
+
readonly exclusions: readonly ContentSourceExclusion[];
|
|
10
|
+
};
|
|
3
11
|
export declare class FileSystemContentSource implements ContentSource {
|
|
4
12
|
private contentDirectory;
|
|
5
13
|
private exclude;
|
|
6
14
|
constructor(contentDirectory: string, exclude?: readonly string[]);
|
|
7
15
|
scan(): Promise<readonly ContentSourceEntry[]>;
|
|
16
|
+
scanWithExclusions(): Promise<ContentSourceScan>;
|
|
8
17
|
read(entry: ContentSourceEntry): Promise<ContentSourceContent>;
|
|
9
18
|
private scanDirectory;
|
|
10
|
-
private isExcluded;
|
|
11
19
|
private resolveFilePath;
|
|
12
20
|
}
|
|
13
21
|
export declare function isIgnoredContentPath(logicalPath: string, exclude?: readonly string[]): boolean;
|
|
22
|
+
export declare function matchContentExcludePattern(logicalPath: string, exclude?: readonly string[]): string | undefined;
|
package/dist/src/pipeline.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import type { Tracer } from "../observability.js";
|
|
1
2
|
import type { RiebeckitePlugin } from "../types/plugin.js";
|
|
2
3
|
import type { PluginLifecycleContext, PluginManifestContext } from "../types/plugin_context.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
constructor(pluginName: string, hookName: LifecycleHookName, cause: unknown);
|
|
4
|
+
export declare class PluginHookError extends Error {
|
|
5
|
+
constructor(pluginName: string, hookName: string, cause: unknown);
|
|
6
6
|
}
|
|
7
|
+
export declare function runPluginHook<TContext extends {
|
|
8
|
+
tracer: Tracer;
|
|
9
|
+
}, TResult>(plugin: RiebeckitePlugin, hookName: string, context: TContext, hook: (context: TContext) => TResult | Promise<TResult>): Promise<TResult>;
|
|
7
10
|
export declare function runSetup(plugins: readonly RiebeckitePlugin[], createContext: (plugin: RiebeckitePlugin) => PluginLifecycleContext): Promise<void>;
|
|
8
11
|
export declare function runBuildStart(plugins: readonly RiebeckitePlugin[], createContext: (plugin: RiebeckitePlugin) => PluginLifecycleContext): Promise<void>;
|
|
9
12
|
export declare function runBuildEnd(plugins: readonly RiebeckitePlugin[], createContext: (plugin: RiebeckitePlugin) => PluginManifestContext): Promise<void>;
|
|
10
13
|
export declare function runDispose(plugins: readonly RiebeckitePlugin[], createContext: (plugin: RiebeckitePlugin) => PluginLifecycleContext): Promise<void>;
|
|
11
|
-
export {};
|
|
@@ -12,7 +12,7 @@ import type { PostContent } from "../types/post_content.js";
|
|
|
12
12
|
* requested yet; the remaining values name the stage currently executing.
|
|
13
13
|
* Once `started` is reached the lifecycle never runs again.
|
|
14
14
|
*/
|
|
15
|
-
export type PluginBuildStage = "idle" | "setup" | "buildStart" | "
|
|
15
|
+
export type PluginBuildStage = "idle" | "setup" | "buildStart" | "onConfigResolved" | "started";
|
|
16
16
|
export declare class PluginRuntime {
|
|
17
17
|
private pipelineOptions;
|
|
18
18
|
private buildLifecycle;
|
|
@@ -23,6 +23,7 @@ export declare class PluginRuntime {
|
|
|
23
23
|
private generatedOutputs;
|
|
24
24
|
private isBuildTime;
|
|
25
25
|
private resolvedPlugins;
|
|
26
|
+
private pageDeclarations;
|
|
26
27
|
constructor(pipelineOptions?: PipelineOptions);
|
|
27
28
|
getDiagnostics(): Diagnostic[];
|
|
28
29
|
getBuildStage(): PluginBuildStage;
|
|
@@ -30,7 +31,7 @@ export declare class PluginRuntime {
|
|
|
30
31
|
* Starts the plugin build lifecycle exactly once, regardless of which public
|
|
31
32
|
* entry point (content processing or location resolution) reaches it first.
|
|
32
33
|
* Concurrent callers await the same run, so the ordered hooks
|
|
33
|
-
* (`setup` → `buildStart` → `
|
|
34
|
+
* (`setup` → `buildStart` → `onConfigResolved`) are never
|
|
34
35
|
* duplicated and no caller proceeds before the lifecycle completes.
|
|
35
36
|
*/
|
|
36
37
|
startBuild(contentIndex: Map<string, string>): Promise<void>;
|
|
@@ -61,6 +62,8 @@ export declare class PluginRuntime {
|
|
|
61
62
|
getPagePaths(manifest: ContentManifest, contentIndex: Map<string, string>): Promise<readonly string[]>;
|
|
62
63
|
getPageRoutes(manifest: ContentManifest, contentIndex: Map<string, string>): Promise<readonly PluginPageRoute[]>;
|
|
63
64
|
getPageOutputs(manifest: ContentManifest, contentIndex: Map<string, string>): Promise<readonly OutputDescriptor[]>;
|
|
65
|
+
private getPageDeclarations;
|
|
66
|
+
private resolvePageDeclarations;
|
|
64
67
|
getContentOutputDependencies(): readonly OutputDependency[];
|
|
65
68
|
collectDiagnostics(contentIndex: Map<string, string>): Promise<Diagnostic[]>;
|
|
66
69
|
private runBuildLifecycle;
|
|
@@ -24,7 +24,7 @@ export type ContentManifestPluginAsset = PluginAsset & {
|
|
|
24
24
|
* The standard article consumer recognizes the `article.*` positions below.
|
|
25
25
|
* Other names remain valid so a custom Site can define its own layout slots.
|
|
26
26
|
*/
|
|
27
|
-
export type ContentBodySlot = "article.
|
|
27
|
+
export type ContentBodySlot = "article.header" | "article.metadata" | "article.aside" | "article.before-content" | "article.after-content" | "article.footer" | (string & {});
|
|
28
28
|
/** Client entries and their explicitly public configuration. */
|
|
29
29
|
export type ContentManifestPluginClientEntry = PluginClientEntry;
|
|
30
30
|
export type ContentManifestEntry = {
|
|
@@ -71,6 +71,7 @@ export type ContentRedirect = {
|
|
|
71
71
|
export type ContentPublicLocation = {
|
|
72
72
|
slug: string;
|
|
73
73
|
permalink: string;
|
|
74
|
+
language?: string;
|
|
74
75
|
redirects?: readonly ContentRedirect[];
|
|
75
76
|
metadata?: Readonly<Record<string, string>>;
|
|
76
77
|
};
|
|
@@ -90,9 +91,10 @@ export type ContentLocationInput = {
|
|
|
90
91
|
export type ContentManifest = {
|
|
91
92
|
entries: ContentManifestEntry[];
|
|
92
93
|
/**
|
|
93
|
-
* Entries that
|
|
94
|
-
*
|
|
95
|
-
*
|
|
94
|
+
* Entries that are routable and therefore get a generated page: `public`
|
|
95
|
+
* and `unlisted` notes. `entries` keeps every scanned note for backward
|
|
96
|
+
* compatibility; plugins that emit generated output should read this view
|
|
97
|
+
* so drafts and scheduled notes never reach generated output.
|
|
96
98
|
*/
|
|
97
99
|
publicEntries: ContentManifestEntry[];
|
|
98
100
|
/** Entries that may appear on discovery surfaces such as navigation, search, feeds, taxonomy, and public graphs. */
|
|
@@ -59,8 +59,6 @@ export type RiebeckitePlugin<TOptions = unknown> = {
|
|
|
59
59
|
onPostParsed?(context: PluginPostContext): void | Promise<void>;
|
|
60
60
|
onPostProcessed?(context: PluginPostContext): void | Promise<void>;
|
|
61
61
|
onManifestCreated?(context: PluginManifestContext): void | Promise<void>;
|
|
62
|
-
onBuildStart?(context: PluginContext): void | Promise<void>;
|
|
63
|
-
onBuildEnd?(context: PluginManifestContext): void | Promise<void>;
|
|
64
62
|
extendMarkdownPipeline?(pipeline: MarkdownPipeline, context: MarkdownPipelineContext): void;
|
|
65
63
|
extendHtmlPipeline?(pipeline: HtmlPipeline): void;
|
|
66
64
|
addDiagnostics?(context: PluginContext): Diagnostic[] | Promise<Diagnostic[]>;
|
|
@@ -14,6 +14,8 @@ export type PluginPage = {
|
|
|
14
14
|
description?: string;
|
|
15
15
|
/** Optional document metadata rendered by the site's document frame. */
|
|
16
16
|
headTags?: readonly PluginHeadTag[];
|
|
17
|
+
/** Language of the page when the page type resolved one. */
|
|
18
|
+
language?: string;
|
|
17
19
|
};
|
|
18
20
|
export type PluginPageContext = PluginContext & {
|
|
19
21
|
/** The public manifest. Unpublished content is not exposed through pages. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ContentManifestEntry } from "./content_manifest.js";
|
|
2
|
+
import type { PluginHeadTag } from "./plugin_head.js";
|
|
2
3
|
import type { PostContent } from "./post_content.js";
|
|
3
4
|
import type { ResolvedRiebeckiteConfig } from "./resolved_riebeckite_config.js";
|
|
4
5
|
export type SeoMetadata = {
|
|
@@ -24,8 +25,8 @@ export type RenderableFeedEntry = ContentManifestEntry & {
|
|
|
24
25
|
html?: string;
|
|
25
26
|
};
|
|
26
27
|
export type PluginSeoExtension = {
|
|
27
|
-
buildArticleSeo(config: ResolvedRiebeckiteConfig, permalink: string, post: PostContent): SeoMetadata;
|
|
28
|
-
buildWebsiteSeo(config: ResolvedRiebeckiteConfig, input: WebsiteSeoInput): SeoMetadata;
|
|
28
|
+
buildArticleSeo(config: ResolvedRiebeckiteConfig, permalink: string, post: PostContent, headTags?: readonly PluginHeadTag[]): SeoMetadata;
|
|
29
|
+
buildWebsiteSeo(config: ResolvedRiebeckiteConfig, input: WebsiteSeoInput, headTags?: readonly PluginHeadTag[]): SeoMetadata;
|
|
29
30
|
buildAbsoluteUrl(config: ResolvedRiebeckiteConfig, pathOrUrl: string): string;
|
|
30
31
|
buildPostUrl(config: ResolvedRiebeckiteConfig, permalink: string): string;
|
|
31
32
|
getDescription(post: Pick<PostContent, "frontmatter" | "html">): string;
|
|
@@ -8,8 +8,6 @@ export type PostFrontmatter = Record<string, unknown> & {
|
|
|
8
8
|
* this value survives a rename or public-location change.
|
|
9
9
|
*/
|
|
10
10
|
id?: string;
|
|
11
|
-
/** @deprecated Use `id`. Read only as a compatibility fallback. */
|
|
12
|
-
uid?: string;
|
|
13
11
|
title?: string;
|
|
14
12
|
description?: string;
|
|
15
13
|
date?: string | Date;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ContentSource } from "../content/content_source.js";
|
|
2
|
-
import type { NavigationConfig } from "./navigation_config.js";
|
|
3
2
|
import type { RiebeckitePlugin } from "./plugin.js";
|
|
4
3
|
import type { PublishStrategy } from "./publish_strategy.js";
|
|
5
4
|
import type { SiteConfig } from "./site_config.js";
|
|
@@ -10,8 +9,13 @@ export type ResolvedRiebeckiteConfig = {
|
|
|
10
9
|
* relative to their application root.
|
|
11
10
|
*/
|
|
12
11
|
buildDirectory?: string;
|
|
13
|
-
site: Required<SiteConfig
|
|
14
|
-
|
|
12
|
+
site: Omit<Required<SiteConfig>, "feed"> & {
|
|
13
|
+
feed: {
|
|
14
|
+
title: string;
|
|
15
|
+
description: string;
|
|
16
|
+
language: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
15
19
|
content: {
|
|
16
20
|
directory: string;
|
|
17
21
|
source?: ContentSource;
|
|
@@ -20,11 +24,6 @@ export type ResolvedRiebeckiteConfig = {
|
|
|
20
24
|
publishStrategy: PublishStrategy;
|
|
21
25
|
};
|
|
22
26
|
};
|
|
23
|
-
markdown: {
|
|
24
|
-
syntaxHighlight: {
|
|
25
|
-
theme: string;
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
27
|
theme: Required<Omit<ThemeConfig, "tokens">> & {
|
|
29
28
|
tokens: NonNullable<ThemeConfig["tokens"]>;
|
|
30
29
|
styles: ThemeStyle[];
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { ContentSource } from "../content/content_source.js";
|
|
2
|
-
import type { NavigationConfig } from "./navigation_config.js";
|
|
3
2
|
import type { PluginInput } from "./plugin.js";
|
|
4
3
|
import type { PublishStrategy } from "./publish_strategy.js";
|
|
5
4
|
import type { SiteConfig } from "./site_config.js";
|
|
6
5
|
import type { ThemeInput } from "./theme_config.js";
|
|
7
6
|
export interface RiebeckiteConfig {
|
|
8
7
|
site: SiteConfig;
|
|
9
|
-
navigation?: NavigationConfig;
|
|
10
8
|
content?: {
|
|
11
9
|
directory?: string;
|
|
12
10
|
source?: ContentSource;
|
|
@@ -15,11 +13,6 @@ export interface RiebeckiteConfig {
|
|
|
15
13
|
publishStrategy?: PublishStrategy;
|
|
16
14
|
};
|
|
17
15
|
};
|
|
18
|
-
markdown?: {
|
|
19
|
-
syntaxHighlight?: {
|
|
20
|
-
theme?: string;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
16
|
theme?: ThemeInput;
|
|
24
17
|
plugins?: PluginInput[];
|
|
25
18
|
cache?: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"tsx": "^4.22.4",
|
|
52
|
-
"@riebeckite/test": "0.0.
|
|
52
|
+
"@riebeckite/test": "0.0.17"
|
|
53
53
|
},
|
|
54
54
|
"repository": {
|
|
55
55
|
"type": "git",
|