scribe-cms 0.0.8 → 0.0.10
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 +433 -384
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +433 -384
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +643 -512
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +643 -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/studio/server.js
CHANGED
|
@@ -186,65 +186,93 @@ function pathSuffix(template) {
|
|
|
186
186
|
if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);
|
|
187
187
|
return template.slice(idx + SLUG_PLACEHOLDER.length);
|
|
188
188
|
}
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
if (locale === defaultLocale) return relative;
|
|
192
|
-
return `/${locale}${relative}`;
|
|
189
|
+
function resolveDefaultLocaleRouting() {
|
|
190
|
+
return { strategy: "path-prefix", prefixDefaultLocale: false };
|
|
193
191
|
}
|
|
194
|
-
function
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
192
|
+
function splitPathAndSearch(pathname) {
|
|
193
|
+
const q = pathname.indexOf("?");
|
|
194
|
+
if (q === -1) return { pathname, search: "" };
|
|
195
|
+
return { pathname: pathname.slice(0, q), search: pathname.slice(q) };
|
|
196
|
+
}
|
|
197
|
+
function createUrlBuilder(config) {
|
|
198
|
+
const localeRouting = config.localeRouting ?? resolveDefaultLocaleRouting();
|
|
199
|
+
const defaultLocale = config.defaultLocale;
|
|
200
|
+
const prefixedLocales = localeRouting.strategy === "path-prefix" ? localeRouting.prefixDefaultLocale ? [...config.locales] : config.locales.filter((locale) => locale !== defaultLocale) : config.locales.filter((locale) => locale !== defaultLocale);
|
|
201
|
+
function applyLocaleToPath(pathname, locale) {
|
|
202
|
+
if (locale === defaultLocale) {
|
|
203
|
+
if (localeRouting.strategy === "path-prefix" && localeRouting.prefixDefaultLocale) {
|
|
204
|
+
return `/${defaultLocale}${pathname}`;
|
|
205
|
+
}
|
|
206
|
+
return pathname;
|
|
207
|
+
}
|
|
208
|
+
if (localeRouting.strategy === "search-param") {
|
|
209
|
+
const { pathname: base, search } = splitPathAndSearch(pathname);
|
|
210
|
+
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
211
|
+
params.set(localeRouting.param, locale);
|
|
212
|
+
const qs = params.toString();
|
|
213
|
+
return qs ? `${base}?${qs}` : base;
|
|
214
|
+
}
|
|
215
|
+
return `/${locale}${pathname}`;
|
|
216
|
+
}
|
|
217
|
+
function resolvePath(template, slug, locale) {
|
|
218
|
+
const relative = template.replace(SLUG_PLACEHOLDER, slug);
|
|
219
|
+
return applyLocaleToPath(relative, locale);
|
|
220
|
+
}
|
|
221
|
+
function extractSlugFromResolvedPath(template, resolvedPath) {
|
|
222
|
+
let pathname = resolvedPath;
|
|
223
|
+
if (localeRouting.strategy === "search-param") {
|
|
224
|
+
pathname = splitPathAndSearch(resolvedPath).pathname;
|
|
225
|
+
} else if (localeRouting.strategy === "path-prefix") {
|
|
226
|
+
for (const locale of config.locales) {
|
|
227
|
+
if (locale === defaultLocale && !localeRouting.prefixDefaultLocale) continue;
|
|
228
|
+
const prefix2 = `/${locale}`;
|
|
229
|
+
if (pathname === prefix2 || pathname.startsWith(`${prefix2}/`)) {
|
|
230
|
+
pathname = pathname.slice(prefix2.length) || "/";
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const prefix = pathPrefix(template);
|
|
236
|
+
const suffix = pathSuffix(template);
|
|
237
|
+
if (!pathname.startsWith(prefix)) return null;
|
|
238
|
+
if (suffix && !pathname.endsWith(suffix)) return null;
|
|
239
|
+
const slugEnd = suffix ? pathname.length - suffix.length : pathname.length;
|
|
240
|
+
const slug = pathname.slice(prefix.length, slugEnd);
|
|
241
|
+
return slug.length > 0 ? slug : null;
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
defaultLocale,
|
|
245
|
+
locales: config.locales,
|
|
246
|
+
localeRouting,
|
|
247
|
+
prefixedLocales,
|
|
248
|
+
resolvePath,
|
|
249
|
+
extractSlugFromResolvedPath,
|
|
250
|
+
applyLocaleToPath
|
|
251
|
+
};
|
|
202
252
|
}
|
|
203
253
|
|
|
204
254
|
// src/core/builtin-fields.ts
|
|
205
255
|
var SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
206
|
-
|
|
256
|
+
z.string().regex(SLUG_PATTERN, "slug must be lowercase-kebab-case");
|
|
207
257
|
var isoDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}(T[\d:.Z+-]*)?$/, "Use ISO date YYYY-MM-DD or full ISO 8601");
|
|
208
258
|
var canonicalPathSchema = z.string().regex(/^\//, "canonicalPath must start with /");
|
|
209
|
-
|
|
259
|
+
var DEPRECATED_REDIRECT_FIELDS = [
|
|
260
|
+
[
|
|
261
|
+
"aliases",
|
|
262
|
+
"aliases frontmatter is removed \u2014 add redirects to content/<type>/_redirects.json instead"
|
|
263
|
+
],
|
|
264
|
+
[
|
|
265
|
+
"redirect_to",
|
|
266
|
+
"redirect_to frontmatter is removed \u2014 add redirects to content/<type>/_redirects.json instead"
|
|
267
|
+
]
|
|
268
|
+
];
|
|
269
|
+
function extractBuiltinEnFields(data, _pathTemplate, _enSlug, _defaultLocale) {
|
|
210
270
|
const issues = [];
|
|
211
271
|
const rest = { ...data };
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
let redirectTo;
|
|
217
|
-
if (redirectRaw !== void 0 && redirectRaw !== null && redirectRaw !== "") {
|
|
218
|
-
if (typeof redirectRaw !== "string") {
|
|
219
|
-
issues.push({
|
|
220
|
-
field: "redirect_to",
|
|
221
|
-
message: "redirect_to must be a string path",
|
|
222
|
-
level: "error"
|
|
223
|
-
});
|
|
224
|
-
} else if (!pathTemplate) {
|
|
225
|
-
issues.push({
|
|
226
|
-
field: "redirect_to",
|
|
227
|
-
message: "redirect_to is not allowed on reference-only content types",
|
|
228
|
-
level: "error"
|
|
229
|
-
});
|
|
230
|
-
} else if (!extractSlugFromResolvedPath(pathTemplate, redirectRaw)) {
|
|
231
|
-
issues.push({
|
|
232
|
-
field: "redirect_to",
|
|
233
|
-
message: `redirect_to must match path template "${pathTemplate}" (prefix "${pathPrefix(pathTemplate)}"${pathSuffix(pathTemplate) ? `, suffix "${pathSuffix(pathTemplate)}"` : ""})`,
|
|
234
|
-
level: "error"
|
|
235
|
-
});
|
|
236
|
-
} else {
|
|
237
|
-
redirectTo = redirectRaw;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const aliases = aliasesResult.success ? aliasesResult.data : [];
|
|
241
|
-
if (!aliasesResult.success) {
|
|
242
|
-
for (const issue of aliasesResult.error.issues) {
|
|
243
|
-
issues.push({
|
|
244
|
-
field: `aliases.${issue.path.join(".")}`,
|
|
245
|
-
message: issue.message,
|
|
246
|
-
level: "error"
|
|
247
|
-
});
|
|
272
|
+
for (const [field, message] of DEPRECATED_REDIRECT_FIELDS) {
|
|
273
|
+
if (rest[field] !== void 0) {
|
|
274
|
+
issues.push({ field, message, level: "error" });
|
|
275
|
+
delete rest[field];
|
|
248
276
|
}
|
|
249
277
|
}
|
|
250
278
|
let publishedAt;
|
|
@@ -306,8 +334,6 @@ function extractBuiltinEnFields(data, pathTemplate, enSlug, defaultLocale) {
|
|
|
306
334
|
}
|
|
307
335
|
return {
|
|
308
336
|
builtin: {
|
|
309
|
-
aliases,
|
|
310
|
-
redirectTo,
|
|
311
337
|
publishedAt,
|
|
312
338
|
updatedAt,
|
|
313
339
|
noindex,
|
|
@@ -317,20 +343,24 @@ function extractBuiltinEnFields(data, pathTemplate, enSlug, defaultLocale) {
|
|
|
317
343
|
issues
|
|
318
344
|
};
|
|
319
345
|
}
|
|
320
|
-
function resolveCanonicalPathname(type, doc, defaultLocale) {
|
|
346
|
+
function resolveCanonicalPathname(type, doc, defaultLocale, localeRouting) {
|
|
347
|
+
const urlBuilder = createUrlBuilder({
|
|
348
|
+
locales: [defaultLocale, ...doc.locale !== defaultLocale ? [doc.locale] : []],
|
|
349
|
+
defaultLocale,
|
|
350
|
+
localeRouting: localeRouting ?? { strategy: "path-prefix", prefixDefaultLocale: false }
|
|
351
|
+
});
|
|
321
352
|
if (doc.canonicalPathOverride) {
|
|
322
|
-
|
|
323
|
-
return `/${doc.locale}${doc.canonicalPathOverride}`;
|
|
353
|
+
return urlBuilder.applyLocaleToPath(doc.canonicalPathOverride, doc.locale);
|
|
324
354
|
}
|
|
325
355
|
if (!type.path) return `/${doc.slug}`;
|
|
326
|
-
return resolvePath(type.path, doc.slug, doc.locale
|
|
356
|
+
return urlBuilder.resolvePath(type.path, doc.slug, doc.locale);
|
|
327
357
|
}
|
|
328
|
-
function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale) {
|
|
358
|
+
function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale, localeRouting) {
|
|
329
359
|
const out = { ...frontmatter };
|
|
330
360
|
if (doc.publishedAt !== void 0) out.publishedAt = doc.publishedAt;
|
|
331
361
|
if (doc.updatedAt !== void 0) out.updatedAt = doc.updatedAt;
|
|
332
362
|
out.noindex = doc.noindex;
|
|
333
|
-
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale);
|
|
363
|
+
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale, localeRouting);
|
|
334
364
|
return out;
|
|
335
365
|
}
|
|
336
366
|
var SCHEMA_VERSION = 4;
|
|
@@ -503,7 +533,8 @@ function parseEnMdx(filePath, config, type) {
|
|
|
503
533
|
locale: config.defaultLocale
|
|
504
534
|
},
|
|
505
535
|
type,
|
|
506
|
-
config.defaultLocale
|
|
536
|
+
config.defaultLocale,
|
|
537
|
+
config.localeRouting
|
|
507
538
|
);
|
|
508
539
|
const crossIssues = type.crossValidate?.(result.data, {
|
|
509
540
|
locale: config.defaultLocale,
|
|
@@ -517,8 +548,6 @@ function parseEnMdx(filePath, config, type) {
|
|
|
517
548
|
slug,
|
|
518
549
|
enSlug: slug,
|
|
519
550
|
locale: config.defaultLocale,
|
|
520
|
-
aliases: builtin.aliases,
|
|
521
|
-
redirectTo: builtin.redirectTo,
|
|
522
551
|
publishedAt: builtin.publishedAt,
|
|
523
552
|
updatedAt: builtin.updatedAt,
|
|
524
553
|
noindex: builtin.noindex,
|