scribe-cms 0.0.8 → 0.0.9
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/dist/cli/index.cjs +432 -384
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +432 -384
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +642 -512
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +642 -513
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs +287 -261
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +286 -261
- package/dist/runtime.js.map +1 -1
- package/dist/src/config/resolve-config.d.ts.map +1 -1
- package/dist/src/core/builtin-fields.d.ts +8 -8
- package/dist/src/core/builtin-fields.d.ts.map +1 -1
- package/dist/src/core/types.d.ts +11 -4
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/create-project.d.ts.map +1 -1
- package/dist/src/export/build-static-raw-exports.d.ts.map +1 -1
- package/dist/src/i18n/build-url.d.ts +16 -3
- package/dist/src/i18n/build-url.d.ts.map +1 -1
- package/dist/src/i18n/resolve-document.d.ts +3 -2
- package/dist/src/i18n/resolve-document.d.ts.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/loader/create-loader.d.ts.map +1 -1
- package/dist/src/redirects/build-json-redirects.d.ts +6 -0
- package/dist/src/redirects/build-json-redirects.d.ts.map +1 -0
- package/dist/src/redirects/build-redirects.d.ts +9 -7
- package/dist/src/redirects/build-redirects.d.ts.map +1 -1
- package/dist/src/redirects/load-type-redirects.d.ts +14 -0
- package/dist/src/redirects/load-type-redirects.d.ts.map +1 -0
- package/dist/src/redirects/redirect-schema.d.ts +31 -0
- package/dist/src/redirects/redirect-schema.d.ts.map +1 -0
- package/dist/src/runtime.d.ts +3 -1
- package/dist/src/runtime.d.ts.map +1 -1
- package/dist/src/sitemap/generate-sitemap.d.ts.map +1 -1
- package/dist/src/validate/validate-project.d.ts.map +1 -1
- package/dist/src/validate/validate-redirects.d.ts +4 -0
- package/dist/src/validate/validate-redirects.d.ts.map +1 -0
- package/dist/studio/server.cjs +90 -61
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.js +90 -61
- package/dist/studio/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/core/slug-aliases.d.ts +0 -27
- package/dist/src/core/slug-aliases.d.ts.map +0 -1
- package/dist/src/redirects/translation-index.d.ts +0 -4
- package/dist/src/redirects/translation-index.d.ts.map +0 -1
package/dist/runtime.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var path = require('path');
|
|
4
4
|
var zod = require('zod');
|
|
5
5
|
var fs2 = require('fs');
|
|
6
6
|
var matter = require('gray-matter');
|
|
@@ -8,7 +8,7 @@ var Database = require('better-sqlite3');
|
|
|
8
8
|
|
|
9
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
12
12
|
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
13
13
|
var matter__default = /*#__PURE__*/_interopDefault(matter);
|
|
14
14
|
var Database__default = /*#__PURE__*/_interopDefault(Database);
|
|
@@ -20,14 +20,14 @@ var SLUG_PLACEHOLDER = "{slug}";
|
|
|
20
20
|
function isRoutableType(type) {
|
|
21
21
|
return typeof type.path === "string" && type.path.length > 0;
|
|
22
22
|
}
|
|
23
|
-
function assertValidPathTemplate(
|
|
24
|
-
if (!
|
|
25
|
-
throw new Error(`Content type "${typeId}": path must start with / (got "${
|
|
23
|
+
function assertValidPathTemplate(path6, typeId) {
|
|
24
|
+
if (!path6.startsWith("/")) {
|
|
25
|
+
throw new Error(`Content type "${typeId}": path must start with / (got "${path6}")`);
|
|
26
26
|
}
|
|
27
|
-
const count = (
|
|
27
|
+
const count = (path6.match(/\{slug\}/g) ?? []).length;
|
|
28
28
|
if (count !== 1) {
|
|
29
29
|
throw new Error(
|
|
30
|
-
`Content type "${typeId}": path must contain exactly one {slug} (got "${
|
|
30
|
+
`Content type "${typeId}": path must contain exactly one {slug} (got "${path6}")`
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -41,19 +41,69 @@ function pathSuffix(template) {
|
|
|
41
41
|
if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);
|
|
42
42
|
return template.slice(idx + SLUG_PLACEHOLDER.length);
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
if (locale === defaultLocale) return relative;
|
|
47
|
-
return `/${locale}${relative}`;
|
|
44
|
+
function resolveDefaultLocaleRouting() {
|
|
45
|
+
return { strategy: "path-prefix", prefixDefaultLocale: false };
|
|
48
46
|
}
|
|
49
|
-
function
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
47
|
+
function splitPathAndSearch(pathname) {
|
|
48
|
+
const q = pathname.indexOf("?");
|
|
49
|
+
if (q === -1) return { pathname, search: "" };
|
|
50
|
+
return { pathname: pathname.slice(0, q), search: pathname.slice(q) };
|
|
51
|
+
}
|
|
52
|
+
function createUrlBuilder(config) {
|
|
53
|
+
const localeRouting = config.localeRouting ?? resolveDefaultLocaleRouting();
|
|
54
|
+
const defaultLocale = config.defaultLocale;
|
|
55
|
+
const prefixedLocales = localeRouting.strategy === "path-prefix" ? localeRouting.prefixDefaultLocale ? [...config.locales] : config.locales.filter((locale) => locale !== defaultLocale) : config.locales.filter((locale) => locale !== defaultLocale);
|
|
56
|
+
function applyLocaleToPath(pathname, locale) {
|
|
57
|
+
if (locale === defaultLocale) {
|
|
58
|
+
if (localeRouting.strategy === "path-prefix" && localeRouting.prefixDefaultLocale) {
|
|
59
|
+
return `/${defaultLocale}${pathname}`;
|
|
60
|
+
}
|
|
61
|
+
return pathname;
|
|
62
|
+
}
|
|
63
|
+
if (localeRouting.strategy === "search-param") {
|
|
64
|
+
const { pathname: base, search } = splitPathAndSearch(pathname);
|
|
65
|
+
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
66
|
+
params.set(localeRouting.param, locale);
|
|
67
|
+
const qs = params.toString();
|
|
68
|
+
return qs ? `${base}?${qs}` : base;
|
|
69
|
+
}
|
|
70
|
+
return `/${locale}${pathname}`;
|
|
71
|
+
}
|
|
72
|
+
function resolvePath(template, slug, locale) {
|
|
73
|
+
const relative = template.replace(SLUG_PLACEHOLDER, slug);
|
|
74
|
+
return applyLocaleToPath(relative, locale);
|
|
75
|
+
}
|
|
76
|
+
function extractSlugFromResolvedPath(template, resolvedPath) {
|
|
77
|
+
let pathname = resolvedPath;
|
|
78
|
+
if (localeRouting.strategy === "search-param") {
|
|
79
|
+
pathname = splitPathAndSearch(resolvedPath).pathname;
|
|
80
|
+
} else if (localeRouting.strategy === "path-prefix") {
|
|
81
|
+
for (const locale of config.locales) {
|
|
82
|
+
if (locale === defaultLocale && !localeRouting.prefixDefaultLocale) continue;
|
|
83
|
+
const prefix2 = `/${locale}`;
|
|
84
|
+
if (pathname === prefix2 || pathname.startsWith(`${prefix2}/`)) {
|
|
85
|
+
pathname = pathname.slice(prefix2.length) || "/";
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const prefix = pathPrefix(template);
|
|
91
|
+
const suffix = pathSuffix(template);
|
|
92
|
+
if (!pathname.startsWith(prefix)) return null;
|
|
93
|
+
if (suffix && !pathname.endsWith(suffix)) return null;
|
|
94
|
+
const slugEnd = suffix ? pathname.length - suffix.length : pathname.length;
|
|
95
|
+
const slug = pathname.slice(prefix.length, slugEnd);
|
|
96
|
+
return slug.length > 0 ? slug : null;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
defaultLocale,
|
|
100
|
+
locales: config.locales,
|
|
101
|
+
localeRouting,
|
|
102
|
+
prefixedLocales,
|
|
103
|
+
resolvePath,
|
|
104
|
+
extractSlugFromResolvedPath,
|
|
105
|
+
applyLocaleToPath
|
|
106
|
+
};
|
|
57
107
|
}
|
|
58
108
|
|
|
59
109
|
// src/config/resolve-config.ts
|
|
@@ -76,10 +126,17 @@ function resolveConfig(input, baseDir) {
|
|
|
76
126
|
`scribe config: defaultLocale "${defaultLocale}" is not in locales [${raw.locales.join(", ")}]`
|
|
77
127
|
);
|
|
78
128
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
129
|
+
const localeRouting = raw.localeRouting ?? {
|
|
130
|
+
strategy: "path-prefix",
|
|
131
|
+
prefixDefaultLocale: false
|
|
132
|
+
};
|
|
133
|
+
if (localeRouting.strategy === "search-param" && !localeRouting.param) {
|
|
134
|
+
throw new Error('scribe config: localeRouting search-param requires a "param" name');
|
|
135
|
+
}
|
|
136
|
+
const projectRoot = path__default.default.resolve(process.cwd(), raw.rootDir);
|
|
137
|
+
const contentRoot = path__default.default.resolve(projectRoot, raw.contentDir ?? "content");
|
|
138
|
+
const storePath = path__default.default.resolve(projectRoot, raw.store ?? ".scribe/store.sqlite");
|
|
139
|
+
const assetsPath = raw.assetsDir ? path__default.default.resolve(projectRoot, raw.assetsDir) : void 0;
|
|
83
140
|
const seenIds = /* @__PURE__ */ new Set();
|
|
84
141
|
const types = raw.types.map((type) => {
|
|
85
142
|
if (seenIds.has(type.id)) {
|
|
@@ -103,6 +160,7 @@ function resolveConfig(input, baseDir) {
|
|
|
103
160
|
assetsPath,
|
|
104
161
|
locales: [...raw.locales],
|
|
105
162
|
defaultLocale,
|
|
163
|
+
localeRouting,
|
|
106
164
|
localePresets: raw.localePresets,
|
|
107
165
|
translate: raw.translate,
|
|
108
166
|
types
|
|
@@ -202,10 +260,10 @@ function introspectSchema(schema, prefix = []) {
|
|
|
202
260
|
}
|
|
203
261
|
function extractByPaths(data, paths) {
|
|
204
262
|
const out = {};
|
|
205
|
-
for (const
|
|
206
|
-
const value = getAtPath(data,
|
|
263
|
+
for (const path6 of paths) {
|
|
264
|
+
const value = getAtPath(data, path6);
|
|
207
265
|
if (value !== void 0) {
|
|
208
|
-
setAtPath(out,
|
|
266
|
+
setAtPath(out, path6.filter((p) => p !== "*"), value);
|
|
209
267
|
}
|
|
210
268
|
}
|
|
211
269
|
return out;
|
|
@@ -223,13 +281,13 @@ function mergeStructuralOntoLocale(localeData, enData, schema) {
|
|
|
223
281
|
const translatable = pickTranslatable(localeData, schema);
|
|
224
282
|
return deepMerge(structural, translatable);
|
|
225
283
|
}
|
|
226
|
-
function getAtPath(obj,
|
|
284
|
+
function getAtPath(obj, path6) {
|
|
227
285
|
let current = obj;
|
|
228
|
-
for (const segment of
|
|
286
|
+
for (const segment of path6) {
|
|
229
287
|
if (segment === "*") {
|
|
230
288
|
if (!Array.isArray(current)) return void 0;
|
|
231
289
|
return current.map(
|
|
232
|
-
(item) => typeof item === "object" && item !== null ? getAtPath(item,
|
|
290
|
+
(item) => typeof item === "object" && item !== null ? getAtPath(item, path6.slice(path6.indexOf("*") + 1)) : void 0
|
|
233
291
|
);
|
|
234
292
|
}
|
|
235
293
|
if (typeof current !== "object" || current === null || Array.isArray(current)) return void 0;
|
|
@@ -237,13 +295,13 @@ function getAtPath(obj, path5) {
|
|
|
237
295
|
}
|
|
238
296
|
return current;
|
|
239
297
|
}
|
|
240
|
-
function setAtPath(obj,
|
|
241
|
-
if (
|
|
242
|
-
if (
|
|
243
|
-
obj[
|
|
298
|
+
function setAtPath(obj, path6, value) {
|
|
299
|
+
if (path6.length === 0) return;
|
|
300
|
+
if (path6.length === 1) {
|
|
301
|
+
obj[path6[0]] = value;
|
|
244
302
|
return;
|
|
245
303
|
}
|
|
246
|
-
const [head, ...rest] =
|
|
304
|
+
const [head, ...rest] = path6;
|
|
247
305
|
if (!(head in obj) || typeof obj[head] !== "object" || obj[head] === null) {
|
|
248
306
|
obj[head] = {};
|
|
249
307
|
}
|
|
@@ -278,45 +336,23 @@ var SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
|
278
336
|
var slugPatternSchema = zod.z.string().regex(SLUG_PATTERN, "slug must be lowercase-kebab-case");
|
|
279
337
|
var isoDateSchema = zod.z.string().regex(/^\d{4}-\d{2}-\d{2}(T[\d:.Z+-]*)?$/, "Use ISO date YYYY-MM-DD or full ISO 8601");
|
|
280
338
|
var canonicalPathSchema = zod.z.string().regex(/^\//, "canonicalPath must start with /");
|
|
281
|
-
|
|
339
|
+
var DEPRECATED_REDIRECT_FIELDS = [
|
|
340
|
+
[
|
|
341
|
+
"aliases",
|
|
342
|
+
"aliases frontmatter is removed \u2014 add redirects to content/<type>/_redirects.json instead"
|
|
343
|
+
],
|
|
344
|
+
[
|
|
345
|
+
"redirect_to",
|
|
346
|
+
"redirect_to frontmatter is removed \u2014 add redirects to content/<type>/_redirects.json instead"
|
|
347
|
+
]
|
|
348
|
+
];
|
|
349
|
+
function extractBuiltinEnFields(data, _pathTemplate, _enSlug, _defaultLocale) {
|
|
282
350
|
const issues = [];
|
|
283
351
|
const rest = { ...data };
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
let redirectTo;
|
|
289
|
-
if (redirectRaw !== void 0 && redirectRaw !== null && redirectRaw !== "") {
|
|
290
|
-
if (typeof redirectRaw !== "string") {
|
|
291
|
-
issues.push({
|
|
292
|
-
field: "redirect_to",
|
|
293
|
-
message: "redirect_to must be a string path",
|
|
294
|
-
level: "error"
|
|
295
|
-
});
|
|
296
|
-
} else if (!pathTemplate) {
|
|
297
|
-
issues.push({
|
|
298
|
-
field: "redirect_to",
|
|
299
|
-
message: "redirect_to is not allowed on reference-only content types",
|
|
300
|
-
level: "error"
|
|
301
|
-
});
|
|
302
|
-
} else if (!extractSlugFromResolvedPath(pathTemplate, redirectRaw)) {
|
|
303
|
-
issues.push({
|
|
304
|
-
field: "redirect_to",
|
|
305
|
-
message: `redirect_to must match path template "${pathTemplate}" (prefix "${pathPrefix(pathTemplate)}"${pathSuffix(pathTemplate) ? `, suffix "${pathSuffix(pathTemplate)}"` : ""})`,
|
|
306
|
-
level: "error"
|
|
307
|
-
});
|
|
308
|
-
} else {
|
|
309
|
-
redirectTo = redirectRaw;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
const aliases = aliasesResult.success ? aliasesResult.data : [];
|
|
313
|
-
if (!aliasesResult.success) {
|
|
314
|
-
for (const issue of aliasesResult.error.issues) {
|
|
315
|
-
issues.push({
|
|
316
|
-
field: `aliases.${issue.path.join(".")}`,
|
|
317
|
-
message: issue.message,
|
|
318
|
-
level: "error"
|
|
319
|
-
});
|
|
352
|
+
for (const [field, message] of DEPRECATED_REDIRECT_FIELDS) {
|
|
353
|
+
if (rest[field] !== void 0) {
|
|
354
|
+
issues.push({ field, message, level: "error" });
|
|
355
|
+
delete rest[field];
|
|
320
356
|
}
|
|
321
357
|
}
|
|
322
358
|
let publishedAt;
|
|
@@ -378,8 +414,6 @@ function extractBuiltinEnFields(data, pathTemplate, enSlug, defaultLocale) {
|
|
|
378
414
|
}
|
|
379
415
|
return {
|
|
380
416
|
builtin: {
|
|
381
|
-
aliases,
|
|
382
|
-
redirectTo,
|
|
383
417
|
publishedAt,
|
|
384
418
|
updatedAt,
|
|
385
419
|
noindex,
|
|
@@ -395,20 +429,24 @@ function documentLastModified(doc) {
|
|
|
395
429
|
const date = new Date(raw);
|
|
396
430
|
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
397
431
|
}
|
|
398
|
-
function resolveCanonicalPathname(type, doc, defaultLocale) {
|
|
432
|
+
function resolveCanonicalPathname(type, doc, defaultLocale, localeRouting) {
|
|
433
|
+
const urlBuilder = createUrlBuilder({
|
|
434
|
+
locales: [defaultLocale, ...doc.locale !== defaultLocale ? [doc.locale] : []],
|
|
435
|
+
defaultLocale,
|
|
436
|
+
localeRouting: localeRouting ?? { strategy: "path-prefix", prefixDefaultLocale: false }
|
|
437
|
+
});
|
|
399
438
|
if (doc.canonicalPathOverride) {
|
|
400
|
-
|
|
401
|
-
return `/${doc.locale}${doc.canonicalPathOverride}`;
|
|
439
|
+
return urlBuilder.applyLocaleToPath(doc.canonicalPathOverride, doc.locale);
|
|
402
440
|
}
|
|
403
441
|
if (!type.path) return `/${doc.slug}`;
|
|
404
|
-
return resolvePath(type.path, doc.slug, doc.locale
|
|
442
|
+
return urlBuilder.resolvePath(type.path, doc.slug, doc.locale);
|
|
405
443
|
}
|
|
406
|
-
function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale) {
|
|
444
|
+
function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale, localeRouting) {
|
|
407
445
|
const out = { ...frontmatter };
|
|
408
446
|
if (doc.publishedAt !== void 0) out.publishedAt = doc.publishedAt;
|
|
409
447
|
if (doc.updatedAt !== void 0) out.updatedAt = doc.updatedAt;
|
|
410
448
|
out.noindex = doc.noindex;
|
|
411
|
-
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale);
|
|
449
|
+
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale, localeRouting);
|
|
412
450
|
return out;
|
|
413
451
|
}
|
|
414
452
|
function seoFieldsFromEn(enDoc) {
|
|
@@ -416,8 +454,7 @@ function seoFieldsFromEn(enDoc) {
|
|
|
416
454
|
publishedAt: enDoc.publishedAt,
|
|
417
455
|
updatedAt: enDoc.updatedAt,
|
|
418
456
|
noindex: enDoc.noindex,
|
|
419
|
-
canonicalPathOverride: enDoc.canonicalPathOverride
|
|
420
|
-
redirectTo: enDoc.redirectTo
|
|
457
|
+
canonicalPathOverride: enDoc.canonicalPathOverride
|
|
421
458
|
};
|
|
422
459
|
}
|
|
423
460
|
var SCHEMA_VERSION = 4;
|
|
@@ -476,7 +513,7 @@ function resolveStorePath(config) {
|
|
|
476
513
|
function openStore(config, mode = "readwrite") {
|
|
477
514
|
const storePath = resolveStorePath(config);
|
|
478
515
|
if (mode === "readwrite") {
|
|
479
|
-
fs2__default.default.mkdirSync(
|
|
516
|
+
fs2__default.default.mkdirSync(path__default.default.dirname(storePath), { recursive: true });
|
|
480
517
|
}
|
|
481
518
|
const db = new Database__default.default(storePath, { readonly: mode === "readonly" });
|
|
482
519
|
if (mode === "readwrite") {
|
|
@@ -540,10 +577,10 @@ function isPostFile(name) {
|
|
|
540
577
|
}
|
|
541
578
|
function listEnFiles(contentDir) {
|
|
542
579
|
if (!fs2__default.default.existsSync(contentDir)) return [];
|
|
543
|
-
return fs2__default.default.readdirSync(contentDir).filter(isPostFile).map((f) =>
|
|
580
|
+
return fs2__default.default.readdirSync(contentDir).filter(isPostFile).map((f) => path__default.default.join(contentDir, f));
|
|
544
581
|
}
|
|
545
582
|
function slugFromPath(filePath) {
|
|
546
|
-
return
|
|
583
|
+
return path__default.default.basename(filePath).replace(/\.(md|mdx)$/, "");
|
|
547
584
|
}
|
|
548
585
|
function parseEnMdx(filePath, config, type) {
|
|
549
586
|
const raw = fs2__default.default.readFileSync(filePath, "utf8");
|
|
@@ -589,7 +626,8 @@ function parseEnMdx(filePath, config, type) {
|
|
|
589
626
|
locale: config.defaultLocale
|
|
590
627
|
},
|
|
591
628
|
type,
|
|
592
|
-
config.defaultLocale
|
|
629
|
+
config.defaultLocale,
|
|
630
|
+
config.localeRouting
|
|
593
631
|
);
|
|
594
632
|
const crossIssues = type.crossValidate?.(result.data, {
|
|
595
633
|
locale: config.defaultLocale,
|
|
@@ -603,8 +641,6 @@ function parseEnMdx(filePath, config, type) {
|
|
|
603
641
|
slug,
|
|
604
642
|
enSlug: slug,
|
|
605
643
|
locale: config.defaultLocale,
|
|
606
|
-
aliases: builtin.aliases,
|
|
607
|
-
redirectTo: builtin.redirectTo,
|
|
608
644
|
publishedAt: builtin.publishedAt,
|
|
609
645
|
updatedAt: builtin.updatedAt,
|
|
610
646
|
noindex: builtin.noindex,
|
|
@@ -615,7 +651,7 @@ function parseEnMdx(filePath, config, type) {
|
|
|
615
651
|
};
|
|
616
652
|
return { document, issues };
|
|
617
653
|
}
|
|
618
|
-
function buildDocumentFromTranslation(row, enDoc, type) {
|
|
654
|
+
function buildDocumentFromTranslation(row, enDoc, type, config) {
|
|
619
655
|
const localeFm = JSON.parse(row.frontmatter_json);
|
|
620
656
|
const merged = mergeStructuralOntoLocale(localeFm, enDoc.frontmatter, type.schema);
|
|
621
657
|
const seo = seoFieldsFromEn(enDoc);
|
|
@@ -623,14 +659,13 @@ function buildDocumentFromTranslation(row, enDoc, type) {
|
|
|
623
659
|
merged,
|
|
624
660
|
{ ...seo, slug: row.slug, locale: row.locale },
|
|
625
661
|
type,
|
|
626
|
-
|
|
662
|
+
config.defaultLocale,
|
|
663
|
+
config.localeRouting
|
|
627
664
|
);
|
|
628
665
|
return {
|
|
629
666
|
slug: row.slug,
|
|
630
667
|
enSlug: row.en_slug,
|
|
631
668
|
locale: row.locale,
|
|
632
|
-
aliases: [],
|
|
633
|
-
redirectTo: seo.redirectTo,
|
|
634
669
|
publishedAt: seo.publishedAt,
|
|
635
670
|
updatedAt: seo.updatedAt,
|
|
636
671
|
noindex: seo.noindex,
|
|
@@ -644,7 +679,7 @@ function createContentLoader(config, type) {
|
|
|
644
679
|
let cached = null;
|
|
645
680
|
let signature = "";
|
|
646
681
|
let lastCheck = 0;
|
|
647
|
-
const contentDir =
|
|
682
|
+
const contentDir = path__default.default.join(
|
|
648
683
|
/* turbopackIgnore: true */
|
|
649
684
|
config.rootDir,
|
|
650
685
|
type.contentDir
|
|
@@ -708,7 +743,7 @@ function createContentLoader(config, type) {
|
|
|
708
743
|
for (const row of rowsByLocale.get(locale) ?? []) {
|
|
709
744
|
const enDoc = englishBySlug.get(row.en_slug);
|
|
710
745
|
if (!enDoc) continue;
|
|
711
|
-
const doc = buildDocumentFromTranslation(row, enDoc, type);
|
|
746
|
+
const doc = buildDocumentFromTranslation(row, enDoc, type, config);
|
|
712
747
|
bySlug.set(doc.slug, doc);
|
|
713
748
|
byEnSlug.set(row.en_slug, doc);
|
|
714
749
|
}
|
|
@@ -734,72 +769,18 @@ function createContentLoader(config, type) {
|
|
|
734
769
|
return cached;
|
|
735
770
|
};
|
|
736
771
|
}
|
|
737
|
-
function readEnDocument(config, type, enSlug) {
|
|
738
|
-
const contentDir = path3__default.default.join(
|
|
739
|
-
/* turbopackIgnore: true */
|
|
740
|
-
config.rootDir,
|
|
741
|
-
type.contentDir
|
|
742
|
-
);
|
|
743
|
-
for (const ext of [".mdx", ".md"]) {
|
|
744
|
-
const filePath = path3__default.default.join(contentDir, `${enSlug}${ext}`);
|
|
745
|
-
if (!fs2__default.default.existsSync(filePath)) continue;
|
|
746
|
-
const { document } = parseEnMdx(filePath, config, type);
|
|
747
|
-
return document;
|
|
748
|
-
}
|
|
749
|
-
return null;
|
|
750
|
-
}
|
|
751
772
|
|
|
752
773
|
// src/i18n/resolve-document.ts
|
|
753
|
-
function
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
return null;
|
|
760
|
-
}
|
|
761
|
-
function enCanonicalDoc(doc, allDocs, defaultLocale) {
|
|
762
|
-
if (doc.locale === defaultLocale) return doc;
|
|
763
|
-
return allDocs.get(defaultLocale)?.bySlug.get(doc.enSlug) ?? doc;
|
|
764
|
-
}
|
|
765
|
-
function redirectPathForDocument(doc, locale, defaultLocale, allDocs, type) {
|
|
766
|
-
if (!type.path) return void 0;
|
|
767
|
-
const enDoc = enCanonicalDoc(doc, allDocs, defaultLocale);
|
|
768
|
-
if (!enDoc.redirectTo) return void 0;
|
|
769
|
-
const targetEnSlug = extractSlugFromResolvedPath(type.path, enDoc.redirectTo);
|
|
770
|
-
if (!targetEnSlug) return void 0;
|
|
771
|
-
const targetEnDoc = allDocs.get(defaultLocale)?.bySlug.get(targetEnSlug);
|
|
772
|
-
const targetSlug = targetEnDoc ? getSlugForLocale(targetEnDoc, defaultLocale, locale, allDocs, defaultLocale) ?? targetEnSlug : targetEnSlug;
|
|
773
|
-
return resolvePath(type.path, targetSlug, locale, defaultLocale);
|
|
774
|
-
}
|
|
775
|
-
function withRedirectTo(result, locale, defaultLocale, allDocs, type) {
|
|
776
|
-
if (result.shouldRedirectTo || !result.document) return result;
|
|
777
|
-
const redirect = redirectPathForDocument(result.document, locale, defaultLocale, allDocs, type);
|
|
778
|
-
if (!redirect) return result;
|
|
779
|
-
return {
|
|
780
|
-
document: null,
|
|
781
|
-
actualLocale: result.actualLocale,
|
|
782
|
-
shouldRedirectTo: redirect
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
|
-
function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type) {
|
|
774
|
+
function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type, localeRouting) {
|
|
775
|
+
const urlBuilder = createUrlBuilder({
|
|
776
|
+
locales: [defaultLocale, locale],
|
|
777
|
+
defaultLocale,
|
|
778
|
+
localeRouting: localeRouting ?? { strategy: "path-prefix", prefixDefaultLocale: false }
|
|
779
|
+
});
|
|
786
780
|
const idx = allDocs.get(locale);
|
|
787
781
|
const direct = idx?.bySlug.get(slug);
|
|
788
782
|
if (direct) {
|
|
789
|
-
return
|
|
790
|
-
}
|
|
791
|
-
const aliasDoc = findEnDocByAlias(slug, allDocs, defaultLocale);
|
|
792
|
-
if (aliasDoc && type.path) {
|
|
793
|
-
const canonicalSlug = aliasDoc.slug;
|
|
794
|
-
const localizedSlug = getSlugForLocale(aliasDoc, defaultLocale, locale, allDocs, defaultLocale);
|
|
795
|
-
const targetSlug = localizedSlug ?? canonicalSlug;
|
|
796
|
-
if (targetSlug !== slug) {
|
|
797
|
-
return {
|
|
798
|
-
document: null,
|
|
799
|
-
actualLocale: locale,
|
|
800
|
-
shouldRedirectTo: resolvePath(type.path, targetSlug, locale, defaultLocale)
|
|
801
|
-
};
|
|
802
|
-
}
|
|
783
|
+
return { document: direct, actualLocale: locale };
|
|
803
784
|
}
|
|
804
785
|
for (const [docLocale, docIdx] of allDocs) {
|
|
805
786
|
const found = docIdx.bySlug.get(slug);
|
|
@@ -812,17 +793,11 @@ function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type) {
|
|
|
812
793
|
return {
|
|
813
794
|
document: null,
|
|
814
795
|
actualLocale: locale,
|
|
815
|
-
shouldRedirectTo: resolvePath(type.path, correctSlug, locale
|
|
796
|
+
shouldRedirectTo: urlBuilder.resolvePath(type.path, correctSlug, locale)
|
|
816
797
|
};
|
|
817
798
|
}
|
|
818
799
|
if (docLocale === defaultLocale) {
|
|
819
|
-
return
|
|
820
|
-
{ document: found, actualLocale: defaultLocale },
|
|
821
|
-
locale,
|
|
822
|
-
defaultLocale,
|
|
823
|
-
allDocs,
|
|
824
|
-
type
|
|
825
|
-
);
|
|
800
|
+
return { document: found, actualLocale: defaultLocale };
|
|
826
801
|
}
|
|
827
802
|
if (!type.path) {
|
|
828
803
|
return { document: null, actualLocale: locale };
|
|
@@ -830,39 +805,21 @@ function resolveLocalizedDocument(slug, locale, defaultLocale, allDocs, type) {
|
|
|
830
805
|
return {
|
|
831
806
|
document: null,
|
|
832
807
|
actualLocale: locale,
|
|
833
|
-
shouldRedirectTo: resolvePath(type.path, found.enSlug, locale
|
|
808
|
+
shouldRedirectTo: urlBuilder.resolvePath(type.path, found.enSlug, locale)
|
|
834
809
|
};
|
|
835
810
|
}
|
|
836
811
|
if (locale !== defaultLocale) {
|
|
837
812
|
const enDoc = allDocs.get(defaultLocale)?.bySlug.get(slug);
|
|
838
813
|
if (enDoc && type.indexFallback === "en") {
|
|
839
|
-
return
|
|
840
|
-
{ document: enDoc, actualLocale: defaultLocale },
|
|
841
|
-
locale,
|
|
842
|
-
defaultLocale,
|
|
843
|
-
allDocs,
|
|
844
|
-
type
|
|
845
|
-
);
|
|
814
|
+
return { document: enDoc, actualLocale: defaultLocale };
|
|
846
815
|
}
|
|
847
816
|
const byEn = idx?.byEnSlug.get(slug);
|
|
848
817
|
if (byEn) {
|
|
849
|
-
return
|
|
850
|
-
{ document: byEn, actualLocale: locale },
|
|
851
|
-
locale,
|
|
852
|
-
defaultLocale,
|
|
853
|
-
allDocs,
|
|
854
|
-
type
|
|
855
|
-
);
|
|
818
|
+
return { document: byEn, actualLocale: locale };
|
|
856
819
|
}
|
|
857
820
|
const fallback = allDocs.get(defaultLocale)?.bySlug.get(slug);
|
|
858
821
|
if (fallback && type.indexFallback === "en") {
|
|
859
|
-
return
|
|
860
|
-
{ document: fallback, actualLocale: defaultLocale },
|
|
861
|
-
locale,
|
|
862
|
-
defaultLocale,
|
|
863
|
-
allDocs,
|
|
864
|
-
type
|
|
865
|
-
);
|
|
822
|
+
return { document: fallback, actualLocale: defaultLocale };
|
|
866
823
|
}
|
|
867
824
|
}
|
|
868
825
|
return { document: null, actualLocale: locale };
|
|
@@ -904,6 +861,7 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
904
861
|
}
|
|
905
862
|
return type.path;
|
|
906
863
|
}
|
|
864
|
+
const urlBuilder = createUrlBuilder(config);
|
|
907
865
|
const runtime = {
|
|
908
866
|
id: type.id,
|
|
909
867
|
config: type,
|
|
@@ -919,15 +877,21 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
919
877
|
return load().get(locale)?.bySlug.get(slug) ?? null;
|
|
920
878
|
},
|
|
921
879
|
resolve(slug, locale) {
|
|
922
|
-
const result = resolveLocalizedDocument(
|
|
880
|
+
const result = resolveLocalizedDocument(
|
|
881
|
+
slug,
|
|
882
|
+
locale,
|
|
883
|
+
config.defaultLocale,
|
|
884
|
+
load(),
|
|
885
|
+
type,
|
|
886
|
+
config.localeRouting
|
|
887
|
+
);
|
|
923
888
|
if (result.document && type.path) {
|
|
924
889
|
return {
|
|
925
890
|
...result,
|
|
926
|
-
canonicalPath: resolvePath(
|
|
891
|
+
canonicalPath: urlBuilder.resolvePath(
|
|
927
892
|
type.path,
|
|
928
893
|
result.document.slug,
|
|
929
|
-
result.actualLocale
|
|
930
|
-
config.defaultLocale
|
|
894
|
+
result.actualLocale
|
|
931
895
|
)
|
|
932
896
|
};
|
|
933
897
|
}
|
|
@@ -951,10 +915,9 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
951
915
|
alternates(doc) {
|
|
952
916
|
const pathTemplate = assertRoutable("alternates");
|
|
953
917
|
const out = {
|
|
954
|
-
[config.defaultLocale]: resolvePath(
|
|
918
|
+
[config.defaultLocale]: urlBuilder.resolvePath(
|
|
955
919
|
pathTemplate,
|
|
956
920
|
doc.enSlug,
|
|
957
|
-
config.defaultLocale,
|
|
958
921
|
config.defaultLocale
|
|
959
922
|
)
|
|
960
923
|
};
|
|
@@ -963,7 +926,7 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
963
926
|
if (locale === config.defaultLocale) continue;
|
|
964
927
|
const translated = all.get(locale)?.byEnSlug.get(doc.enSlug);
|
|
965
928
|
if (translated) {
|
|
966
|
-
out[locale] = resolvePath(pathTemplate, translated.slug, locale
|
|
929
|
+
out[locale] = urlBuilder.resolvePath(pathTemplate, translated.slug, locale);
|
|
967
930
|
}
|
|
968
931
|
}
|
|
969
932
|
return out;
|
|
@@ -978,7 +941,7 @@ function buildRuntime(config, type, getRuntime) {
|
|
|
978
941
|
},
|
|
979
942
|
url(slug, locale) {
|
|
980
943
|
const pathTemplate = assertRoutable("url");
|
|
981
|
-
return resolvePath(pathTemplate, slug, locale
|
|
944
|
+
return urlBuilder.resolvePath(pathTemplate, slug, locale);
|
|
982
945
|
},
|
|
983
946
|
related(doc, fieldName, locale) {
|
|
984
947
|
const meta = relationFields.get(fieldName);
|
|
@@ -1040,87 +1003,150 @@ function createProject(config) {
|
|
|
1040
1003
|
}
|
|
1041
1004
|
};
|
|
1042
1005
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1006
|
+
var redirectFromSchema = zod.z.union([
|
|
1007
|
+
slugPatternSchema,
|
|
1008
|
+
zod.z.array(slugPatternSchema).min(1).max(20)
|
|
1009
|
+
]);
|
|
1010
|
+
var typeRedirectEntrySchema = zod.z.object({
|
|
1011
|
+
from: redirectFromSchema,
|
|
1012
|
+
toSlug: slugPatternSchema.optional(),
|
|
1013
|
+
toType: zod.z.string().min(1).optional(),
|
|
1014
|
+
toUrl: zod.z.string().min(1).optional(),
|
|
1015
|
+
permanent: zod.z.boolean().optional()
|
|
1016
|
+
}).superRefine((entry, ctx) => {
|
|
1017
|
+
const hasToSlug = entry.toSlug !== void 0;
|
|
1018
|
+
const hasToUrl = entry.toUrl !== void 0;
|
|
1019
|
+
const hasToType = entry.toType !== void 0;
|
|
1020
|
+
const targetCount = Number(hasToSlug) + Number(hasToUrl);
|
|
1021
|
+
if (targetCount !== 1) {
|
|
1022
|
+
ctx.addIssue({
|
|
1023
|
+
code: "custom",
|
|
1024
|
+
message: "Each redirect must specify exactly one of toSlug/toType+toSlug or toUrl",
|
|
1025
|
+
path: ["toSlug"]
|
|
1026
|
+
});
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (hasToUrl && hasToType) {
|
|
1030
|
+
ctx.addIssue({
|
|
1031
|
+
code: "custom",
|
|
1032
|
+
message: "toUrl cannot be combined with toType",
|
|
1033
|
+
path: ["toUrl"]
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
if (hasToType && !hasToSlug) {
|
|
1037
|
+
ctx.addIssue({
|
|
1038
|
+
code: "custom",
|
|
1039
|
+
message: "Cross-type redirects require both toType and toSlug",
|
|
1040
|
+
path: ["toSlug"]
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
var typeRedirectsFileSchema = zod.z.object({
|
|
1045
|
+
redirects: zod.z.array(typeRedirectEntrySchema).max(500)
|
|
1046
|
+
});
|
|
1047
|
+
function normalizeRedirectFrom(from) {
|
|
1048
|
+
return Array.isArray(from) ? from : [from];
|
|
1049
|
+
}
|
|
1050
|
+
function parseRedirectEntry(entry) {
|
|
1051
|
+
const fromSlugs = normalizeRedirectFrom(entry.from);
|
|
1052
|
+
if (entry.toUrl !== void 0) {
|
|
1053
|
+
return {
|
|
1054
|
+
fromSlugs,
|
|
1055
|
+
kind: "anywhere",
|
|
1056
|
+
toUrl: entry.toUrl,
|
|
1057
|
+
permanent: entry.permanent ?? true
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
if (entry.toType !== void 0) {
|
|
1061
|
+
return {
|
|
1062
|
+
fromSlugs,
|
|
1063
|
+
kind: "cross-type",
|
|
1064
|
+
toType: entry.toType,
|
|
1065
|
+
toSlug: entry.toSlug,
|
|
1066
|
+
permanent: entry.permanent ?? true
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
fromSlugs,
|
|
1071
|
+
kind: "same-type",
|
|
1072
|
+
toSlug: entry.toSlug,
|
|
1073
|
+
permanent: entry.permanent ?? true
|
|
1074
|
+
};
|
|
1047
1075
|
}
|
|
1048
1076
|
|
|
1049
|
-
// src/
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1077
|
+
// src/redirects/load-type-redirects.ts
|
|
1078
|
+
var TYPE_REDIRECTS_FILENAME = "_redirects.json";
|
|
1079
|
+
function redirectsFilePath(config, type) {
|
|
1080
|
+
return path__default.default.join(config.rootDir, type.contentDir, TYPE_REDIRECTS_FILENAME);
|
|
1081
|
+
}
|
|
1082
|
+
function loadTypeRedirectsFile(config, type) {
|
|
1083
|
+
const filePath = redirectsFilePath(config, type);
|
|
1084
|
+
if (!fs2__default.default.existsSync(filePath)) return null;
|
|
1085
|
+
let raw;
|
|
1086
|
+
try {
|
|
1087
|
+
raw = JSON.parse(fs2__default.default.readFileSync(filePath, "utf8"));
|
|
1088
|
+
} catch (error) {
|
|
1089
|
+
throw new Error(
|
|
1090
|
+
`${type.id}: failed to parse ${TYPE_REDIRECTS_FILENAME}: ${error instanceof Error ? error.message : String(error)}`
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
const parsed = typeRedirectsFileSchema.safeParse(raw);
|
|
1094
|
+
if (!parsed.success) {
|
|
1095
|
+
const details = parsed.error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
|
|
1096
|
+
throw new Error(`${type.id}: invalid ${TYPE_REDIRECTS_FILENAME}: ${details}`);
|
|
1059
1097
|
}
|
|
1098
|
+
return {
|
|
1099
|
+
contentTypeId: type.id,
|
|
1100
|
+
contentDir: type.contentDir,
|
|
1101
|
+
filePath,
|
|
1102
|
+
entries: parsed.data.redirects.map(parseRedirectEntry)
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
function loadAllTypeRedirects(config) {
|
|
1106
|
+
const out = [];
|
|
1060
1107
|
for (const type of config.types) {
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
});
|
|
1085
|
-
continue;
|
|
1086
|
-
}
|
|
1087
|
-
const existing = aliasToTarget.get(alias);
|
|
1088
|
-
if (existing) {
|
|
1089
|
-
issues.push({
|
|
1090
|
-
contentTypeId: type.id,
|
|
1091
|
-
enSlug,
|
|
1092
|
-
field: "aliases",
|
|
1093
|
-
message: `Alias "${alias}" is already claimed by ${existing.contentTypeId}/${existing.canonicalSlug}`,
|
|
1094
|
-
level: "error"
|
|
1095
|
-
});
|
|
1096
|
-
continue;
|
|
1097
|
-
}
|
|
1098
|
-
aliasToTarget.set(alias, {
|
|
1099
|
-
contentTypeId: type.id,
|
|
1100
|
-
canonicalSlug: enSlug,
|
|
1101
|
-
path: type.path
|
|
1102
|
-
});
|
|
1103
|
-
allAliasSlugs.add(alias);
|
|
1108
|
+
const loaded = loadTypeRedirectsFile(config, type);
|
|
1109
|
+
if (loaded) out.push(loaded);
|
|
1110
|
+
}
|
|
1111
|
+
return out;
|
|
1112
|
+
}
|
|
1113
|
+
function collectRedirectSourceSlugs(loaded) {
|
|
1114
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
1115
|
+
for (const file of loaded) {
|
|
1116
|
+
for (const entry of file.entries) {
|
|
1117
|
+
for (const from of entry.fromSlugs) {
|
|
1118
|
+
slugs.add(from);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return slugs;
|
|
1123
|
+
}
|
|
1124
|
+
function collectOutboundRedirectSourcesByType(loaded) {
|
|
1125
|
+
const out = /* @__PURE__ */ new Map();
|
|
1126
|
+
for (const file of loaded) {
|
|
1127
|
+
const set = out.get(file.contentTypeId) ?? /* @__PURE__ */ new Set();
|
|
1128
|
+
for (const entry of file.entries) {
|
|
1129
|
+
for (const from of entry.fromSlugs) {
|
|
1130
|
+
set.add(from);
|
|
1104
1131
|
}
|
|
1105
1132
|
}
|
|
1133
|
+
out.set(file.contentTypeId, set);
|
|
1106
1134
|
}
|
|
1107
|
-
return
|
|
1135
|
+
return out;
|
|
1108
1136
|
}
|
|
1109
1137
|
|
|
1110
1138
|
// src/redirects/build-redirects.ts
|
|
1111
1139
|
function getRedirectSourceSlugs(project) {
|
|
1112
|
-
const
|
|
1113
|
-
const
|
|
1140
|
+
const loaded = loadAllTypeRedirects(project.config);
|
|
1141
|
+
const aliasSlugs = collectRedirectSourceSlugs(loaded);
|
|
1142
|
+
const outboundByType = collectOutboundRedirectSourcesByType(loaded);
|
|
1114
1143
|
for (const type of project.config.types) {
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
const doc = readEnDocument(project.config, type, enSlug);
|
|
1118
|
-
if (doc?.redirectTo) outbound.add(enSlug);
|
|
1144
|
+
if (!outboundByType.has(type.id)) {
|
|
1145
|
+
outboundByType.set(type.id, /* @__PURE__ */ new Set());
|
|
1119
1146
|
}
|
|
1120
|
-
outboundByType.set(type.id, outbound);
|
|
1121
1147
|
}
|
|
1122
1148
|
return {
|
|
1123
|
-
aliasSlugs
|
|
1149
|
+
aliasSlugs,
|
|
1124
1150
|
outboundByType
|
|
1125
1151
|
};
|
|
1126
1152
|
}
|
|
@@ -1128,13 +1154,12 @@ function getRedirectSourceSlugs(project) {
|
|
|
1128
1154
|
// src/sitemap/join-base-url.ts
|
|
1129
1155
|
function joinBaseUrl(baseUrl, pathname) {
|
|
1130
1156
|
const origin = baseUrl.replace(/\/$/, "");
|
|
1131
|
-
const
|
|
1132
|
-
return `${origin}${
|
|
1157
|
+
const path6 = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
1158
|
+
return `${origin}${path6}`;
|
|
1133
1159
|
}
|
|
1134
1160
|
|
|
1135
1161
|
// src/sitemap/generate-sitemap.ts
|
|
1136
1162
|
function shouldIncludeEnDoc(enDoc, enSlug, redirectSources, contentTypeId, excludeNoindex) {
|
|
1137
|
-
if (enDoc.redirectTo) return false;
|
|
1138
1163
|
if (redirectSources.aliasSlugs.has(enSlug)) return false;
|
|
1139
1164
|
const outbound = redirectSources.outboundByType.get(contentTypeId);
|
|
1140
1165
|
if (outbound?.has(enSlug)) return false;
|
|
@@ -1233,6 +1258,7 @@ function createScribe(input) {
|
|
|
1233
1258
|
}
|
|
1234
1259
|
|
|
1235
1260
|
exports.createScribe = createScribe;
|
|
1261
|
+
exports.createUrlBuilder = createUrlBuilder;
|
|
1236
1262
|
exports.isRoutableType = isRoutableType;
|
|
1237
1263
|
//# sourceMappingURL=runtime.cjs.map
|
|
1238
1264
|
//# sourceMappingURL=runtime.cjs.map
|