@lupinum/ginko-content 0.3.0-rc.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -9
- package/dist/cli.mjs +52 -55
- package/dist/cms-contract/index.d.ts +7 -7
- package/dist/cms-contract/index.js +1 -2
- package/dist/cms-contract/mdc.d.ts +3 -9
- package/dist/cms-contract/mdc.js +6 -4
- package/dist/cms-contract/path.d.ts +3 -5
- package/dist/cms-contract/path.js +0 -1
- package/dist/cms-contract/render-policy.js +4 -0
- package/dist/cms-contract/schema.d.ts +1 -1
- package/dist/cms-contract/schema.js +3 -1
- package/dist/core/content/graph.d.ts +7 -22
- package/dist/core/content/graph.js +38 -52
- package/dist/core/content/locale.d.ts +10 -4
- package/dist/core/content/locale.js +15 -6
- package/dist/core/content/path.d.ts +35 -1
- package/dist/core/content/path.js +72 -13
- package/dist/core/content/structural.d.ts +1 -2
- package/dist/core/content/structural.js +1 -1
- package/dist/core/data-source-error.d.ts +5 -0
- package/dist/core/data-source-error.js +10 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/json-value.d.ts +1 -1
- package/dist/core/markdown/normalize-comark.d.ts +6 -0
- package/dist/core/markdown/normalize-comark.js +15 -0
- package/dist/core/markdown/parse-comark.d.ts +3 -0
- package/dist/core/markdown/parse-comark.js +30 -0
- package/dist/core/provider-errors.js +1 -1
- package/dist/core/provider-route-record.d.ts +18 -0
- package/dist/core/provider-route-record.js +106 -0
- package/dist/core/query/execute.d.ts +16 -23
- package/dist/core/query/execute.js +94 -110
- package/dist/core/query/filter.d.ts +8 -9
- package/dist/core/query/filter.js +145 -53
- package/dist/core/query/limits.d.ts +10 -0
- package/dist/core/query/limits.js +27 -0
- package/dist/core/query/lower.d.ts +12 -6
- package/dist/core/query/lower.js +356 -89
- package/dist/core/query/operators.d.ts +21 -10
- package/dist/core/query/operators.js +18 -11
- package/dist/core/query/params.d.ts +7 -10
- package/dist/core/query/params.js +47 -33
- package/dist/core/query/plan.d.ts +96 -105
- package/dist/core/references/resolve.d.ts +1 -1
- package/dist/core/references/resolve.js +31 -13
- package/dist/core/references/schema.d.ts +2 -0
- package/dist/core/references/schema.js +6 -8
- package/dist/core/runtime-diagnostics.d.ts +7 -0
- package/dist/core/runtime-diagnostics.js +9 -0
- package/dist/features/agent/agent-markdown.js +18 -3
- package/dist/features/agent/agent-paths.d.ts +0 -1
- package/dist/features/agent/agent-paths.js +0 -4
- package/dist/features/agent/walker.js +10 -7
- package/dist/features/collections/resolve.d.ts +2 -14
- package/dist/features/collections/resolve.js +3 -7
- package/dist/features/localization/config.d.ts +9 -1
- package/dist/features/localization/config.js +6 -1
- package/dist/features/localization/locale-policy.d.ts +14 -2
- package/dist/features/localization/locale-policy.js +81 -25
- package/dist/features/localization/path.d.ts +0 -10
- package/dist/features/localization/path.js +1 -23
- package/dist/features/localization/reference-path.d.ts +7 -0
- package/dist/features/localization/reference-path.js +10 -0
- package/dist/features/localization/results.d.ts +8 -43
- package/dist/features/localization/results.js +24 -47
- package/dist/features/localization/route-projector.d.ts +23 -16
- package/dist/features/localization/route-projector.js +35 -29
- package/dist/features/navigation/build.js +9 -5
- package/dist/features/navigation/canonical.d.ts +2 -8
- package/dist/features/navigation/canonical.js +8 -48
- package/dist/features/navigation/diagnostics.d.ts +11 -0
- package/dist/features/navigation/diagnostics.js +52 -0
- package/dist/features/navigation/query.d.ts +3 -5
- package/dist/features/navigation/resolve.d.ts +18 -2
- package/dist/features/navigation/resolve.js +28 -5
- package/dist/features/navigation/tree.d.ts +0 -1
- package/dist/features/navigation/tree.js +1 -1
- package/dist/features/query/context.d.ts +5 -3
- package/dist/features/query/diagnostics.d.ts +4 -0
- package/dist/features/query/diagnostics.js +22 -0
- package/dist/features/query/documents.js +6 -10
- package/dist/features/query/locale-options.js +2 -1
- package/dist/features/query/localized-docs.d.ts +0 -7
- package/dist/features/query/localized-docs.js +5 -31
- package/dist/features/query/navigation.d.ts +4 -4
- package/dist/features/query/navigation.js +2 -11
- package/dist/features/query/pagination.js +42 -31
- package/dist/features/query/populate.d.ts +1 -0
- package/dist/features/query/populate.js +76 -13
- package/dist/features/query/query-plan-boundary.d.ts +9 -0
- package/dist/features/query/query-plan-boundary.js +137 -0
- package/dist/features/query/responses.d.ts +28 -3
- package/dist/features/query/responses.js +33 -45
- package/dist/features/query/routes.d.ts +3 -10
- package/dist/features/query/routes.js +23 -13
- package/dist/features/query/unified.d.ts +6 -9
- package/dist/features/search/sections.js +3 -7
- package/dist/features/sitemap/counts.d.ts +1 -4
- package/dist/features/sitemap/query.d.ts +3 -6
- package/dist/features/sitemap/query.js +1 -1
- package/dist/features/validation/links.d.ts +2 -2
- package/dist/integrations/nitro/build.d.ts +5 -22
- package/dist/integrations/nitro/build.js +14 -47
- package/dist/integrations/nitro/ingest.js +18 -6
- package/dist/integrations/nitro/preview.js +23 -6
- package/dist/module.d.mts +51 -57
- package/dist/module.json +1 -1
- package/dist/module.mjs +44 -29
- package/dist/parsers/csv.js +5 -4
- package/dist/parsers/markdown.js +5 -6
- package/dist/parsers/path-meta.js +13 -6
- package/dist/parsers/reserved.d.ts +1 -2
- package/dist/portability/json.js +6 -1
- package/dist/portability/mdc.js +9 -4
- package/dist/public/agent-registry.d.ts +1 -1
- package/dist/public/agent-registry.js +8 -1
- package/dist/public/agent.d.ts +1 -2
- package/dist/public/client.d.ts +3 -3
- package/dist/public/data-source.d.ts +32 -19
- package/dist/public/data-source.js +3 -0
- package/dist/public/navigation.d.ts +7 -0
- package/dist/public/navigation.js +8 -0
- package/dist/public/provider-binder.d.ts +1 -1
- package/dist/public/provider-binder.js +93 -59
- package/dist/public/provider-contract.d.ts +27 -12
- package/dist/public/provider-contract.js +8 -0
- package/dist/public/provider-document.d.ts +46 -0
- package/dist/public/provider-document.js +109 -0
- package/dist/public/provider-errors.d.ts +1 -1
- package/dist/public/provider-errors.js +18 -9
- package/dist/public/provider-query.d.ts +73 -28
- package/dist/public/provider-query.js +48 -5
- package/dist/public/provider.d.ts +3 -3
- package/dist/public/provider.js +1 -1
- package/dist/public/server.d.ts +3 -3
- package/dist/public/server.js +0 -1
- package/dist/runtime/app/components/ContentRenderer.d.vue.ts +2 -2
- package/dist/runtime/app/components/ContentRenderer.vue.d.ts +2 -2
- package/dist/runtime/app/components/ContentRendererInline.vue +2 -2
- package/dist/runtime/app/components/Prose/ProsePre.d.vue.ts +2 -2
- package/dist/runtime/app/components/Prose/ProsePre.vue.d.ts +2 -2
- package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +2 -2
- package/dist/runtime/app/composables/query-api.d.ts +2 -2
- package/dist/runtime/app/composables/search.d.ts +9 -14
- package/dist/runtime/app/composables/search.js +4 -4
- package/dist/runtime/app/composables/site-data.d.ts +2 -2
- package/dist/runtime/app/composables/utils.d.ts +3 -3
- package/dist/runtime/app/composables/utils.js +3 -0
- package/dist/runtime/server/agent-markdown.js +9 -54
- package/dist/runtime/server/agent-site.d.ts +0 -2
- package/dist/runtime/server/agent-site.js +13 -27
- package/dist/runtime/server/api/agent-raw.js +3 -3
- package/dist/runtime/server/api/cache.d.ts +3 -5
- package/dist/runtime/server/api/cache.js +1 -1
- package/dist/runtime/server/api/locales.js +16 -2
- package/dist/runtime/server/api/navigation.js +35 -5
- package/dist/runtime/server/api/query.d.ts +1 -1
- package/dist/runtime/server/api/query.js +16 -2
- package/dist/runtime/server/api/revalidate.d.ts +3 -0
- package/dist/runtime/server/api/revalidate.js +108 -21
- package/dist/runtime/server/api/search.d.ts +1 -2
- package/dist/runtime/server/api/search.js +4 -7
- package/dist/runtime/server/api/site-data.d.ts +6 -1
- package/dist/runtime/server/api/site-data.js +32 -1
- package/dist/runtime/server/cache-adapter.js +2 -2
- package/dist/runtime/server/cache-adapters.d.ts +2 -12
- package/dist/runtime/server/cache-adapters.js +0 -9
- package/dist/runtime/server/collection-helpers.d.ts +1 -1
- package/dist/runtime/server/collection-helpers.js +20 -28
- package/dist/runtime/server/index.d.ts +1 -1
- package/dist/runtime/server/index.js +0 -1
- package/dist/runtime/server/middleware/agent-link-headers.js +5 -2
- package/dist/runtime/server/middleware/preview.d.ts +2 -0
- package/dist/runtime/server/middleware/preview.js +7 -0
- package/dist/runtime/server/navigation-query.d.ts +7 -2
- package/dist/runtime/server/navigation-query.js +64 -18
- package/dist/runtime/server/pagefind.js +8 -9
- package/dist/runtime/server/plugins/sitemap.js +1 -2
- package/dist/runtime/server/provider-query.d.ts +23 -36
- package/dist/runtime/server/provider-query.js +250 -185
- package/dist/runtime/server/provider-result.d.ts +5 -5
- package/dist/runtime/server/provider-route-facts.d.ts +6 -6
- package/dist/runtime/server/provider-route-facts.js +141 -96
- package/dist/runtime/server/providers/filesystem.js +75 -84
- package/dist/runtime/server/providers/index.d.ts +7 -7
- package/dist/runtime/server/providers/index.js +29 -44
- package/dist/runtime/server/query-api.d.ts +2 -2
- package/dist/runtime/server/query-api.js +28 -9
- package/dist/runtime/server/query-executor.d.ts +2 -3
- package/dist/runtime/server/query-executor.js +15 -14
- package/dist/runtime/server/query-http-validation.d.ts +10 -24
- package/dist/runtime/server/query-http-validation.js +100 -299
- package/dist/runtime/server/search.d.ts +2 -2
- package/dist/runtime/server/search.js +9 -3
- package/dist/runtime/server/sitemap-provider.js +11 -9
- package/dist/runtime/utils/query.d.ts +4 -4
- package/dist/runtime/utils/query.js +2 -2
- package/dist/storage/driver.d.ts +1 -16
- package/dist/storage/graph.d.ts +3 -14
- package/dist/storage/graph.js +7 -22
- package/dist/storage/references.d.ts +2 -2
- package/dist/storage/references.js +10 -4
- package/dist/storage/snapshot-runtime.js +6 -1
- package/dist/storage/validation.d.ts +6 -3
- package/dist/storage/validation.js +46 -12
- package/dist/testing/data-source-contract.d.ts +20 -1
- package/dist/testing/data-source-contract.js +63 -29
- package/dist/testing/provider-contract.d.ts +19 -4
- package/dist/testing/provider-contract.js +96 -16
- package/dist/testing/provider-fixture.d.ts +8 -2
- package/dist/testing/provider-fixture.js +132 -48
- package/dist/types/api.d.ts +12 -2
- package/dist/types/config.d.ts +5 -11
- package/dist/types/config.js +2 -2
- package/dist/types/content.d.ts +10 -8
- package/dist/types/fields.d.ts +1 -2
- package/dist/types/fields.js +28 -19
- package/dist/types/module.d.ts +11 -6
- package/dist/types/navigation.d.ts +13 -0
- package/dist/types/navigation.js +28 -0
- package/dist/types/query-parts/public.d.ts +35 -23
- package/dist/types/query-parts/public.js +7 -0
- package/dist/types/query-parts/results.d.ts +6 -22
- package/dist/types/query-parts/transport.d.ts +21 -80
- package/dist/types/query-parts/transport.js +18 -0
- package/dist/types/reference.d.ts +14 -1
- package/dist/types/reference.js +13 -1
- package/dist/types/runtime.d.ts +4 -15
- package/dist/web-types.json +1 -1
- package/package.json +9 -5
- package/dist/core/query/builder.d.ts +0 -18
- package/dist/core/query/builder.js +0 -186
- package/dist/features/query/public-limits.d.ts +0 -2
- package/dist/features/query/public-limits.js +0 -2
- package/dist/runtime/server/provider-document.d.ts +0 -44
- package/dist/runtime/server/provider-document.js +0 -63
- package/dist/runtime/server/provider-query-wire.d.ts +0 -30
- package/dist/runtime/server/provider-query-wire.js +0 -28
package/README.md
CHANGED
|
@@ -10,11 +10,14 @@ Use it when you want content files to stay simple, but your Nuxt app still
|
|
|
10
10
|
needs explicit APIs for route resolution, typed frontmatter, localized content,
|
|
11
11
|
and server-side reads.
|
|
12
12
|
|
|
13
|
+
This README describes the stable `0.3` line.
|
|
14
|
+
|
|
13
15
|
## Requirements
|
|
14
16
|
|
|
15
|
-
- Node.js 22 or
|
|
17
|
+
- Node.js 22.18–22.x, 24.11–24.x, or 26+
|
|
16
18
|
- Nuxt 4.4.7 through Nuxt 4.x
|
|
17
|
-
- Vue 3.5
|
|
19
|
+
- Vue 3.5.35 through Vue 3.x
|
|
20
|
+
- ESM; CommonJS `require()` is not supported
|
|
18
21
|
|
|
19
22
|
## Install
|
|
20
23
|
|
|
@@ -75,7 +78,7 @@ Render the current route through the collection:
|
|
|
75
78
|
```vue
|
|
76
79
|
<!-- pages/[...slug].vue -->
|
|
77
80
|
<script setup lang="ts">
|
|
78
|
-
import { pages } from '
|
|
81
|
+
import { pages } from '~~/content.config'
|
|
79
82
|
|
|
80
83
|
const { page } = await useContentPage(pages)
|
|
81
84
|
</script>
|
|
@@ -94,9 +97,10 @@ const { page } = await useContentPage(pages)
|
|
|
94
97
|
- locale-aware content routing
|
|
95
98
|
- route-aware page loading with `useContentPage(pages)`
|
|
96
99
|
- semantic previous/next route-page data through `useContentPage(pages, { surround })`
|
|
97
|
-
- server reads through `one`, `many`, `paginate`, `resolveOne`, `
|
|
98
|
-
`
|
|
99
|
-
-
|
|
100
|
+
- server reads through `one`, `many`, `paginate`, `resolveOne`, `navigation`,
|
|
101
|
+
and `surround`
|
|
102
|
+
- route and search composables, plus pure client query functions for other
|
|
103
|
+
reads
|
|
100
104
|
- search helpers for MiniSearch, Pagefind, and provider-owned search
|
|
101
105
|
- sitemap integration for public content routes
|
|
102
106
|
- a server-side provider contract for advanced custom sources
|
|
@@ -116,7 +120,8 @@ Do not duplicate docs, blog, pricing, privacy, or translated locale paths in
|
|
|
116
120
|
`@nuxtjs/sitemap >= 8.0.15 < 9` when translated static app slugs such as `/preise`
|
|
117
121
|
and `/en/pricing` need cross-locale sitemap alternates.
|
|
118
122
|
|
|
119
|
-
See the public guide:
|
|
123
|
+
See the public guide:
|
|
124
|
+
[Sitemap and prerender](https://github.com/lupinum-dev/ginko-content/blob/main/docs/content/docs/4.guides/4.routing-and-seo/3.sitemap-and-prerender.md).
|
|
120
125
|
|
|
121
126
|
## Integration Dependencies
|
|
122
127
|
|
|
@@ -134,10 +139,13 @@ See the public guide: [Sitemap and prerender](../../docs/content/docs/4.guides/4
|
|
|
134
139
|
The default provider reads files from your Nuxt project. The package does not
|
|
135
140
|
include a CMS UI, Studio, admin panel, or content editing workflow.
|
|
136
141
|
|
|
137
|
-
##
|
|
142
|
+
## Project links
|
|
138
143
|
|
|
139
|
-
- Documentation: [
|
|
144
|
+
- Documentation source: [Getting started](https://github.com/lupinum-dev/ginko-content/blob/main/docs/content/docs/3.get-started/1.installation.md)
|
|
140
145
|
- Repository: [github.com/lupinum-dev/ginko-content](https://github.com/lupinum-dev/ginko-content)
|
|
146
|
+
- Issues: [GitHub issues](https://github.com/lupinum-dev/ginko-content/issues)
|
|
147
|
+
- Contributing: [CONTRIBUTING.md](https://github.com/lupinum-dev/ginko-content/blob/main/CONTRIBUTING.md)
|
|
148
|
+
- Security: [SECURITY.md](https://github.com/lupinum-dev/ginko-content/blob/main/SECURITY.md)
|
|
141
149
|
|
|
142
150
|
## Credits
|
|
143
151
|
|
package/dist/cli.mjs
CHANGED
|
@@ -316,62 +316,63 @@ function extractLocaleCodesFromConfig(text) {
|
|
|
316
316
|
|
|
317
317
|
async function detectI18n(rootDir) {
|
|
318
318
|
const nuxtConfigPath = join(rootDir, "nuxt.config.ts");
|
|
319
|
-
const contentConfigPath = join(rootDir, "content.config.ts");
|
|
320
319
|
const nuxtConfig = await readTextIfPresent(nuxtConfigPath);
|
|
321
|
-
const contentConfig = await readTextIfPresent(contentConfigPath);
|
|
322
320
|
const packageJson = await readPackageJson(rootDir);
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
321
|
+
const contentI18nBlocks = findObjectPropertyBlocks(nuxtConfig, "content").flatMap((block) => findObjectPropertyBlocks(block, "i18n"));
|
|
322
|
+
const nuxtI18nBlocks = findObjectPropertyBlocks(nuxtConfig, "i18n");
|
|
323
|
+
for (const contentI18nBlock of contentI18nBlocks) {
|
|
324
|
+
const index = nuxtI18nBlocks.indexOf(contentI18nBlock);
|
|
325
|
+
if (index !== -1) {
|
|
326
|
+
nuxtI18nBlocks.splice(index, 1);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const nuxtI18nConfig = nuxtI18nBlocks.join("\n");
|
|
330
|
+
const contentI18nConfig = contentI18nBlocks.join("\n");
|
|
331
|
+
const hasNuxtI18nModule = /['"]@nuxtjs\/i18n['"]/.test(nuxtConfig);
|
|
332
|
+
const authorityConfig = hasNuxtI18nModule ? nuxtI18nConfig : contentI18nConfig;
|
|
336
333
|
return {
|
|
337
|
-
locales:
|
|
338
|
-
hasNuxtI18nModule
|
|
339
|
-
|
|
340
|
-
|
|
334
|
+
locales: extractLocaleCodesFromConfig(authorityConfig).sort(),
|
|
335
|
+
hasNuxtI18nModule,
|
|
336
|
+
hasNuxtI18nDependency: hasDependency(packageJson, "@nuxtjs/i18n"),
|
|
337
|
+
nuxtI18nDeclaresLocales: /\blocales\s*:/.test(nuxtI18nConfig),
|
|
338
|
+
nuxtI18nDeclaresDefaultLocale: /\bdefaultLocale\s*:/.test(nuxtI18nConfig),
|
|
339
|
+
contentI18nDeclaresLocales: /\blocales\s*:/.test(contentI18nConfig),
|
|
340
|
+
contentI18nDeclaresDefaultLocale: /\bdefaultLocale\s*:/.test(contentI18nConfig)
|
|
341
341
|
};
|
|
342
342
|
}
|
|
343
|
-
|
|
343
|
+
function inspectI18nConfig(detected) {
|
|
344
344
|
const findings = [];
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
345
|
+
if (detected.hasNuxtI18nModule) {
|
|
346
|
+
if (!detected.hasNuxtI18nDependency) {
|
|
347
|
+
findings.push({
|
|
348
|
+
severity: "error",
|
|
349
|
+
file: "package.json",
|
|
350
|
+
message: "Direct @nuxtjs/i18n dependency is missing for an i18n app.",
|
|
351
|
+
suggestion: "Install @nuxtjs/i18n directly so Nuxt owns route localization explicitly."
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
if (!detected.nuxtI18nDeclaresLocales || !detected.nuxtI18nDeclaresDefaultLocale) {
|
|
355
|
+
findings.push({
|
|
356
|
+
severity: "error",
|
|
357
|
+
file: "nuxt.config.ts",
|
|
358
|
+
message: "Nuxt I18n locale authority is incomplete.",
|
|
359
|
+
suggestion: "Declare locales and defaultLocale under top-level i18n in nuxt.config.ts."
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (detected.contentI18nDeclaresLocales || detected.contentI18nDeclaresDefaultLocale) {
|
|
363
|
+
findings.push({
|
|
364
|
+
severity: "error",
|
|
365
|
+
file: "nuxt.config.ts",
|
|
366
|
+
message: "Duplicate locale authority found in content.i18n.",
|
|
367
|
+
suggestion: "Remove locales and defaultLocale from content.i18n; Nuxt I18n is authoritative when registered. Keep only fallback and translatedSlugs there."
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
} else if (!detected.contentI18nDeclaresLocales || !detected.contentI18nDeclaresDefaultLocale) {
|
|
370
371
|
findings.push({
|
|
371
372
|
severity: "error",
|
|
372
373
|
file: "nuxt.config.ts",
|
|
373
|
-
message: "
|
|
374
|
-
suggestion: "
|
|
374
|
+
message: "Content-owned locale authority is incomplete.",
|
|
375
|
+
suggestion: "Without @nuxtjs/i18n, declare locales and defaultLocale under content.i18n in nuxt.config.ts."
|
|
375
376
|
});
|
|
376
377
|
}
|
|
377
378
|
return findings;
|
|
@@ -599,7 +600,7 @@ async function inspectI18nSearchIndex(rootDir, locales) {
|
|
|
599
600
|
async function inspectI18n(rootDir) {
|
|
600
601
|
const detected = await detectI18n(rootDir);
|
|
601
602
|
return [
|
|
602
|
-
...
|
|
603
|
+
...inspectI18nConfig(detected),
|
|
603
604
|
...await inspectI18nCollections(rootDir),
|
|
604
605
|
...await inspectI18nContentFolders(rootDir, detected.locales),
|
|
605
606
|
...await inspectI18nDuplicateContentGroups(rootDir, detected.locales),
|
|
@@ -746,15 +747,11 @@ async function inspectPublicApiUsage(rootDir) {
|
|
|
746
747
|
{
|
|
747
748
|
// `content.preview` is a real Ginko option (ContentPreviewOptions), unlike
|
|
748
749
|
// `content.database`/`content.build`, so it is not flagged as a v3
|
|
749
|
-
// leftover.
|
|
750
|
-
// filesystem
|
|
751
|
-
// configured token additionally unlocks visibility for files already
|
|
752
|
-
// present in a deployed filesystem checkout. It does not fetch
|
|
753
|
-
// not-yet-published content — that kind of production preview workflow
|
|
754
|
-
// is owned by a CMS provider, not the filesystem provider.
|
|
750
|
+
// leftover. It protects preview-storage overlay reads; it is not a
|
|
751
|
+
// production filesystem-preview switch or a partial-visibility switch.
|
|
755
752
|
pattern: /\bcontent\.preview\b/,
|
|
756
753
|
message: "content.preview configuration found.",
|
|
757
|
-
suggestion: "content.preview
|
|
754
|
+
suggestion: "content.preview protects filesystem preview-storage overlays. Ordinary drafts are visible in development, partials remain structural non-routes, and authenticated filesystem preview is unsupported in production; use provider-owned preview there.",
|
|
758
755
|
severity: "info"
|
|
759
756
|
},
|
|
760
757
|
{
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @lupinum/ginko-content/cms-contract
|
|
3
3
|
*
|
|
4
|
-
* Pure, runtime-safe surface
|
|
4
|
+
* Pure, runtime-safe surface for CMS/provider consumers. This subpath contains
|
|
5
5
|
* NO Node, Nuxt, h3, nitropack, filesystem, or @nuxt/kit dependencies. Every
|
|
6
|
-
* module re-exported from here MUST be importable from a V8 isolate
|
|
7
|
-
*
|
|
6
|
+
* module re-exported from here MUST be importable from a V8 isolate, worker,
|
|
7
|
+
* or browser.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Consumers use this surface to:
|
|
10
10
|
* - normalize a host's `content.config.ts` into the one portable
|
|
11
11
|
* `ResolvedContentContractV1` artifact (`buildResolvedContentContract`),
|
|
12
12
|
* - produce RFC 8785 canonical JSON and incremental SHA-256 hashes without
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
* - parse MDC into the same AST the filesystem provider uses (`parseMdcBody`).
|
|
19
19
|
*
|
|
20
20
|
* If a future change introduces a Node/Nuxt dependency anywhere in this
|
|
21
|
-
* tree,
|
|
21
|
+
* tree, isolate builds will break loudly. That's intentional.
|
|
22
22
|
*/
|
|
23
23
|
export { RESOLVED_CONTENT_CONTRACT_VERSION, buildResolvedContentContract, type BuildResolvedContentContractInput, type BuildResolvedContentContractOptions, } from './build.js';
|
|
24
24
|
export type { PortableComponentPolicyV1, PortableMediaType, ResolvedContentCollectionV1, ResolvedContentContractV1, ResolvedContentFieldTypeV1, ResolvedContentFieldV1, ResolvedContentValidationV1, ContentCmsCollectionConfig, ContentCmsFieldConfig, ContentCmsFieldType, ContentCmsRelationConfig, ContentCollectionConfig, ContentCollectionI18nConfig, } from './types.js';
|
|
25
|
-
export { describeId, generatePath, generateCanonicalKey, generateTitle, isDraftPath, isPartialPath,
|
|
26
|
-
export { CONTENT_FIELD_METADATA_KEY,
|
|
25
|
+
export { describeId, generatePath, generateCanonicalKey, generateTitle, isDraftPath, isPartialPath, mountContentPath, normalizeContentPath, normalizeRouteMounts, prefixPathWithLocale, refineUrlPart, routeRemainder, routeToContentPathCandidates, slugifyUrlSegment, stripLocalePrefix, } from './path.js';
|
|
26
|
+
export { CONTENT_FIELD_METADATA_KEY, CONTENT_REFERENCE_METADATA_KEY, collectTopLevelReferenceFields, getContentFieldMetadata, getObjectShape, getReferenceDescriptor, getSchemaDef, getSchemaTypeName, unwrapSchema, type ContentFieldMetadata, type ContentFieldSchema, } from './schema.js';
|
|
27
27
|
export { parseMdcBody, type ParseMdcBodyOptions, type ParseMdcBodyResult, } from './mdc.js';
|
|
28
28
|
export { assertPublicMarkdownAst, isSafePublicMarkdownUrl, PublicMarkdownValidationError, validatePublicMarkdownAst, type PublicMarkdownIssue, type PublicMarkdownIssueCode, type PublicMarkdownValidationResult, } from './render-policy.js';
|
|
29
29
|
export { verifyPublicImageBytes, type VerifiedPublicImage, } from './asset-bytes.js';
|
|
@@ -9,7 +9,6 @@ export {
|
|
|
9
9
|
generateTitle,
|
|
10
10
|
isDraftPath,
|
|
11
11
|
isPartialPath,
|
|
12
|
-
longestMountForPath,
|
|
13
12
|
mountContentPath,
|
|
14
13
|
normalizeContentPath,
|
|
15
14
|
normalizeRouteMounts,
|
|
@@ -22,7 +21,7 @@ export {
|
|
|
22
21
|
} from "./path.js";
|
|
23
22
|
export {
|
|
24
23
|
CONTENT_FIELD_METADATA_KEY,
|
|
25
|
-
|
|
24
|
+
CONTENT_REFERENCE_METADATA_KEY,
|
|
26
25
|
collectTopLevelReferenceFields,
|
|
27
26
|
getContentFieldMetadata,
|
|
28
27
|
getObjectShape,
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* markdown string in a paragraph element and regexing headings. That broke
|
|
6
|
-
* MDC components, links, tables, and any non-trivial markdown.
|
|
7
|
-
*
|
|
8
|
-
* Per Gate 0: parse once at publish time using ginko-content's real parser,
|
|
9
|
-
* store the AST on `publicEntries`, and have the public provider return the
|
|
10
|
-
* stored AST verbatim. The CMS imports this function from the pure subpath.
|
|
2
|
+
* Single canonical MDC parser entry point for external CMS integrations.
|
|
3
|
+
* Parse at publish time, persist the resulting AST, and return that AST from
|
|
4
|
+
* the public provider instead of maintaining a second markdown parser.
|
|
11
5
|
*/
|
|
12
6
|
import type { MarkdownRoot, Toc } from '../types/content.js';
|
|
13
7
|
export interface ParseMdcBodyOptions {
|
package/dist/cms-contract/mdc.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeComarkNodes } from "../core/markdown/normalize-comark.js";
|
|
2
|
+
import { parseComark } from "../core/markdown/parse-comark.js";
|
|
2
3
|
import { mapMarkdownNodes, toMarkdownRoot } from "../core/markdown/tree.js";
|
|
3
4
|
export async function parseMdcBody(raw, options = {}) {
|
|
4
|
-
const tree = await
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const tree = await parseComark(raw ?? "");
|
|
6
|
+
const nodes = normalizeComarkNodes(tree.nodes);
|
|
7
|
+
const toc = deriveToc(nodes, options);
|
|
8
|
+
const body = toMarkdownRoot(nodes, toc);
|
|
7
9
|
const searchText = renderPlainText(body);
|
|
8
10
|
return { body, toc, searchText };
|
|
9
11
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure path helpers re-exported from `ginko-content`'s canonical path engine.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* imports them. No more parallel implementations of `generatePath` /
|
|
7
|
-
* `generateCanonicalKey` / `slugifyUrlSegment`.
|
|
4
|
+
* External CMS integrations use these instead of duplicating path-generation
|
|
5
|
+
* logic. Ginko Content remains the sole owner of public path semantics.
|
|
8
6
|
*
|
|
9
7
|
* All re-exports MUST be runtime-pure (no Node, no Nuxt, no h3). They are.
|
|
10
8
|
*/
|
|
11
|
-
export { describeId, generatePath, generateCanonicalKey, generateTitle, isDraftPath, isPartialPath, normalizeContentPath, normalizeRouteMounts,
|
|
9
|
+
export { describeId, generatePath, generateCanonicalKey, generateTitle, isDraftPath, isPartialPath, normalizeContentPath, normalizeRouteMounts, routeRemainder, mountContentPath, prefixPathWithLocale, stripLocalePrefix, refineUrlPart, routeToContentPathCandidates, } from '../core/content/path.js';
|
|
12
10
|
export { slugifyUrlSegment } from '../core/content/slug.js';
|
|
@@ -226,6 +226,10 @@ export function validatePublicMarkdownAst(value, policy = { components: {} }) {
|
|
|
226
226
|
continue;
|
|
227
227
|
}
|
|
228
228
|
if (name === "style" && tag === "span" && isSafeShikiStyle(propValue)) continue;
|
|
229
|
+
if (tag === "blockquote" && name === "data-alert") {
|
|
230
|
+
if (typeof propValue !== "string" || !["note", "tip", "important", "warning", "caution"].includes(propValue)) report("invalid_prop_value", propPath, "Blockquote alert metadata is invalid.");
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
229
233
|
if (!name || /^on/i.test(name) || /^v-|^@|^:|^#/.test(name) || FORBIDDEN_PROPS.has(lower)) {
|
|
230
234
|
report("unsafe_prop", propPath, `Property "${name}" is not render-safe.`);
|
|
231
235
|
continue;
|
|
@@ -15,4 +15,4 @@ export { getSchemaDef, getSchemaTypeName, unwrapSchema, getObjectShape, getRefer
|
|
|
15
15
|
*/
|
|
16
16
|
export { CONTENT_FIELD_METADATA_KEY, type ContentFieldMetadata, type ContentFieldSchema, } from '../types/fields.js';
|
|
17
17
|
export { getContentFieldMetadata } from '../types/fields.js';
|
|
18
|
-
export {
|
|
18
|
+
export { CONTENT_REFERENCE_METADATA_KEY, } from '../types/reference.js';
|
|
@@ -10,4 +10,6 @@ export {
|
|
|
10
10
|
CONTENT_FIELD_METADATA_KEY
|
|
11
11
|
} from "../types/fields.js";
|
|
12
12
|
export { getContentFieldMetadata } from "../types/fields.js";
|
|
13
|
-
export {
|
|
13
|
+
export {
|
|
14
|
+
CONTENT_REFERENCE_METADATA_KEY
|
|
15
|
+
} from "../types/reference.js";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Canonical keys are only unique within a collection.
|
|
15
15
|
* - **`byCanonical`**: a derived convenience index containing only keys
|
|
16
16
|
* that occur in one collection. Ambiguous unscoped lookups fail closed.
|
|
17
|
-
* - **`byRoute`**: route path
|
|
17
|
+
* - **`byRoute`**: locale plus route path → canonical key. Used by the
|
|
18
18
|
* page resolver when the request arrives as a localized URL.
|
|
19
19
|
* - **`byRef`**: normalized ref string → canonical key. This is how
|
|
20
20
|
* markdown links such as `[Ada]($authors.ada)` find their target without a scan.
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
*/
|
|
29
29
|
import type { ParsedContent } from '../../types/content';
|
|
30
30
|
import type { ContentLocaleEntry } from '../../types/query';
|
|
31
|
-
import type {
|
|
32
|
-
export interface ContentGraphVariant extends
|
|
31
|
+
import type { ContentVariantIdentity, ResolvedVariant } from '../../types/runtime';
|
|
32
|
+
export interface ContentGraphVariant extends ContentVariantIdentity {
|
|
33
33
|
document: ParsedContent;
|
|
34
34
|
}
|
|
35
35
|
export interface ContentGraph {
|
|
@@ -44,7 +44,9 @@ export interface ContentGraph {
|
|
|
44
44
|
byCollectionCanonical: Record<string, Record<string, Record<string, ContentGraphVariant>>>;
|
|
45
45
|
/** Unambiguous canonical keys only. Derived from `byCollectionCanonical`. */
|
|
46
46
|
byCanonical: Record<string, Record<string, ContentGraphVariant>>;
|
|
47
|
-
/**
|
|
47
|
+
/** Exact collection → ref → canonical key alias index. */
|
|
48
|
+
byCollectionRef: Record<string, Record<string, string>>;
|
|
49
|
+
/** `"<locale>:<route path>"` → canonical key. Used by page resolution. */
|
|
48
50
|
byRoute: Record<string, string>;
|
|
49
51
|
/** normalized ref string → canonical key. */
|
|
50
52
|
byRef: Record<string, string>;
|
|
@@ -54,25 +56,7 @@ export interface ContentGraph {
|
|
|
54
56
|
referenceTargets: Map<string, string>;
|
|
55
57
|
/** Exact collection-scoped user-writable reference targets. */
|
|
56
58
|
referenceTargetsByCollection: Record<string, Map<string, string>>;
|
|
57
|
-
manifest: ContentManifest;
|
|
58
59
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Build the locale resolution chain for a request.
|
|
61
|
-
*
|
|
62
|
-
* Order, from highest to lowest priority:
|
|
63
|
-
* 1. The explicitly requested locale (if any).
|
|
64
|
-
* 2. Author-configured fallbacks for that locale.
|
|
65
|
-
* 3. The site-wide default locale.
|
|
66
|
-
*
|
|
67
|
-
* Duplicates are removed while preserving first-occurrence order, so the
|
|
68
|
-
* caller can walk the chain and stop at the first hit without worrying
|
|
69
|
-
* about re-visiting the default.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* resolveLocaleChain('fr', 'en', { fr: ['de'] }) // ['fr', 'de', 'en']
|
|
73
|
-
* resolveLocaleChain(undefined, 'en') // ['en']
|
|
74
|
-
*/
|
|
75
|
-
export declare const resolveLocaleChain: (requestedLocale: string | undefined, defaultLocale?: string, fallback?: Record<string, string[]>) => string[];
|
|
76
60
|
/**
|
|
77
61
|
* Build a `ContentGraph` from a flat list of parsed documents.
|
|
78
62
|
*
|
|
@@ -88,6 +72,7 @@ export declare const resolveLocaleChain: (requestedLocale: string | undefined, d
|
|
|
88
72
|
export declare const buildContentGraph: (documents: ParsedContent[], options?: {
|
|
89
73
|
locales?: string[];
|
|
90
74
|
defaultLocale?: string;
|
|
75
|
+
referencePathAliases?: (document: ParsedContent) => readonly string[];
|
|
91
76
|
}) => ContentGraph;
|
|
92
77
|
/** Resolve the exact collection-scoped variant set, or an unambiguous one. */
|
|
93
78
|
export declare const getGraphCanonicalVariants: (graph: ContentGraph, canonicalKey: string, collection?: string) => Record<string, ContentGraphVariant> | undefined;
|
|
@@ -1,34 +1,21 @@
|
|
|
1
1
|
import { isNavigationFile } from "./structural.js";
|
|
2
2
|
import { normalizeReferenceValue, buildReferenceTargets } from "../references/resolve.js";
|
|
3
|
-
import { sortLocalesCanonically } from "./locale.js";
|
|
3
|
+
import { resolveLocaleChain, sortLocalesCanonically } from "./locale.js";
|
|
4
4
|
const normalizePath = (path) => {
|
|
5
5
|
if (!path || path === "/") {
|
|
6
6
|
return "/";
|
|
7
7
|
}
|
|
8
8
|
return path.startsWith("/") ? path.endsWith("/") ? path.slice(0, -1) || "/" : path : `/${path.replace(/\/+$/, "")}`;
|
|
9
9
|
};
|
|
10
|
-
const emptyManifest = () => ({
|
|
11
|
-
byCollectionCanonical: {},
|
|
12
|
-
byCanonical: {},
|
|
13
|
-
byCollectionRef: {},
|
|
14
|
-
byRef: {},
|
|
15
|
-
byRoute: {},
|
|
16
|
-
paths: {},
|
|
17
|
-
collections: {}
|
|
18
|
-
});
|
|
19
|
-
export const resolveLocaleChain = (requestedLocale, defaultLocale, fallback = {}) => {
|
|
20
|
-
const chain = [
|
|
21
|
-
...requestedLocale ? [requestedLocale] : [],
|
|
22
|
-
...requestedLocale && fallback[requestedLocale] || [],
|
|
23
|
-
...defaultLocale ? [defaultLocale] : []
|
|
24
|
-
].filter(Boolean);
|
|
25
|
-
return Array.from(new Set(chain));
|
|
26
|
-
};
|
|
27
10
|
export const buildContentGraph = (documents, options = {}) => {
|
|
28
|
-
const manifest = emptyManifest();
|
|
29
11
|
const byId = {};
|
|
12
|
+
const byCollection = {};
|
|
13
|
+
const byPath = {};
|
|
30
14
|
const byCollectionCanonical = {};
|
|
31
15
|
const byCanonical = {};
|
|
16
|
+
const byCollectionRef = {};
|
|
17
|
+
const byRef = {};
|
|
18
|
+
const byRoute = {};
|
|
32
19
|
const byNavigationPath = {};
|
|
33
20
|
const defaultLocale = options.defaultLocale || "";
|
|
34
21
|
for (const document of documents) {
|
|
@@ -38,15 +25,15 @@ export const buildContentGraph = (documents, options = {}) => {
|
|
|
38
25
|
continue;
|
|
39
26
|
}
|
|
40
27
|
const path = normalizePath(document.path);
|
|
41
|
-
|
|
28
|
+
byPath[path] ||= [];
|
|
42
29
|
if (document.locale === defaultLocale) {
|
|
43
|
-
|
|
30
|
+
byPath[path].unshift(documentId);
|
|
44
31
|
} else {
|
|
45
|
-
|
|
32
|
+
byPath[path].push(documentId);
|
|
46
33
|
}
|
|
47
34
|
if (document.collection) {
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
byCollection[document.collection] ||= [];
|
|
36
|
+
byCollection[document.collection].push(documentId);
|
|
50
37
|
}
|
|
51
38
|
if (isNavigationFile(document)) {
|
|
52
39
|
const locale2 = document.locale || defaultLocale;
|
|
@@ -66,45 +53,43 @@ export const buildContentGraph = (documents, options = {}) => {
|
|
|
66
53
|
path,
|
|
67
54
|
document
|
|
68
55
|
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
byCollectionCanonical[collection] ||= {};
|
|
57
|
+
byCollectionCanonical[collection][document.canonicalKey] ||= {};
|
|
58
|
+
byCollectionCanonical[collection][document.canonicalKey][locale] = variant;
|
|
59
|
+
byRoute[`${locale}:${path}`] = document.canonicalKey;
|
|
73
60
|
if (document.type === "markdown" && typeof document.ref === "string" && document.ref.length) {
|
|
74
|
-
|
|
75
|
-
|
|
61
|
+
byCollectionRef[collection] ||= {};
|
|
62
|
+
byCollectionRef[collection][document.ref] = document.canonicalKey;
|
|
76
63
|
}
|
|
77
64
|
}
|
|
78
65
|
const collectionsByCanonical = /* @__PURE__ */ new Map();
|
|
79
|
-
for (const [collection, canonicalEntries] of Object.entries(
|
|
80
|
-
|
|
81
|
-
for (const [canonicalKey, variants] of Object.entries(canonicalEntries)) {
|
|
82
|
-
const graphVariants = Object.fromEntries(
|
|
83
|
-
Object.entries(variants).map(([locale, variant]) => [locale, { ...variant, document: byId[variant.contentId] }])
|
|
84
|
-
);
|
|
85
|
-
byCollectionCanonical[collection][canonicalKey] = graphVariants;
|
|
66
|
+
for (const [collection, canonicalEntries] of Object.entries(byCollectionCanonical)) {
|
|
67
|
+
for (const canonicalKey of Object.keys(canonicalEntries)) {
|
|
86
68
|
collectionsByCanonical.set(canonicalKey, [...collectionsByCanonical.get(canonicalKey) || [], collection]);
|
|
87
69
|
}
|
|
88
70
|
}
|
|
89
71
|
for (const [canonicalKey, collections] of collectionsByCanonical) {
|
|
90
72
|
if (collections.length !== 1) continue;
|
|
91
73
|
const collection = collections[0];
|
|
92
|
-
manifest.byCanonical[canonicalKey] = manifest.byCollectionCanonical[collection][canonicalKey];
|
|
93
74
|
byCanonical[canonicalKey] = byCollectionCanonical[collection][canonicalKey];
|
|
94
75
|
}
|
|
95
76
|
const collectionsByRef = /* @__PURE__ */ new Map();
|
|
96
|
-
for (const [collection, refs] of Object.entries(
|
|
77
|
+
for (const [collection, refs] of Object.entries(byCollectionRef)) {
|
|
97
78
|
for (const ref of Object.keys(refs)) {
|
|
98
79
|
collectionsByRef.set(ref, [...collectionsByRef.get(ref) || [], collection]);
|
|
99
80
|
}
|
|
100
81
|
}
|
|
101
82
|
for (const [ref, collections] of collectionsByRef) {
|
|
102
|
-
if (collections.length === 1)
|
|
83
|
+
if (collections.length === 1) byRef[ref] = byCollectionRef[collections[0]][ref];
|
|
103
84
|
}
|
|
104
85
|
const referenceTargetsByCollection = Object.fromEntries(
|
|
105
|
-
Object.keys(
|
|
86
|
+
Object.keys(byCollectionCanonical).map((collection) => [
|
|
106
87
|
collection,
|
|
107
|
-
buildReferenceTargets(
|
|
88
|
+
buildReferenceTargets(
|
|
89
|
+
documents.filter((document) => (document.collection || "content") === collection && !document.partial && !isNavigationFile(document)),
|
|
90
|
+
options.locales || [],
|
|
91
|
+
options.referencePathAliases
|
|
92
|
+
)
|
|
108
93
|
])
|
|
109
94
|
);
|
|
110
95
|
const referenceTargetCollections = /* @__PURE__ */ new Map();
|
|
@@ -120,16 +105,16 @@ export const buildContentGraph = (documents, options = {}) => {
|
|
|
120
105
|
return {
|
|
121
106
|
documents,
|
|
122
107
|
byId,
|
|
123
|
-
byCollection
|
|
124
|
-
byPath
|
|
108
|
+
byCollection,
|
|
109
|
+
byPath,
|
|
125
110
|
byCollectionCanonical,
|
|
126
111
|
byCanonical,
|
|
127
|
-
|
|
128
|
-
|
|
112
|
+
byCollectionRef,
|
|
113
|
+
byRoute,
|
|
114
|
+
byRef,
|
|
129
115
|
byNavigationPath,
|
|
130
116
|
referenceTargets,
|
|
131
|
-
referenceTargetsByCollection
|
|
132
|
-
manifest
|
|
117
|
+
referenceTargetsByCollection
|
|
133
118
|
};
|
|
134
119
|
};
|
|
135
120
|
export const getGraphCanonicalVariants = (graph, canonicalKey, collection) => {
|
|
@@ -145,8 +130,9 @@ export const resolveGraphVariant = (graph, canonicalKey, requestedLocale, option
|
|
|
145
130
|
return null;
|
|
146
131
|
}
|
|
147
132
|
const availableLocales = sortLocalesCanonically(Object.keys(variants), options);
|
|
148
|
-
const
|
|
149
|
-
const
|
|
133
|
+
const hasExplicitFallback = options.fallback !== void 0;
|
|
134
|
+
const localeChain = options.exact ? requestedLocale ? [requestedLocale] : [] : hasExplicitFallback ? Array.from(new Set([requestedLocale, ...options.fallback || []].filter(Boolean))) : resolveLocaleChain(requestedLocale, options.defaultLocale, options.localeFallback || {});
|
|
135
|
+
const resolvedLocale = localeChain.find((locale) => variants[locale]) || (options.exact || hasExplicitFallback ? void 0 : availableLocales[0]);
|
|
150
136
|
if (resolvedLocale === void 0) {
|
|
151
137
|
return null;
|
|
152
138
|
}
|
|
@@ -164,7 +150,7 @@ export const resolveGraphVariant = (graph, canonicalKey, requestedLocale, option
|
|
|
164
150
|
};
|
|
165
151
|
export const resolveGraphRouteVariant = (graph, routePath, requestedLocale, options = {}) => {
|
|
166
152
|
const normalizedPath = normalizePath(routePath);
|
|
167
|
-
const localeChain = options.exact ? requestedLocale ? [requestedLocale] : [] : options.fallback
|
|
153
|
+
const localeChain = options.exact ? requestedLocale ? [requestedLocale] : [] : options.fallback !== void 0 ? Array.from(new Set([requestedLocale, ...options.fallback || []].filter(Boolean))) : resolveLocaleChain(requestedLocale, options.defaultLocale, options.localeFallback || {});
|
|
168
154
|
const localesToSearch = localeChain.length ? localeChain : sortLocalesCanonically(getGraphVariantLocales(graph, options.collection), options);
|
|
169
155
|
for (const locale of localesToSearch) {
|
|
170
156
|
const canonicalKey = graph.byRoute[`${locale}:${normalizedPath}`];
|
|
@@ -187,7 +173,7 @@ export const resolveGraphCanonicalKey = (graph, identity, collection) => {
|
|
|
187
173
|
if (hasCollectionVariant(normalizedIdentity)) {
|
|
188
174
|
return normalizedIdentity;
|
|
189
175
|
}
|
|
190
|
-
const refCanonicalKey = collection ? graph.
|
|
176
|
+
const refCanonicalKey = collection ? graph.byCollectionRef[collection]?.[normalizedIdentity] : graph.byRef[normalizedIdentity];
|
|
191
177
|
if (refCanonicalKey && hasCollectionVariant(refCanonicalKey)) {
|
|
192
178
|
return refCanonicalKey;
|
|
193
179
|
}
|
|
@@ -23,10 +23,14 @@ import type { ContentCollectionI18nConfig } from '../../types/config';
|
|
|
23
23
|
/** Separator between source id and locale in inline-variant ids. */
|
|
24
24
|
export declare const INLINE_LOCALE_ID_SEPARATOR = "#__locale=";
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
|
|
26
|
+
* Build the locale resolution chain for a request. The requested locale,
|
|
27
|
+
* configured fallbacks, and default locale are ordered by priority and
|
|
28
|
+
* deduplicated without reordering.
|
|
29
|
+
*/
|
|
30
|
+
export declare const resolveLocaleChain: (requestedLocale: string | undefined, defaultLocale?: string, fallback?: Readonly<Record<string, readonly string[]>>) => string[];
|
|
31
|
+
/**
|
|
32
|
+
* Produce the fallback portion of the canonical locale chain, excluding the
|
|
33
|
+
* requested locale itself.
|
|
30
34
|
*
|
|
31
35
|
* @example
|
|
32
36
|
* buildLocaleFallbackChain('fr', 'en', { fr: ['de'] }) // ['de', 'en']
|
|
@@ -64,3 +68,5 @@ export declare const splitInlineLocaleVariantId: (id: string) => {
|
|
|
64
68
|
* override should not fail ingest for the whole document.
|
|
65
69
|
*/
|
|
66
70
|
export declare const expandDataLocaleVariants: (document: ParsedContent, i18nConfig?: ContentCollectionI18nConfig) => ParsedContent[];
|
|
71
|
+
/** Physical locale identity used when content has no configured locale authority. */
|
|
72
|
+
export declare const DEFAULT_CONTENT_LOCALE = "en";
|