@riebeckite/core 0.0.17 → 0.0.19
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 +5 -5
- package/README_ja.md +5 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.js +345 -239
- package/dist/src/config.d.ts +3 -1
- package/dist/src/content/content_build_coordinator.d.ts +1 -0
- package/dist/src/content/content_build_state.d.ts +1 -1
- package/dist/src/content/content_entry_reader.d.ts +1 -0
- package/dist/src/content/content_index_builder.d.ts +6 -2
- package/dist/src/content/content_manager.d.ts +2 -0
- package/dist/src/content/folder_entry.d.ts +1 -1
- package/dist/src/content/manifest_builder.d.ts +1 -1
- package/dist/src/plugin/plugin_lifecycle.d.ts +1 -0
- package/dist/src/project/project_layout.d.ts +11 -0
- package/dist/src/types/content_manifest.d.ts +33 -1
- package/dist/src/types/plugin_page.d.ts +5 -1
- package/dist/src/types/plugin_seo.d.ts +1 -1
- package/dist/src/types/resolved_riebeckite_config.d.ts +5 -0
- package/dist/src/utils/error.d.ts +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -119,41 +119,41 @@ function validateTheme(value, issues) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
function validateThemeConfig(value,
|
|
123
|
-
validateOptionalString(value.name, `${
|
|
122
|
+
function validateThemeConfig(value, path6, issues) {
|
|
123
|
+
validateOptionalString(value.name, `${path6}.name`, issues);
|
|
124
124
|
validateOneOf(
|
|
125
125
|
value.colorMode,
|
|
126
|
-
`${
|
|
126
|
+
`${path6}.colorMode`,
|
|
127
127
|
["light", "dark", "system"],
|
|
128
128
|
issues
|
|
129
129
|
);
|
|
130
130
|
validateOneOf(
|
|
131
131
|
value.typography,
|
|
132
|
-
`${
|
|
132
|
+
`${path6}.typography`,
|
|
133
133
|
["system", "serif", "sans"],
|
|
134
134
|
issues
|
|
135
135
|
);
|
|
136
136
|
validateOneOf(
|
|
137
137
|
value.articleLayout,
|
|
138
|
-
`${
|
|
138
|
+
`${path6}.articleLayout`,
|
|
139
139
|
["article", "sidebar", "full-width"],
|
|
140
140
|
issues
|
|
141
141
|
);
|
|
142
|
-
validateStringArray(value.userCss, `${
|
|
142
|
+
validateStringArray(value.userCss, `${path6}.userCss`, issues);
|
|
143
143
|
if (value.attributes !== void 0 && !isRecord(value.attributes)) {
|
|
144
|
-
issues.push({ path: `${
|
|
144
|
+
issues.push({ path: `${path6}.attributes`, message: "Expected an object." });
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
-
function validateThemeStyles(value,
|
|
147
|
+
function validateThemeStyles(value, path6, issues) {
|
|
148
148
|
if (value === void 0) return;
|
|
149
149
|
if (!Array.isArray(value)) {
|
|
150
|
-
issues.push({ path:
|
|
150
|
+
issues.push({ path: path6, message: "Expected an array." });
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
153
|
for (const [index, style] of value.entries()) {
|
|
154
154
|
if (!isRecord(style) || !isNonEmptyString(style.moduleSpecifier)) {
|
|
155
155
|
issues.push({
|
|
156
|
-
path: `${
|
|
156
|
+
path: `${path6}[${index}].moduleSpecifier`,
|
|
157
157
|
message: "Expected a non-empty string."
|
|
158
158
|
});
|
|
159
159
|
}
|
|
@@ -173,69 +173,69 @@ function validatePlugins(value, issues) {
|
|
|
173
173
|
continue;
|
|
174
174
|
}
|
|
175
175
|
const plugin = input;
|
|
176
|
-
const
|
|
176
|
+
const path6 = `plugins[${index}]`;
|
|
177
177
|
if (!isNonEmptyString(plugin.name)) {
|
|
178
178
|
issues.push({
|
|
179
|
-
path: `${
|
|
179
|
+
path: `${path6}.name`,
|
|
180
180
|
message: "Expected a non-empty string."
|
|
181
181
|
});
|
|
182
182
|
} else if (plugin.enabled !== false) {
|
|
183
183
|
const duplicateIndex = names.get(plugin.name);
|
|
184
184
|
if (duplicateIndex !== void 0) {
|
|
185
185
|
issues.push({
|
|
186
|
-
path: `${
|
|
186
|
+
path: `${path6}.name`,
|
|
187
187
|
message: `Duplicate plugin name "${plugin.name}" (also plugins[${duplicateIndex}]).`
|
|
188
188
|
});
|
|
189
189
|
} else {
|
|
190
190
|
names.set(plugin.name, index);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
-
validateOptionalBoolean(plugin.enabled, `${
|
|
194
|
-
validateCapabilityMetadata(plugin,
|
|
195
|
-
if (plugin.enabled !== false) validatePluginOptions(plugin,
|
|
193
|
+
validateOptionalBoolean(plugin.enabled, `${path6}.enabled`, issues);
|
|
194
|
+
validateCapabilityMetadata(plugin, path6, issues);
|
|
195
|
+
if (plugin.enabled !== false) validatePluginOptions(plugin, path6, issues);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
-
function validateCapabilityMetadata(plugin,
|
|
199
|
-
validateStringArray(plugin.provides, `${
|
|
200
|
-
validateStringArray(plugin.requires, `${
|
|
201
|
-
validateStringArray(plugin.optional, `${
|
|
198
|
+
function validateCapabilityMetadata(plugin, path6, issues) {
|
|
199
|
+
validateStringArray(plugin.provides, `${path6}.provides`, issues, true);
|
|
200
|
+
validateStringArray(plugin.requires, `${path6}.requires`, issues, true);
|
|
201
|
+
validateStringArray(plugin.optional, `${path6}.optional`, issues, true);
|
|
202
202
|
}
|
|
203
|
-
function validatePluginOptions(plugin,
|
|
203
|
+
function validatePluginOptions(plugin, path6, issues) {
|
|
204
204
|
if (!plugin.validateOptions) return;
|
|
205
205
|
try {
|
|
206
206
|
const optionIssues = plugin.validateOptions(plugin.options) ?? [];
|
|
207
207
|
for (const issue of optionIssues) {
|
|
208
208
|
issues.push({
|
|
209
|
-
path: issue.path ? `${
|
|
209
|
+
path: issue.path ? `${path6}.options.${issue.path}` : `${path6}.options`,
|
|
210
210
|
message: issue.message
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
213
|
} catch (error) {
|
|
214
214
|
issues.push({
|
|
215
|
-
path: `${
|
|
215
|
+
path: `${path6}.options`,
|
|
216
216
|
message: `Validator failed: ${toErrorMessage(error)}`
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
-
function validateRequiredString(value,
|
|
220
|
+
function validateRequiredString(value, path6, issues) {
|
|
221
221
|
if (!isNonEmptyString(value)) {
|
|
222
|
-
issues.push({ path:
|
|
222
|
+
issues.push({ path: path6, message: "Expected a non-empty string." });
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
function validateOptionalString(value,
|
|
225
|
+
function validateOptionalString(value, path6, issues) {
|
|
226
226
|
if (value !== void 0 && typeof value !== "string") {
|
|
227
|
-
issues.push({ path:
|
|
227
|
+
issues.push({ path: path6, message: "Expected a string." });
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
|
-
function validateOptionalBoolean(value,
|
|
230
|
+
function validateOptionalBoolean(value, path6, issues) {
|
|
231
231
|
if (value !== void 0 && typeof value !== "boolean") {
|
|
232
|
-
issues.push({ path:
|
|
232
|
+
issues.push({ path: path6, message: "Expected a boolean." });
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
|
-
function validateAbsoluteUrl(value,
|
|
235
|
+
function validateAbsoluteUrl(value, path6, issues) {
|
|
236
236
|
if (value === void 0 || value === "") return;
|
|
237
237
|
if (typeof value !== "string") {
|
|
238
|
-
issues.push({ path:
|
|
238
|
+
issues.push({ path: path6, message: "Expected an absolute URL." });
|
|
239
239
|
return;
|
|
240
240
|
}
|
|
241
241
|
try {
|
|
@@ -243,27 +243,27 @@ function validateAbsoluteUrl(value, path5, issues) {
|
|
|
243
243
|
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
244
244
|
throw new Error();
|
|
245
245
|
} catch {
|
|
246
|
-
issues.push({ path:
|
|
246
|
+
issues.push({ path: path6, message: "Expected an absolute HTTP(S) URL." });
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
|
-
function validateStringArray(value,
|
|
249
|
+
function validateStringArray(value, path6, issues, nonEmpty = false) {
|
|
250
250
|
if (value === void 0) return;
|
|
251
251
|
if (!Array.isArray(value)) {
|
|
252
|
-
issues.push({ path:
|
|
252
|
+
issues.push({ path: path6, message: "Expected an array." });
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
255
|
for (const [index, item] of value.entries()) {
|
|
256
256
|
if (typeof item !== "string" || nonEmpty && !item.trim()) {
|
|
257
257
|
issues.push({
|
|
258
|
-
path: `${
|
|
258
|
+
path: `${path6}[${index}]`,
|
|
259
259
|
message: nonEmpty ? "Expected a non-empty string." : "Expected a string."
|
|
260
260
|
});
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
function validateOneOf(value,
|
|
264
|
+
function validateOneOf(value, path6, choices, issues) {
|
|
265
265
|
if (value !== void 0 && (typeof value !== "string" || !choices.includes(value))) {
|
|
266
|
-
issues.push({ path:
|
|
266
|
+
issues.push({ path: path6, message: `Expected one of: ${choices.join(", ")}.` });
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
function formatValidationIssues(issues) {
|
|
@@ -284,6 +284,74 @@ function toErrorMessage(error) {
|
|
|
284
284
|
return error instanceof Error ? error.message : String(error);
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
// src/types/publish_strategy.ts
|
|
288
|
+
function isPublishable(strategy, frontmatter) {
|
|
289
|
+
if (strategy === "explicit") {
|
|
290
|
+
return frontmatter?.publish === true;
|
|
291
|
+
}
|
|
292
|
+
return !(frontmatter?.private === true || frontmatter?.draft === true);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/content/publishing.ts
|
|
296
|
+
function resolvePublishingState(frontmatter, options) {
|
|
297
|
+
const explicitVisibility = resolveExplicitVisibility(frontmatter?.visibility);
|
|
298
|
+
const publishAt = resolvePublishAt(frontmatter?.publishAt);
|
|
299
|
+
if (explicitVisibility === "draft")
|
|
300
|
+
return state("draft", false, false, publishAt);
|
|
301
|
+
if (publishAt && publishAt.getTime() > options.buildTime.getTime()) {
|
|
302
|
+
return state("scheduled", false, false, publishAt);
|
|
303
|
+
}
|
|
304
|
+
if (explicitVisibility === "unlisted") {
|
|
305
|
+
return state("unlisted", true, false, publishAt);
|
|
306
|
+
}
|
|
307
|
+
if (explicitVisibility === "public" || publishAt) {
|
|
308
|
+
return state("public", true, true, publishAt);
|
|
309
|
+
}
|
|
310
|
+
const routable = isPublishable(options.strategy, frontmatter);
|
|
311
|
+
return state(routable ? "public" : "draft", routable, routable, publishAt);
|
|
312
|
+
}
|
|
313
|
+
function resolvePublishingBuildTime(input) {
|
|
314
|
+
if (input === void 0) return /* @__PURE__ */ new Date();
|
|
315
|
+
if (input instanceof Date) {
|
|
316
|
+
if (Number.isNaN(input.getTime()))
|
|
317
|
+
throw new Error("Invalid publishing build time.");
|
|
318
|
+
return new Date(input.getTime());
|
|
319
|
+
}
|
|
320
|
+
const parsed = new Date(input);
|
|
321
|
+
if (Number.isNaN(parsed.getTime()))
|
|
322
|
+
throw new Error("Invalid publishing build time.");
|
|
323
|
+
return parsed;
|
|
324
|
+
}
|
|
325
|
+
function resolveExplicitVisibility(value) {
|
|
326
|
+
if (value === void 0) return void 0;
|
|
327
|
+
if (value === "public" || value === "unlisted" || value === "draft")
|
|
328
|
+
return value;
|
|
329
|
+
throw new Error(
|
|
330
|
+
`Invalid content visibility "${String(value)}". Expected public, unlisted, or draft.`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
function resolvePublishAt(value) {
|
|
334
|
+
if (value === void 0) return void 0;
|
|
335
|
+
if (!(typeof value === "string" || value instanceof Date)) {
|
|
336
|
+
throw new Error("Invalid publishAt. Expected an ISO 8601 date string.");
|
|
337
|
+
}
|
|
338
|
+
const parsed = value instanceof Date ? value : new Date(value);
|
|
339
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
340
|
+
throw new Error(
|
|
341
|
+
`Invalid publishAt "${String(value)}". Expected an ISO 8601 date string.`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return new Date(parsed.getTime());
|
|
345
|
+
}
|
|
346
|
+
function state(visibility, routable, discoverable, publishAt) {
|
|
347
|
+
return {
|
|
348
|
+
visibility,
|
|
349
|
+
routable,
|
|
350
|
+
discoverable,
|
|
351
|
+
...publishAt ? { publishAt } : {}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
287
355
|
// src/plugin/plugin_dependency_error.ts
|
|
288
356
|
var PluginDependencyError = class extends Error {
|
|
289
357
|
kind;
|
|
@@ -573,14 +641,6 @@ function getResolvedPluginMetadata(plugins) {
|
|
|
573
641
|
}));
|
|
574
642
|
}
|
|
575
643
|
|
|
576
|
-
// src/types/publish_strategy.ts
|
|
577
|
-
function isPublishable(strategy, frontmatter) {
|
|
578
|
-
if (strategy === "explicit") {
|
|
579
|
-
return frontmatter?.publish === true;
|
|
580
|
-
}
|
|
581
|
-
return !(frontmatter?.private === true || frontmatter?.draft === true);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
644
|
// src/types/theme_config.ts
|
|
585
645
|
function defineTheme(theme) {
|
|
586
646
|
return theme;
|
|
@@ -680,10 +740,11 @@ function sanitizeThemeAttributes(attributes) {
|
|
|
680
740
|
).filter(([name]) => !reservedAttributes.has(name))
|
|
681
741
|
);
|
|
682
742
|
}
|
|
683
|
-
function isPublished(config, frontmatter) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
743
|
+
function isPublished(config, frontmatter, options = {}) {
|
|
744
|
+
return resolvePublishingState(frontmatter, {
|
|
745
|
+
strategy: config.content.filters.publishStrategy,
|
|
746
|
+
buildTime: resolvePublishingBuildTime(options.buildTime)
|
|
747
|
+
}).routable;
|
|
687
748
|
}
|
|
688
749
|
function isExcluded(patterns, relativePath) {
|
|
689
750
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
@@ -745,9 +806,9 @@ var configDeprecations = [];
|
|
|
745
806
|
function collectConfigDeprecationDiagnostics(config, notices = configDeprecations) {
|
|
746
807
|
return notices.filter((notice) => hasConfigPath(config, notice.path)).map(createDeprecationDiagnostic);
|
|
747
808
|
}
|
|
748
|
-
function hasConfigPath(config,
|
|
809
|
+
function hasConfigPath(config, path6) {
|
|
749
810
|
let value = config;
|
|
750
|
-
for (const segment of
|
|
811
|
+
for (const segment of path6.split(".")) {
|
|
751
812
|
if (!isRecord2(value) || !(segment in value)) return false;
|
|
752
813
|
value = value[segment];
|
|
753
814
|
}
|
|
@@ -810,7 +871,7 @@ import fs from "node:fs/promises";
|
|
|
810
871
|
import path from "node:path";
|
|
811
872
|
|
|
812
873
|
// src/content/content_build_state.ts
|
|
813
|
-
var CONTENT_BUILD_STATE_VERSION =
|
|
874
|
+
var CONTENT_BUILD_STATE_VERSION = 8;
|
|
814
875
|
var CONTENT_BUILD_STATE_DIRECTORY = ".riebeckite";
|
|
815
876
|
var CONTENT_BUILD_STATE_EXCLUDE = `${CONTENT_BUILD_STATE_DIRECTORY}/**`;
|
|
816
877
|
|
|
@@ -1215,9 +1276,9 @@ function buildContentCollections(entries, definitions) {
|
|
|
1215
1276
|
function normalizePageSize(value) {
|
|
1216
1277
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
1217
1278
|
}
|
|
1218
|
-
function withPage(
|
|
1219
|
-
if (index === 0) return
|
|
1220
|
-
const base =
|
|
1279
|
+
function withPage(path6, index) {
|
|
1280
|
+
if (index === 0) return path6;
|
|
1281
|
+
const base = path6 === "/" ? "" : path6;
|
|
1221
1282
|
return normalizePath(`${base}/page/${index + 1}`);
|
|
1222
1283
|
}
|
|
1223
1284
|
function defaultPath(context) {
|
|
@@ -1705,7 +1766,14 @@ function createPersistentContentCache(options) {
|
|
|
1705
1766
|
);
|
|
1706
1767
|
return void 0;
|
|
1707
1768
|
}
|
|
1708
|
-
|
|
1769
|
+
logger?.warn(
|
|
1770
|
+
"Persistent content cache entry could not be read and will be ignored.",
|
|
1771
|
+
{
|
|
1772
|
+
key,
|
|
1773
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1774
|
+
}
|
|
1775
|
+
);
|
|
1776
|
+
return void 0;
|
|
1709
1777
|
}
|
|
1710
1778
|
},
|
|
1711
1779
|
async set(key, value) {
|
|
@@ -1717,8 +1785,18 @@ function createPersistentContentCache(options) {
|
|
|
1717
1785
|
"Persistent content cache values must be JSON serializable."
|
|
1718
1786
|
);
|
|
1719
1787
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1788
|
+
try {
|
|
1789
|
+
await writeAtomically(filePath, versionDir, serialized);
|
|
1790
|
+
tracer?.event("persistentContentCache.write", { key });
|
|
1791
|
+
} catch (error) {
|
|
1792
|
+
logger?.warn(
|
|
1793
|
+
"Persistent content cache entry could not be written and will be ignored.",
|
|
1794
|
+
{
|
|
1795
|
+
key,
|
|
1796
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1797
|
+
}
|
|
1798
|
+
);
|
|
1799
|
+
}
|
|
1722
1800
|
},
|
|
1723
1801
|
async clear() {
|
|
1724
1802
|
try {
|
|
@@ -2463,9 +2541,9 @@ function resolveRelativeMarkdownSlug(sourceSlug, targetPath) {
|
|
|
2463
2541
|
}
|
|
2464
2542
|
return normalizedParts.join("/").replace(/\.md$/i, "");
|
|
2465
2543
|
}
|
|
2466
|
-
function decodeUriPath(
|
|
2544
|
+
function decodeUriPath(path6) {
|
|
2467
2545
|
try {
|
|
2468
|
-
return decodeURI(
|
|
2546
|
+
return decodeURI(path6);
|
|
2469
2547
|
} catch {
|
|
2470
2548
|
return null;
|
|
2471
2549
|
}
|
|
@@ -2553,16 +2631,16 @@ var GeneratedOutputRegistry = class {
|
|
|
2553
2631
|
outputs = [];
|
|
2554
2632
|
owners = /* @__PURE__ */ new Map();
|
|
2555
2633
|
sinkFor(pluginName) {
|
|
2556
|
-
const register = (
|
|
2557
|
-
const owner = this.owners.get(
|
|
2634
|
+
const register = (path6, output) => {
|
|
2635
|
+
const owner = this.owners.get(path6);
|
|
2558
2636
|
if (owner) {
|
|
2559
2637
|
throw new Error(
|
|
2560
|
-
`Duplicate generated output path "${
|
|
2638
|
+
`Duplicate generated output path "${path6}" declared by "${owner}" and "${pluginName}".`
|
|
2561
2639
|
);
|
|
2562
2640
|
}
|
|
2563
|
-
this.owners.set(
|
|
2641
|
+
this.owners.set(path6, pluginName);
|
|
2564
2642
|
this.outputs.push({
|
|
2565
|
-
path:
|
|
2643
|
+
path: path6,
|
|
2566
2644
|
content: output.content,
|
|
2567
2645
|
dependencies: output.dependencies,
|
|
2568
2646
|
owner: pluginName
|
|
@@ -2586,9 +2664,12 @@ var GeneratedOutputRegistry = class {
|
|
|
2586
2664
|
|
|
2587
2665
|
// src/plugin/plugin_lifecycle.ts
|
|
2588
2666
|
var PluginHookError = class extends Error {
|
|
2667
|
+
path;
|
|
2589
2668
|
constructor(pluginName, hookName, cause) {
|
|
2590
2669
|
super(`Plugin "${pluginName}" failed during "${hookName}"`, { cause });
|
|
2591
2670
|
this.name = "PluginHookError";
|
|
2671
|
+
const path6 = cause?.path;
|
|
2672
|
+
if (typeof path6 === "string") this.path = path6;
|
|
2592
2673
|
}
|
|
2593
2674
|
};
|
|
2594
2675
|
async function runPluginHook(plugin, hookName, context, hook) {
|
|
@@ -3073,12 +3154,12 @@ function normalizePageTypePath(pathname, pageType) {
|
|
|
3073
3154
|
return pageType.directoryIndex ? normalizeDirectoryPagePath(pathname) : normalizePagePath(pathname);
|
|
3074
3155
|
}
|
|
3075
3156
|
function normalizeDirectoryPagePath(pathname) {
|
|
3076
|
-
const
|
|
3077
|
-
return
|
|
3157
|
+
const path6 = normalizePagePath(pathname);
|
|
3158
|
+
return path6 === "/" ? path6 : `${path6}/`;
|
|
3078
3159
|
}
|
|
3079
3160
|
function normalizePagePath(pathname) {
|
|
3080
|
-
const
|
|
3081
|
-
return
|
|
3161
|
+
const path6 = `/${pathname.split("/").filter(Boolean).join("/")}`;
|
|
3162
|
+
return path6 === "/" ? path6 : path6.replace(/\/$/, "");
|
|
3082
3163
|
}
|
|
3083
3164
|
function countSeverity(diagnostics, severity) {
|
|
3084
3165
|
return diagnostics.filter((diagnostic) => diagnostic.severity === severity).length;
|
|
@@ -3101,6 +3182,14 @@ function uniqueOutputs(outputs) {
|
|
|
3101
3182
|
return [...byPath.values()].map(({ output }) => output).sort((left, right) => left.path.localeCompare(right.path));
|
|
3102
3183
|
}
|
|
3103
3184
|
|
|
3185
|
+
// src/utils/error.ts
|
|
3186
|
+
function attachErrorPath(error, path6) {
|
|
3187
|
+
if (error instanceof Error && error.path === void 0) {
|
|
3188
|
+
error.path = path6;
|
|
3189
|
+
}
|
|
3190
|
+
return error;
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3104
3193
|
// src/content/affected_content.ts
|
|
3105
3194
|
function determineAffectedContent(changeSet, previousState, currentPaths, currentContentIndex) {
|
|
3106
3195
|
const changedPaths = [
|
|
@@ -3121,9 +3210,9 @@ function determineAffectedContent(changeSet, previousState, currentPaths, curren
|
|
|
3121
3210
|
previousState.contentIndex,
|
|
3122
3211
|
currentContentIndex
|
|
3123
3212
|
);
|
|
3124
|
-
for (const [
|
|
3125
|
-
if (!isMarkdownPath2(
|
|
3126
|
-
const slug = toDependencyId(
|
|
3213
|
+
for (const [path6, entry] of Object.entries(previousState.entries)) {
|
|
3214
|
+
if (!isMarkdownPath2(path6)) continue;
|
|
3215
|
+
const slug = toDependencyId(path6);
|
|
3127
3216
|
if (direct.has(slug) || dependent.has(slug)) continue;
|
|
3128
3217
|
if (!entry.linkTargets?.some((target) => changedIndexKeys.has(target))) {
|
|
3129
3218
|
continue;
|
|
@@ -3160,27 +3249,27 @@ function findChangedIndexKeys(previousIndex, currentIndex) {
|
|
|
3160
3249
|
return changed;
|
|
3161
3250
|
}
|
|
3162
3251
|
function addAllNotes(target, currentPaths, exclude) {
|
|
3163
|
-
for (const
|
|
3164
|
-
if (!isMarkdownPath2(
|
|
3165
|
-
const slug = toDependencyId(
|
|
3252
|
+
for (const path6 of currentPaths) {
|
|
3253
|
+
if (!isMarkdownPath2(path6)) continue;
|
|
3254
|
+
const slug = toDependencyId(path6);
|
|
3166
3255
|
if (exclude?.has(slug)) continue;
|
|
3167
3256
|
target.add(slug);
|
|
3168
3257
|
}
|
|
3169
3258
|
}
|
|
3170
|
-
function isMarkdownPath2(
|
|
3171
|
-
return
|
|
3259
|
+
function isMarkdownPath2(path6) {
|
|
3260
|
+
return path6.endsWith(".md");
|
|
3172
3261
|
}
|
|
3173
|
-
function toDependencyId(
|
|
3174
|
-
return
|
|
3262
|
+
function toDependencyId(path6) {
|
|
3263
|
+
return path6.replace(/\.md$/, "");
|
|
3175
3264
|
}
|
|
3176
|
-
function toDependency(
|
|
3177
|
-
return isMarkdownPath2(
|
|
3265
|
+
function toDependency(path6) {
|
|
3266
|
+
return isMarkdownPath2(path6) ? { kind: "content", id: toDependencyId(path6) } : { kind: "file", id: path6.replace(/\\/g, "/") };
|
|
3178
3267
|
}
|
|
3179
3268
|
function buildDependentsByDependency(state2) {
|
|
3180
3269
|
const dependents = /* @__PURE__ */ new Map();
|
|
3181
|
-
for (const [
|
|
3182
|
-
if (!isMarkdownPath2(
|
|
3183
|
-
const slug = toDependencyId(
|
|
3270
|
+
for (const [path6, entry] of Object.entries(state2.entries)) {
|
|
3271
|
+
if (!isMarkdownPath2(path6)) continue;
|
|
3272
|
+
const slug = toDependencyId(path6);
|
|
3184
3273
|
for (const dependency of entry.dependencies) {
|
|
3185
3274
|
const key = dependencyKey2(dependency);
|
|
3186
3275
|
const values = dependents.get(key) ?? /* @__PURE__ */ new Set();
|
|
@@ -3202,18 +3291,18 @@ function diffContentEntries(previous, current) {
|
|
|
3202
3291
|
const added = [];
|
|
3203
3292
|
const changed = [];
|
|
3204
3293
|
const unchanged = [];
|
|
3205
|
-
for (const [
|
|
3206
|
-
const previousEntry = previous.entries[
|
|
3294
|
+
for (const [path6, fingerprint] of currentFingerprints) {
|
|
3295
|
+
const previousEntry = previous.entries[path6];
|
|
3207
3296
|
if (!previousEntry) {
|
|
3208
|
-
added.push(
|
|
3297
|
+
added.push(path6);
|
|
3209
3298
|
} else if (previousEntry.fingerprint !== fingerprint) {
|
|
3210
|
-
changed.push(
|
|
3299
|
+
changed.push(path6);
|
|
3211
3300
|
} else {
|
|
3212
|
-
unchanged.push(
|
|
3301
|
+
unchanged.push(path6);
|
|
3213
3302
|
}
|
|
3214
3303
|
}
|
|
3215
3304
|
const removed = Object.keys(previous.entries).filter(
|
|
3216
|
-
(
|
|
3305
|
+
(path6) => !currentFingerprints.has(path6)
|
|
3217
3306
|
);
|
|
3218
3307
|
return sortChangeSet({ added, changed, removed, unchanged });
|
|
3219
3308
|
}
|
|
@@ -3225,9 +3314,6 @@ function allContentChanged(entries) {
|
|
|
3225
3314
|
unchanged: []
|
|
3226
3315
|
});
|
|
3227
3316
|
}
|
|
3228
|
-
function hasContentChanges(changeSet) {
|
|
3229
|
-
return changeSet.added.length > 0 || changeSet.changed.length > 0 || changeSet.removed.length > 0;
|
|
3230
|
-
}
|
|
3231
3317
|
function sortChangeSet(changeSet) {
|
|
3232
3318
|
return {
|
|
3233
3319
|
added: [...changeSet.added].sort(),
|
|
@@ -3303,54 +3389,73 @@ var ContentIndexBuilder = class _ContentIndexBuilder {
|
|
|
3303
3389
|
}
|
|
3304
3390
|
source;
|
|
3305
3391
|
async build(contentEntries, read = (entry) => this.source.read(entry)) {
|
|
3306
|
-
const
|
|
3392
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
3307
3393
|
for (const contentEntry of contentEntries) {
|
|
3308
|
-
await this.indexContentEntry(
|
|
3394
|
+
await this.indexContentEntry(candidates, contentEntry, read);
|
|
3309
3395
|
}
|
|
3310
|
-
return
|
|
3396
|
+
return resolveContentIndex(candidates);
|
|
3311
3397
|
}
|
|
3312
3398
|
static buildFromAliases(contentEntries, aliasesByPath) {
|
|
3313
|
-
const
|
|
3399
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
3314
3400
|
for (const contentEntry of contentEntries) {
|
|
3315
3401
|
_ContentIndexBuilder.indexContentEntryFromAliases(
|
|
3316
|
-
|
|
3402
|
+
candidates,
|
|
3317
3403
|
contentEntry,
|
|
3318
3404
|
aliasesByPath.get(contentEntry.path) ?? []
|
|
3319
3405
|
);
|
|
3320
3406
|
}
|
|
3321
|
-
return
|
|
3407
|
+
return resolveContentIndex(candidates);
|
|
3322
3408
|
}
|
|
3323
|
-
async indexContentEntry(
|
|
3409
|
+
async indexContentEntry(candidates, contentEntry, read) {
|
|
3324
3410
|
const aliases = contentEntry.path.toLowerCase().endsWith(".md") ? extractFrontmatterAliases(readText(await read(contentEntry))) : [];
|
|
3325
3411
|
_ContentIndexBuilder.indexContentEntryFromAliases(
|
|
3326
|
-
|
|
3412
|
+
candidates,
|
|
3327
3413
|
contentEntry,
|
|
3328
3414
|
aliases
|
|
3329
3415
|
);
|
|
3330
3416
|
}
|
|
3331
|
-
static indexContentEntryFromAliases(
|
|
3417
|
+
static indexContentEntryFromAliases(candidates, contentEntry, aliases) {
|
|
3332
3418
|
const contentPath = contentEntry.path;
|
|
3333
3419
|
const ext = contentPath.split(".").pop()?.toLowerCase() ?? "";
|
|
3334
3420
|
const value = ext === "md" ? contentPath.replace(/\.md$/, "") : contentPath;
|
|
3335
3421
|
const parts = value.split("/");
|
|
3336
3422
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
3337
3423
|
const rawSuffix = parts.slice(i).join("/");
|
|
3338
|
-
|
|
3424
|
+
addCandidate(candidates, rawSuffix, value);
|
|
3339
3425
|
if (ext !== "md") {
|
|
3340
|
-
|
|
3426
|
+
addCandidate(candidates, rawSuffix.replace(/\.[^/.]+$/, ""), value);
|
|
3341
3427
|
}
|
|
3342
3428
|
}
|
|
3343
3429
|
if (ext === "md") {
|
|
3344
|
-
for (const alias of aliases)
|
|
3430
|
+
for (const alias of aliases) addCandidate(candidates, alias, value);
|
|
3345
3431
|
}
|
|
3346
3432
|
}
|
|
3347
3433
|
};
|
|
3434
|
+
function resolveContentIndex(candidates) {
|
|
3435
|
+
const index = /* @__PURE__ */ new Map();
|
|
3436
|
+
const ambiguities = /* @__PURE__ */ new Map();
|
|
3437
|
+
for (const [key, values] of candidates) {
|
|
3438
|
+
const list = [...values].sort(compareCandidates);
|
|
3439
|
+
const [only] = list;
|
|
3440
|
+
if (list.length === 1 && only !== void 0) {
|
|
3441
|
+
index.set(key, only);
|
|
3442
|
+
continue;
|
|
3443
|
+
}
|
|
3444
|
+
ambiguities.set(key, list);
|
|
3445
|
+
}
|
|
3446
|
+
return { index, ambiguities };
|
|
3447
|
+
}
|
|
3448
|
+
function compareCandidates(left, right) {
|
|
3449
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
3450
|
+
}
|
|
3348
3451
|
function readText(content) {
|
|
3349
3452
|
return typeof content === "string" ? content : new TextDecoder().decode(content);
|
|
3350
3453
|
}
|
|
3351
|
-
function
|
|
3454
|
+
function addCandidate(candidates, key, value) {
|
|
3352
3455
|
const normalizedKey = key.toLowerCase();
|
|
3353
|
-
|
|
3456
|
+
const values = candidates.get(normalizedKey) ?? /* @__PURE__ */ new Set();
|
|
3457
|
+
values.add(value);
|
|
3458
|
+
candidates.set(normalizedKey, values);
|
|
3354
3459
|
}
|
|
3355
3460
|
|
|
3356
3461
|
// src/content/content_build_coordinator.ts
|
|
@@ -3433,7 +3538,10 @@ var ContentBuildCoordinator = class {
|
|
|
3433
3538
|
previousState,
|
|
3434
3539
|
changeSet
|
|
3435
3540
|
);
|
|
3436
|
-
const
|
|
3541
|
+
const {
|
|
3542
|
+
index: currentContentIndex,
|
|
3543
|
+
ambiguities: currentContentIndexAmbiguities
|
|
3544
|
+
} = await this.dependencies.observability.tracer.span(
|
|
3437
3545
|
"content.index",
|
|
3438
3546
|
{},
|
|
3439
3547
|
() => ContentIndexBuilder.buildFromAliases(
|
|
@@ -3471,6 +3579,7 @@ var ContentBuildCoordinator = class {
|
|
|
3471
3579
|
currentEntries,
|
|
3472
3580
|
currentContentAliases,
|
|
3473
3581
|
currentContentIndex,
|
|
3582
|
+
currentContentIndexAmbiguities,
|
|
3474
3583
|
changeSet,
|
|
3475
3584
|
affectedContent: affected
|
|
3476
3585
|
};
|
|
@@ -3498,8 +3607,8 @@ var ContentBuildCoordinator = class {
|
|
|
3498
3607
|
function readText2(content) {
|
|
3499
3608
|
return typeof content === "string" ? content : new TextDecoder().decode(content);
|
|
3500
3609
|
}
|
|
3501
|
-
function toSlug(
|
|
3502
|
-
return
|
|
3610
|
+
function toSlug(path6) {
|
|
3611
|
+
return path6.replace(/\.md$/, "");
|
|
3503
3612
|
}
|
|
3504
3613
|
function collectDependencies2(manifestEntry, trackedDependencies) {
|
|
3505
3614
|
if (!manifestEntry) return [];
|
|
@@ -3588,9 +3697,14 @@ var ContentEntryReader = class {
|
|
|
3588
3697
|
if (cached) return cached;
|
|
3589
3698
|
const content = this.source.read(entry).then(
|
|
3590
3699
|
(value) => typeof value === "string" ? value : new TextDecoder().decode(value)
|
|
3591
|
-
)
|
|
3592
|
-
|
|
3593
|
-
|
|
3700
|
+
);
|
|
3701
|
+
const retain = entry.path.endsWith(".md");
|
|
3702
|
+
const tracked = retain ? content : content.finally(() => this.texts.delete(entry.path));
|
|
3703
|
+
this.texts.set(entry.path, tracked);
|
|
3704
|
+
return tracked;
|
|
3705
|
+
}
|
|
3706
|
+
clearReadCache() {
|
|
3707
|
+
this.texts.clear();
|
|
3594
3708
|
}
|
|
3595
3709
|
};
|
|
3596
3710
|
|
|
@@ -3682,8 +3796,8 @@ var ContentLocationResolver = class {
|
|
|
3682
3796
|
}
|
|
3683
3797
|
}
|
|
3684
3798
|
};
|
|
3685
|
-
function toSlug2(
|
|
3686
|
-
return
|
|
3799
|
+
function toSlug2(path6) {
|
|
3800
|
+
return path6.replace(/\.md$/, "");
|
|
3687
3801
|
}
|
|
3688
3802
|
async function mapConcurrent2(values, concurrency, map) {
|
|
3689
3803
|
const results = new Array(values.length);
|
|
@@ -3881,7 +3995,7 @@ var ManifestBuilder = class {
|
|
|
3881
3995
|
assets: uniqueAssets(assets)
|
|
3882
3996
|
};
|
|
3883
3997
|
}
|
|
3884
|
-
build(entries, contentIndex) {
|
|
3998
|
+
build(entries, contentIndex, contentIndexAmbiguities = /* @__PURE__ */ new Map()) {
|
|
3885
3999
|
const bySlug = new Map(entries.map((entry) => [entry.slug, entry]));
|
|
3886
4000
|
const byContentId = createContentIdIndex(entries);
|
|
3887
4001
|
const byAlias = createAliasIndex(entries);
|
|
@@ -3922,6 +4036,7 @@ var ManifestBuilder = class {
|
|
|
3922
4036
|
outgoingLinks,
|
|
3923
4037
|
incomingLinks,
|
|
3924
4038
|
contentIndex,
|
|
4039
|
+
contentIndexAmbiguities,
|
|
3925
4040
|
assets: [],
|
|
3926
4041
|
clientEntries: [],
|
|
3927
4042
|
diagnostics: [],
|
|
@@ -4038,10 +4153,10 @@ function buildOutputInventory(manifest, pluginPageOutputs = [], contentOutputDep
|
|
|
4038
4153
|
for (const entry of manifest.publicEntries) {
|
|
4039
4154
|
addOutput(outputs, contentOutput(entry, contentOutputDependencies));
|
|
4040
4155
|
}
|
|
4041
|
-
for (const [
|
|
4156
|
+
for (const [path6, redirect] of manifest.publicRedirects) {
|
|
4042
4157
|
addOutput(outputs, {
|
|
4043
4158
|
kind: "redirect",
|
|
4044
|
-
path: htmlOutputPath(
|
|
4159
|
+
path: htmlOutputPath(path6),
|
|
4045
4160
|
producer: `content:${redirect.slug}:redirect`,
|
|
4046
4161
|
dependencies: [{ type: "content", slug: redirect.slug }]
|
|
4047
4162
|
});
|
|
@@ -4170,79 +4285,19 @@ function assertNoGeneratedOutputCollision(existing, incoming) {
|
|
|
4170
4285
|
);
|
|
4171
4286
|
}
|
|
4172
4287
|
function normalizePublicPath(pathname) {
|
|
4173
|
-
const
|
|
4174
|
-
return
|
|
4288
|
+
const path6 = `/${pathname.split("/").filter(Boolean).join("/")}`;
|
|
4289
|
+
return path6 === "/" ? path6 : path6.replace(/\/$/, "");
|
|
4175
4290
|
}
|
|
4176
|
-
function isMarkdownPath3(
|
|
4177
|
-
return
|
|
4291
|
+
function isMarkdownPath3(path6) {
|
|
4292
|
+
return path6.endsWith(".md");
|
|
4178
4293
|
}
|
|
4179
|
-
function toSlug3(
|
|
4180
|
-
return
|
|
4294
|
+
function toSlug3(path6) {
|
|
4295
|
+
return path6.replace(/\.md$/, "");
|
|
4181
4296
|
}
|
|
4182
4297
|
function compareOutput(left, right) {
|
|
4183
4298
|
return left.path.localeCompare(right.path) || left.kind.localeCompare(right.kind);
|
|
4184
4299
|
}
|
|
4185
4300
|
|
|
4186
|
-
// src/content/publishing.ts
|
|
4187
|
-
function resolvePublishingState(frontmatter, options) {
|
|
4188
|
-
const explicitVisibility = resolveExplicitVisibility(frontmatter?.visibility);
|
|
4189
|
-
const publishAt = resolvePublishAt(frontmatter?.publishAt);
|
|
4190
|
-
if (explicitVisibility === "draft")
|
|
4191
|
-
return state("draft", false, false, publishAt);
|
|
4192
|
-
if (publishAt && publishAt.getTime() > options.buildTime.getTime()) {
|
|
4193
|
-
return state("scheduled", false, false, publishAt);
|
|
4194
|
-
}
|
|
4195
|
-
if (explicitVisibility === "unlisted") {
|
|
4196
|
-
return state("unlisted", true, false, publishAt);
|
|
4197
|
-
}
|
|
4198
|
-
if (explicitVisibility === "public" || publishAt) {
|
|
4199
|
-
return state("public", true, true, publishAt);
|
|
4200
|
-
}
|
|
4201
|
-
const routable = isPublishable(options.strategy, frontmatter);
|
|
4202
|
-
return state(routable ? "public" : "draft", routable, routable, publishAt);
|
|
4203
|
-
}
|
|
4204
|
-
function resolvePublishingBuildTime(input) {
|
|
4205
|
-
if (input === void 0) return /* @__PURE__ */ new Date();
|
|
4206
|
-
if (input instanceof Date) {
|
|
4207
|
-
if (Number.isNaN(input.getTime()))
|
|
4208
|
-
throw new Error("Invalid publishing build time.");
|
|
4209
|
-
return new Date(input.getTime());
|
|
4210
|
-
}
|
|
4211
|
-
const parsed = new Date(input);
|
|
4212
|
-
if (Number.isNaN(parsed.getTime()))
|
|
4213
|
-
throw new Error("Invalid publishing build time.");
|
|
4214
|
-
return parsed;
|
|
4215
|
-
}
|
|
4216
|
-
function resolveExplicitVisibility(value) {
|
|
4217
|
-
if (value === void 0) return void 0;
|
|
4218
|
-
if (value === "public" || value === "unlisted" || value === "draft")
|
|
4219
|
-
return value;
|
|
4220
|
-
throw new Error(
|
|
4221
|
-
`Invalid content visibility "${String(value)}". Expected public, unlisted, or draft.`
|
|
4222
|
-
);
|
|
4223
|
-
}
|
|
4224
|
-
function resolvePublishAt(value) {
|
|
4225
|
-
if (value === void 0) return void 0;
|
|
4226
|
-
if (!(typeof value === "string" || value instanceof Date)) {
|
|
4227
|
-
throw new Error("Invalid publishAt. Expected an ISO 8601 date string.");
|
|
4228
|
-
}
|
|
4229
|
-
const parsed = value instanceof Date ? value : new Date(value);
|
|
4230
|
-
if (Number.isNaN(parsed.getTime())) {
|
|
4231
|
-
throw new Error(
|
|
4232
|
-
`Invalid publishAt "${String(value)}". Expected an ISO 8601 date string.`
|
|
4233
|
-
);
|
|
4234
|
-
}
|
|
4235
|
-
return new Date(parsed.getTime());
|
|
4236
|
-
}
|
|
4237
|
-
function state(visibility, routable, discoverable, publishAt) {
|
|
4238
|
-
return {
|
|
4239
|
-
visibility,
|
|
4240
|
-
routable,
|
|
4241
|
-
discoverable,
|
|
4242
|
-
...publishAt ? { publishAt } : {}
|
|
4243
|
-
};
|
|
4244
|
-
}
|
|
4245
|
-
|
|
4246
4301
|
// src/content/content_manager.ts
|
|
4247
4302
|
var CONTENT_PROCESSING_CONCURRENCY = 16;
|
|
4248
4303
|
var ContentManager = class {
|
|
@@ -4300,6 +4355,7 @@ var ContentManager = class {
|
|
|
4300
4355
|
manifestBuilder = new ManifestBuilder();
|
|
4301
4356
|
pluginRuntime;
|
|
4302
4357
|
contentIndex = null;
|
|
4358
|
+
contentIndexAmbiguities = /* @__PURE__ */ new Map();
|
|
4303
4359
|
contentIndexPromise = null;
|
|
4304
4360
|
contentCache = /* @__PURE__ */ new Map();
|
|
4305
4361
|
manifest = null;
|
|
@@ -4328,15 +4384,10 @@ var ContentManager = class {
|
|
|
4328
4384
|
async getContentIndex(preparation) {
|
|
4329
4385
|
if (this.contentIndex) return this.contentIndex;
|
|
4330
4386
|
if (!preparation && this.contentIndexPromise)
|
|
4331
|
-
return await this.contentIndexPromise;
|
|
4332
|
-
if (preparation?.previousState && !hasContentChanges(preparation.changeSet)) {
|
|
4333
|
-
this.contentIndex = new Map(
|
|
4334
|
-
Object.entries(preparation.previousState.contentIndex)
|
|
4335
|
-
);
|
|
4336
|
-
return this.contentIndex;
|
|
4337
|
-
}
|
|
4387
|
+
return (await this.contentIndexPromise).index;
|
|
4338
4388
|
if (preparation) {
|
|
4339
4389
|
this.contentIndex = preparation.currentContentIndex;
|
|
4390
|
+
this.contentIndexAmbiguities = preparation.currentContentIndexAmbiguities;
|
|
4340
4391
|
return this.contentIndex;
|
|
4341
4392
|
}
|
|
4342
4393
|
const promise = this.observability().tracer.span(
|
|
@@ -4349,7 +4400,9 @@ var ContentManager = class {
|
|
|
4349
4400
|
);
|
|
4350
4401
|
if (!preparation) this.contentIndexPromise = promise;
|
|
4351
4402
|
try {
|
|
4352
|
-
|
|
4403
|
+
const built = await promise;
|
|
4404
|
+
this.contentIndex = built.index;
|
|
4405
|
+
this.contentIndexAmbiguities = built.ambiguities;
|
|
4353
4406
|
return this.contentIndex;
|
|
4354
4407
|
} finally {
|
|
4355
4408
|
if (!preparation) this.contentIndexPromise = null;
|
|
@@ -4364,48 +4417,55 @@ var ContentManager = class {
|
|
|
4364
4417
|
contentPath: `${slug}.md`
|
|
4365
4418
|
},
|
|
4366
4419
|
async () => {
|
|
4367
|
-
|
|
4368
|
-
this.
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
await this.pluginRuntime.startBuild(contentIndex);
|
|
4372
|
-
await this.pluginRuntime.runContentLoaded(slug, rawPost, contentIndex);
|
|
4373
|
-
await this.ensureRoutableSlugs();
|
|
4374
|
-
this.pipeline ??= new Pipeline(
|
|
4375
|
-
contentIndex,
|
|
4376
|
-
await this.locationResolver.getPermalinks(),
|
|
4377
|
-
(postSlug) => this.getPost(postSlug),
|
|
4378
|
-
this.pipelineOptions,
|
|
4379
|
-
this.isBuildTime
|
|
4380
|
-
);
|
|
4381
|
-
const content = await this.pipeline.execute(rawPost, {
|
|
4382
|
-
sourceSlug: slug
|
|
4383
|
-
});
|
|
4384
|
-
this.processedContentCount += 1;
|
|
4385
|
-
if (this.processedContentCount % 100 === 0) {
|
|
4386
|
-
this.observability().tracer.event("content.process.sample", {
|
|
4387
|
-
processed: this.processedContentCount
|
|
4388
|
-
});
|
|
4420
|
+
try {
|
|
4421
|
+
return await this.processContent(slug);
|
|
4422
|
+
} catch (error) {
|
|
4423
|
+
throw attachErrorPath(error, `${slug}.md`);
|
|
4389
4424
|
}
|
|
4390
|
-
await this.pluginRuntime.runPostHook(
|
|
4391
|
-
"onPostParsed",
|
|
4392
|
-
slug,
|
|
4393
|
-
rawPost,
|
|
4394
|
-
content,
|
|
4395
|
-
contentIndex
|
|
4396
|
-
);
|
|
4397
|
-
await this.pluginRuntime.runPostHook(
|
|
4398
|
-
"onPostProcessed",
|
|
4399
|
-
slug,
|
|
4400
|
-
rawPost,
|
|
4401
|
-
content,
|
|
4402
|
-
contentIndex
|
|
4403
|
-
);
|
|
4404
|
-
this.contentCache.set(slug, content);
|
|
4405
|
-
return content;
|
|
4406
4425
|
}
|
|
4407
4426
|
);
|
|
4408
4427
|
}
|
|
4428
|
+
async processContent(slug) {
|
|
4429
|
+
const [contentIndex, rawPost] = await Promise.all([
|
|
4430
|
+
this.getContentIndex(),
|
|
4431
|
+
this.getPost(slug)
|
|
4432
|
+
]);
|
|
4433
|
+
await this.pluginRuntime.startBuild(contentIndex);
|
|
4434
|
+
await this.pluginRuntime.runContentLoaded(slug, rawPost, contentIndex);
|
|
4435
|
+
await this.ensureRoutableSlugs();
|
|
4436
|
+
this.pipeline ??= new Pipeline(
|
|
4437
|
+
contentIndex,
|
|
4438
|
+
await this.locationResolver.getPermalinks(),
|
|
4439
|
+
(postSlug) => this.getPost(postSlug),
|
|
4440
|
+
this.pipelineOptions,
|
|
4441
|
+
this.isBuildTime
|
|
4442
|
+
);
|
|
4443
|
+
const content = await this.pipeline.execute(rawPost, {
|
|
4444
|
+
sourceSlug: slug
|
|
4445
|
+
});
|
|
4446
|
+
this.processedContentCount += 1;
|
|
4447
|
+
if (this.processedContentCount % 100 === 0) {
|
|
4448
|
+
this.observability().tracer.event("content.process.sample", {
|
|
4449
|
+
processed: this.processedContentCount
|
|
4450
|
+
});
|
|
4451
|
+
}
|
|
4452
|
+
await this.pluginRuntime.runPostHook(
|
|
4453
|
+
"onPostParsed",
|
|
4454
|
+
slug,
|
|
4455
|
+
rawPost,
|
|
4456
|
+
content,
|
|
4457
|
+
contentIndex
|
|
4458
|
+
);
|
|
4459
|
+
await this.pluginRuntime.runPostHook(
|
|
4460
|
+
"onPostProcessed",
|
|
4461
|
+
slug,
|
|
4462
|
+
rawPost,
|
|
4463
|
+
content,
|
|
4464
|
+
contentIndex
|
|
4465
|
+
);
|
|
4466
|
+
this.contentCache.set(slug, content);
|
|
4467
|
+
return content;
|
|
4468
|
+
}
|
|
4409
4469
|
async getManifest(options) {
|
|
4410
4470
|
if (this.manifest) return this.manifest;
|
|
4411
4471
|
if (this.manifestPromise) return await this.manifestPromise;
|
|
@@ -4471,7 +4531,11 @@ var ContentManager = class {
|
|
|
4471
4531
|
const manifest = await this.observability().tracer.span(
|
|
4472
4532
|
"content.graph",
|
|
4473
4533
|
{},
|
|
4474
|
-
() => this.manifestBuilder.build(
|
|
4534
|
+
() => this.manifestBuilder.build(
|
|
4535
|
+
entries,
|
|
4536
|
+
contentIndex,
|
|
4537
|
+
this.contentIndexAmbiguities
|
|
4538
|
+
)
|
|
4475
4539
|
);
|
|
4476
4540
|
const cacheManifestEntries = structuredClone(manifest.entries);
|
|
4477
4541
|
this.locationResolver.populateRedirects(manifest, locations);
|
|
@@ -4608,6 +4672,7 @@ var ContentManager = class {
|
|
|
4608
4672
|
return { entries, contentIndex, diagnostics };
|
|
4609
4673
|
}
|
|
4610
4674
|
async dispose() {
|
|
4675
|
+
this.entryReader.clearReadCache();
|
|
4611
4676
|
if (!this.contentIndex) return;
|
|
4612
4677
|
await this.pluginRuntime.dispose(this.contentIndex);
|
|
4613
4678
|
}
|
|
@@ -4707,7 +4772,13 @@ var ContentManager = class {
|
|
|
4707
4772
|
const routableSlugs = /* @__PURE__ */ new Set();
|
|
4708
4773
|
await mapConcurrent3(posts, CONTENT_PROCESSING_CONCURRENCY, async (post) => {
|
|
4709
4774
|
const markdown = await this.getPost(post.slug);
|
|
4710
|
-
|
|
4775
|
+
let frontmatter;
|
|
4776
|
+
try {
|
|
4777
|
+
frontmatter = readFrontmatter(markdown);
|
|
4778
|
+
} catch (error) {
|
|
4779
|
+
throw attachErrorPath(error, `${post.slug}.md`);
|
|
4780
|
+
}
|
|
4781
|
+
const publishing = resolvePublishingState(frontmatter, {
|
|
4711
4782
|
strategy,
|
|
4712
4783
|
buildTime: this.publishingBuildTime
|
|
4713
4784
|
});
|
|
@@ -4797,7 +4868,12 @@ function resolveFolderLocation(manifest, folder) {
|
|
|
4797
4868
|
if (candidate) return { type: "content", entry: candidate.entry };
|
|
4798
4869
|
}
|
|
4799
4870
|
if (candidates.length > 1) return { type: "ambiguous", candidates };
|
|
4800
|
-
const
|
|
4871
|
+
const normalizedFolder = normalizeFolder2(folder);
|
|
4872
|
+
const direct = manifest.folderLocations.get(normalizedFolder);
|
|
4873
|
+
if (direct) return { type: "generated", pathname: direct.pathname };
|
|
4874
|
+
const location = [...manifest.folderLocations.values()].find(
|
|
4875
|
+
(candidate) => candidate.folder === normalizedFolder
|
|
4876
|
+
);
|
|
4801
4877
|
return location ? { type: "generated", pathname: location.pathname } : { type: "none" };
|
|
4802
4878
|
}
|
|
4803
4879
|
function resolvePublicFolderLocation(manifest, pathname) {
|
|
@@ -4811,12 +4887,15 @@ function resolvePublicFolderLocation(manifest, pathname) {
|
|
|
4811
4887
|
);
|
|
4812
4888
|
return location ? { type: "generated", pathname: location.pathname } : { type: "none" };
|
|
4813
4889
|
}
|
|
4814
|
-
function resolveGeneratedFolderLocation(manifest, folder) {
|
|
4890
|
+
function resolveGeneratedFolderLocation(manifest, folder, language) {
|
|
4815
4891
|
const normalizedFolder = normalizeFolder2(folder);
|
|
4816
4892
|
if (!normalizedFolder) return null;
|
|
4817
4893
|
const candidates = /* @__PURE__ */ new Set();
|
|
4818
4894
|
const prefix = `${normalizedFolder}/`;
|
|
4819
4895
|
for (const entry of manifest.publicEntries) {
|
|
4896
|
+
if (language !== void 0 && entry.publicLocation.language !== language) {
|
|
4897
|
+
continue;
|
|
4898
|
+
}
|
|
4820
4899
|
if (!entry.slug.startsWith(prefix)) continue;
|
|
4821
4900
|
const remainder = entry.slug.slice(prefix.length).split("/").filter(Boolean);
|
|
4822
4901
|
const pathname = parentPath(
|
|
@@ -5031,7 +5110,7 @@ function clampFinite(value, min, max) {
|
|
|
5031
5110
|
// src/content/read_only_content_graph.ts
|
|
5032
5111
|
async function readOnlyContentGraph(source, locations) {
|
|
5033
5112
|
const entries = await source.scan();
|
|
5034
|
-
const contentIndex = await new ContentIndexBuilder(source).build(entries);
|
|
5113
|
+
const { index: contentIndex, ambiguities: contentIndexAmbiguities } = await new ContentIndexBuilder(source).build(entries);
|
|
5035
5114
|
const markdownEntries = entries.filter((entry) => entry.path.endsWith(".md")).toSorted((left, right) => left.path.localeCompare(right.path));
|
|
5036
5115
|
const markdownContents = await Promise.all(
|
|
5037
5116
|
markdownEntries.map(async (entry) => ({
|
|
@@ -5042,7 +5121,11 @@ async function readOnlyContentGraph(source, locations) {
|
|
|
5042
5121
|
const graphEntries = markdownContents.map(
|
|
5043
5122
|
({ entry, markdown }) => createGraphEntry(entry, markdown, contentIndex, locations)
|
|
5044
5123
|
);
|
|
5045
|
-
return new ManifestBuilder().build(
|
|
5124
|
+
return new ManifestBuilder().build(
|
|
5125
|
+
graphEntries,
|
|
5126
|
+
contentIndex,
|
|
5127
|
+
contentIndexAmbiguities
|
|
5128
|
+
).graph;
|
|
5046
5129
|
}
|
|
5047
5130
|
function createGraphEntry(entry, markdown, contentIndex, locations) {
|
|
5048
5131
|
const slug = entry.path.replace(/\.md$/, "");
|
|
@@ -5076,7 +5159,26 @@ async function readText3(source, entry) {
|
|
|
5076
5159
|
return typeof content === "string" ? content : new TextDecoder().decode(content);
|
|
5077
5160
|
}
|
|
5078
5161
|
|
|
5162
|
+
// src/project/project_layout.ts
|
|
5163
|
+
import path5 from "node:path";
|
|
5164
|
+
function resolveManagedStateRoot(config) {
|
|
5165
|
+
const directory = config?.buildDirectory;
|
|
5166
|
+
return directory ? path5.resolve(directory) : void 0;
|
|
5167
|
+
}
|
|
5168
|
+
function resolveBuildOutputDirectory(config) {
|
|
5169
|
+
const directory = config?.outputDirectory;
|
|
5170
|
+
return directory ? path5.resolve(directory) : void 0;
|
|
5171
|
+
}
|
|
5172
|
+
|
|
5079
5173
|
// src/types/content_manifest.ts
|
|
5174
|
+
var ARTICLE_SLOT = {
|
|
5175
|
+
header: "article.header",
|
|
5176
|
+
metadata: "article.metadata",
|
|
5177
|
+
aside: "article.aside",
|
|
5178
|
+
beforeContent: "article.before-content",
|
|
5179
|
+
afterContent: "article.after-content",
|
|
5180
|
+
footer: "article.footer"
|
|
5181
|
+
};
|
|
5080
5182
|
function appendContentBodySlot(entry, slot, html) {
|
|
5081
5183
|
if (!html.trim()) return;
|
|
5082
5184
|
const previous = entry.bodySlots?.[slot];
|
|
@@ -5088,12 +5190,12 @@ ${html}` : html
|
|
|
5088
5190
|
}
|
|
5089
5191
|
|
|
5090
5192
|
// src/types/plugin_endpoint.ts
|
|
5091
|
-
function defineEndpoint(
|
|
5193
|
+
function defineEndpoint(path6, handler, options = {}) {
|
|
5092
5194
|
if (options.cacheControl === void 0) {
|
|
5093
|
-
return { path:
|
|
5195
|
+
return { path: path6, handler };
|
|
5094
5196
|
}
|
|
5095
5197
|
return {
|
|
5096
|
-
path:
|
|
5198
|
+
path: path6,
|
|
5097
5199
|
handler: async (context) => {
|
|
5098
5200
|
const response = await handler(context);
|
|
5099
5201
|
const headers = { ...response.headers };
|
|
@@ -5128,6 +5230,7 @@ function calculateReadingTime(html) {
|
|
|
5128
5230
|
return Math.max(1, Math.ceil(cjkCharacters / 500 + latinWords / 220));
|
|
5129
5231
|
}
|
|
5130
5232
|
export {
|
|
5233
|
+
ARTICLE_SLOT,
|
|
5131
5234
|
ATTACHMENTS_BASE_PATH,
|
|
5132
5235
|
CompositeTraceSink,
|
|
5133
5236
|
ConfigValidationError,
|
|
@@ -5142,6 +5245,7 @@ export {
|
|
|
5142
5245
|
PluginDependencyError,
|
|
5143
5246
|
SinkTracer,
|
|
5144
5247
|
appendContentBodySlot,
|
|
5248
|
+
attachErrorPath,
|
|
5145
5249
|
attachmentUrl,
|
|
5146
5250
|
buildContentCollections,
|
|
5147
5251
|
buildGraphEdges,
|
|
@@ -5193,6 +5297,7 @@ export {
|
|
|
5193
5297
|
readContentBuildStateStatus,
|
|
5194
5298
|
readContentSourceEntry,
|
|
5195
5299
|
readOnlyContentGraph,
|
|
5300
|
+
resolveBuildOutputDirectory,
|
|
5196
5301
|
resolveConfig,
|
|
5197
5302
|
resolveConfigModule,
|
|
5198
5303
|
resolveContentBuildStatePath,
|
|
@@ -5202,6 +5307,7 @@ export {
|
|
|
5202
5307
|
resolveFolderEntry,
|
|
5203
5308
|
resolveFolderLocation,
|
|
5204
5309
|
resolveGeneratedFolderLocation,
|
|
5310
|
+
resolveManagedStateRoot,
|
|
5205
5311
|
resolvePlugins,
|
|
5206
5312
|
resolvePublicFolderLocation,
|
|
5207
5313
|
resolvePublishingBuildTime,
|