@lupinum/ginko-content 0.1.6 → 0.2.1
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/compatibility.json +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/cms-contract/build.js +15 -20
- package/dist/cms-contract/types.d.ts +12 -7
- package/dist/core/content/document +1 -0
- package/dist/core/content/document.d.ts +16 -0
- package/dist/core/content/document.js +2 -0
- package/dist/core/content/graph.d.ts +3 -1
- package/dist/core/content/graph.js +21 -20
- package/dist/core/content/locale.d.ts +6 -1
- package/dist/core/content/locale.js +17 -6
- package/dist/core/content/path.d.ts +5 -5
- package/dist/core/content/path.js +8 -8
- package/dist/core/content/snapshot +1 -0
- package/dist/core/content/snapshot.d.ts +25 -0
- package/dist/core/content/snapshot.js +99 -0
- package/dist/core/provider-errors.d.ts +1 -1
- package/dist/core/provider-errors.js +1 -0
- package/dist/core/query/builder.js +3 -3
- package/dist/core/query/execute.js +75 -36
- package/dist/core/query/filter.js +2 -2
- package/dist/core/query/lower.js +79 -3
- package/dist/core/query/params.js +7 -7
- package/dist/core/query/plan.d.ts +18 -0
- package/dist/core/query/plan.js +7 -0
- package/dist/core/references/resolve.js +6 -9
- package/dist/features/agent/agent-markdown +1 -0
- package/dist/features/agent/agent-markdown.d.ts +116 -0
- package/dist/features/agent/agent-markdown.js +138 -0
- package/dist/features/agent/walker +1 -0
- package/dist/features/agent/walker.d.ts +10 -0
- package/dist/features/agent/walker.js +174 -0
- package/dist/features/collections/resolve.d.ts +2 -2
- package/dist/features/collections/resolve.js +19 -16
- package/dist/features/localization/links.js +1 -1
- package/dist/features/localization/results.d.ts +3 -3
- package/dist/features/localization/results.js +46 -41
- package/dist/features/localization/translated-slugs.js +5 -5
- package/dist/features/navigation/build.d.ts +2 -2
- package/dist/features/navigation/build.js +23 -26
- package/dist/features/navigation/canonical.d.ts +10 -11
- package/dist/features/navigation/canonical.js +26 -21
- package/dist/features/navigation/resolve.js +4 -4
- package/dist/features/navigation/tree.js +3 -3
- package/dist/{runtime → features}/query/backlinks.js +3 -5
- package/dist/{runtime → features}/query/documents.js +1 -1
- package/dist/{runtime → features}/query/localized-docs.d.ts +1 -1
- package/dist/{runtime → features}/query/localized-docs.js +3 -6
- package/dist/{runtime → features}/query/navigation.d.ts +1 -1
- package/dist/{runtime → features}/query/navigation.js +8 -8
- package/dist/{runtime → features}/query/populate.js +6 -14
- package/dist/{runtime → features}/query/unified.d.ts +4 -4
- package/dist/{runtime → features}/query/unified.js +4 -2
- package/dist/{runtime → features}/query/variants.js +4 -4
- package/dist/features/search/navigation.js +2 -2
- package/dist/features/search/sections.d.ts +1 -1
- package/dist/features/search/sections.js +1 -1
- package/dist/features/sitemap/query.d.ts +5 -5
- package/dist/features/sitemap/query.js +6 -6
- package/dist/integrations/nitro/ingest.js +9 -20
- package/dist/integrations/nitro/storage.d.ts +1 -0
- package/dist/integrations/nitro/storage.js +22 -8
- package/dist/module.d.mts +135 -812
- package/dist/module.json +1 -1
- package/dist/module.mjs +75 -28
- package/dist/parsers/csv.js +3 -3
- package/dist/parsers/index.js +3 -3
- package/dist/parsers/json.js +8 -6
- package/dist/parsers/markdown-plugins.js +9 -5
- package/dist/parsers/markdown.js +7 -6
- package/dist/parsers/path-meta.js +21 -19
- package/dist/parsers/reserved +1 -0
- package/dist/parsers/reserved.d.ts +15 -0
- package/dist/parsers/reserved.js +35 -0
- package/dist/parsers/yaml.js +6 -4
- package/dist/public/agent +1 -0
- package/dist/public/agent.d.ts +17 -0
- package/dist/public/agent.js +34 -0
- package/dist/public/client.d.ts +2 -3
- package/dist/public/client.js +1 -2
- package/dist/public/provider-query +1 -0
- package/dist/public/provider-query.d.ts +58 -0
- package/dist/public/provider-query.js +5 -0
- package/dist/public/provider.d.ts +10 -3
- package/dist/public/provider.js +3 -0
- package/dist/public/server.d.ts +7 -12
- package/dist/public/server.js +5 -36
- package/dist/runtime/app/components/ContentRenderer.d.vue.ts +3 -3
- package/dist/runtime/app/components/ContentRenderer.vue +2 -2
- package/dist/runtime/app/components/ContentRenderer.vue.d.ts +3 -3
- package/dist/runtime/app/components/ContentRendererInline.d.vue.ts +1 -1
- package/dist/runtime/app/components/ContentRendererInline.vue.d.ts +1 -1
- package/dist/runtime/app/components/Prose/ProseImg.d.vue.ts +4 -4
- package/dist/runtime/app/components/Prose/ProseImg.vue.d.ts +4 -4
- package/dist/runtime/app/components/Prose/ProsePre.d.vue.ts +1 -1
- package/dist/runtime/app/components/Prose/ProsePre.vue.d.ts +1 -1
- package/dist/runtime/app/components/internal/ContentRendererMarkdown.d.vue.ts +1 -1
- package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue +4 -4
- package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue.d.ts +1 -1
- package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +3 -3
- package/dist/runtime/app/composables/preview.d.ts +1 -1
- package/dist/runtime/app/composables/query-api.d.ts +5 -5
- package/dist/runtime/app/composables/query-api.js +5 -3
- package/dist/runtime/app/composables/route.d.ts +1 -1
- package/dist/runtime/app/composables/route.js +4 -4
- package/dist/runtime/app/composables/search.js +1 -1
- package/dist/runtime/app/composables/use-content-document.js +1 -1
- package/dist/runtime/app/composables/use-content-list.js +1 -1
- package/dist/runtime/app/composables/use-content-navigation.js +2 -2
- package/dist/runtime/app/composables/use-content-page.js +4 -4
- package/dist/runtime/app/pages/content.vue +2 -1
- package/dist/runtime/markdown/plugins.js +6 -8
- package/dist/runtime/server/agent-markdown.d.ts +5 -65
- package/dist/runtime/server/agent-markdown.js +40 -315
- package/dist/runtime/server/agent-site.js +1 -1
- package/dist/runtime/server/api/agent-raw.js +1 -1
- package/dist/runtime/server/api/cache.d.ts +1 -1
- package/dist/runtime/server/api/cache.js +43 -4
- package/dist/runtime/server/api/locales.js +3 -3
- package/dist/runtime/server/api/navigation.d.ts +1 -1
- package/dist/runtime/server/api/navigation.js +3 -1
- package/dist/runtime/server/api/query.js +2 -2
- package/dist/runtime/server/api/search-index.d.ts +1 -1
- package/dist/runtime/server/api/sitemap.d.ts +1 -1
- package/dist/runtime/server/cache-adapters.d.ts +18 -0
- package/dist/runtime/server/cache-adapters.js +12 -0
- package/dist/runtime/server/collection-helpers.d.ts +2 -2
- package/dist/runtime/server/collection-helpers.js +15 -11
- package/dist/runtime/server/index.d.ts +6 -4
- package/dist/runtime/server/index.js +10 -3
- package/dist/runtime/server/middleware/agent-link-headers.js +1 -1
- package/dist/runtime/server/middleware/agent-markdown.js +1 -1
- package/dist/runtime/server/navigation-query.d.ts +2 -2
- package/dist/runtime/server/navigation-query.js +52 -7
- package/dist/runtime/server/navigation.d.ts +1 -1
- package/dist/runtime/server/provider-document +1 -0
- package/dist/runtime/server/provider-document.d.ts +59 -0
- package/dist/runtime/server/provider-document.js +48 -0
- package/dist/runtime/server/provider-query-wire +1 -0
- package/dist/runtime/server/provider-query-wire.d.ts +32 -0
- package/dist/runtime/server/provider-query-wire.js +27 -0
- package/dist/runtime/server/provider-query.d.ts +18 -9
- package/dist/runtime/server/provider-query.js +62 -28
- package/dist/runtime/server/provider-result.d.ts +4 -4
- package/dist/runtime/server/providers/filesystem.js +3 -11
- package/dist/runtime/server/providers/index.d.ts +18 -1
- package/dist/runtime/server/providers/index.js +72 -20
- package/dist/runtime/server/query-api.d.ts +5 -5
- package/dist/runtime/server/query-api.js +9 -6
- package/dist/runtime/server/query-executor.d.ts +3 -3
- package/dist/runtime/server/query-executor.js +43 -59
- package/dist/runtime/server/search.d.ts +1 -1
- package/dist/runtime/server/search.js +4 -4
- package/dist/runtime/server/sitemap.js +5 -5
- package/dist/runtime/server/storage-access.d.ts +4 -1
- package/dist/runtime/server/storage-access.js +27 -2
- package/dist/runtime/transformers/component-resolver.d.ts +1 -1
- package/dist/storage/content.d.ts +2 -6
- package/dist/storage/content.js +19 -8
- package/dist/storage/contents.d.ts +9 -1
- package/dist/storage/contents.js +26 -19
- package/dist/storage/driver.d.ts +2 -2
- package/dist/storage/driver.js +2 -1
- package/dist/storage/graph.js +4 -0
- package/dist/storage/manifest.js +3 -1
- package/dist/storage/references.js +9 -5
- package/dist/storage/snapshot-runtime +1 -0
- package/dist/storage/snapshot-runtime.d.ts +11 -0
- package/dist/storage/snapshot-runtime.js +46 -0
- package/dist/storage/validation.d.ts +1 -1
- package/dist/storage/validation.js +47 -102
- package/dist/testing/provider-contract.d.ts +31 -4
- package/dist/testing/provider-contract.js +241 -81
- package/dist/testing/provider-fixture.d.ts +1 -1
- package/dist/testing/provider-fixture.js +124 -120
- package/dist/types/config.d.ts +8 -4
- package/dist/types/content.d.ts +104 -70
- package/dist/types/fields.js +1 -1
- package/dist/types/module.d.ts +1 -1
- package/dist/types/query-parts/public.d.ts +14 -5
- package/dist/types/query-parts/results.d.ts +6 -2
- package/dist/types/query-parts/transport.d.ts +19 -0
- package/dist/types/virtual.d.ts +6 -0
- package/dist/types.d.mts +2 -2
- package/dist/web-types.json +1 -1
- package/package.json +39 -9
- package/dist/runtime/app/plugins/markdown-components +0 -1
- package/dist/runtime/app/plugins/markdown-components.d.ts +0 -2
- package/dist/runtime/app/plugins/markdown-components.js +0 -19
- /package/dist/{runtime → features/agent}/agent-paths +0 -0
- /package/dist/{runtime → features/agent}/agent-paths.d.ts +0 -0
- /package/dist/{runtime → features/agent}/agent-paths.js +0 -0
- /package/dist/{runtime → features}/query/backlinks +0 -0
- /package/dist/{runtime → features}/query/backlinks.d.ts +0 -0
- /package/dist/{runtime → features}/query/context +0 -0
- /package/dist/{runtime → features}/query/context.d.ts +0 -0
- /package/dist/{runtime → features}/query/context.js +0 -0
- /package/dist/{runtime → features}/query/documents +0 -0
- /package/dist/{runtime → features}/query/documents.d.ts +0 -0
- /package/dist/{runtime → features}/query/errors +0 -0
- /package/dist/{runtime → features}/query/errors.d.ts +0 -0
- /package/dist/{runtime → features}/query/errors.js +0 -0
- /package/dist/{runtime → features}/query/handles +0 -0
- /package/dist/{runtime → features}/query/handles.d.ts +0 -0
- /package/dist/{runtime → features}/query/handles.js +0 -0
- /package/dist/{runtime → features}/query/locale-options +0 -0
- /package/dist/{runtime → features}/query/locale-options.d.ts +0 -0
- /package/dist/{runtime → features}/query/locale-options.js +0 -0
- /package/dist/{runtime → features}/query/localized-docs +0 -0
- /package/dist/{runtime → features}/query/navigation +0 -0
- /package/dist/{runtime → features}/query/pagination +0 -0
- /package/dist/{runtime → features}/query/pagination.d.ts +0 -0
- /package/dist/{runtime → features}/query/pagination.js +0 -0
- /package/dist/{runtime → features}/query/populate +0 -0
- /package/dist/{runtime → features}/query/populate.d.ts +0 -0
- /package/dist/{runtime → features}/query/public-limits +0 -0
- /package/dist/{runtime → features}/query/public-limits.d.ts +0 -0
- /package/dist/{runtime → features}/query/public-limits.js +0 -0
- /package/dist/{runtime → features}/query/resolve +0 -0
- /package/dist/{runtime → features}/query/resolve.d.ts +0 -0
- /package/dist/{runtime → features}/query/resolve.js +0 -0
- /package/dist/{runtime → features}/query/responses +0 -0
- /package/dist/{runtime → features}/query/responses.d.ts +0 -0
- /package/dist/{runtime → features}/query/responses.js +0 -0
- /package/dist/{runtime → features}/query/routes +0 -0
- /package/dist/{runtime → features}/query/routes.d.ts +0 -0
- /package/dist/{runtime → features}/query/routes.js +0 -0
- /package/dist/{runtime → features}/query/unified +0 -0
- /package/dist/{runtime → features}/query/variants +0 -0
- /package/dist/{runtime → features}/query/variants.d.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Build the navigation tree from a flat list of content metadata.
|
|
3
3
|
*
|
|
4
|
-
* The input is a flat list of content rows with `title`, `
|
|
4
|
+
* The input is a flat list of content rows with `title`, `path`, `file`, and
|
|
5
5
|
* optional extra fields; the output is a `NavItem[]` tree where parent folders
|
|
6
6
|
* are synthesized from path segments and `/.navigation.yml` config entries
|
|
7
7
|
* can override titles and metadata per directory.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - **`.navigation.yml`** — `configs['/guide']` can set `navigation: false`
|
|
15
15
|
* on a directory to hide the entire subtree from navigation; or
|
|
16
16
|
* override `title`/other fields.
|
|
17
|
-
* - **Natural sort** — siblings sort by `
|
|
17
|
+
* - **Natural sort** — siblings sort by `file.path` (filename without the
|
|
18
18
|
* extension) via `Intl.Collator({ numeric: true })`, so `10-foo` comes
|
|
19
19
|
* after `2-foo`, not between `1-foo` and `20-foo`.
|
|
20
20
|
* - **Two-pass shaping** — we build a mutable canonical tree, then project it
|
|
@@ -10,19 +10,18 @@ const pick = (keys) => (obj) => {
|
|
|
10
10
|
};
|
|
11
11
|
const isObject = (value) => Object.prototype.toString.call(value) === "[object Object]";
|
|
12
12
|
const parentCanonicalKey = (content, depth) => {
|
|
13
|
-
const canonicalKey = content.
|
|
13
|
+
const canonicalKey = content.canonicalKey;
|
|
14
14
|
if (typeof canonicalKey !== "string" || !canonicalKey) {
|
|
15
15
|
return void 0;
|
|
16
16
|
}
|
|
17
17
|
return canonicalKey.split("/").slice(0, depth + 1).join("/") || void 0;
|
|
18
18
|
};
|
|
19
|
+
const sortBasename = (item) => {
|
|
20
|
+
const path = item.file?.path;
|
|
21
|
+
return typeof path === "string" ? path.split(".").slice(0, -1).join(".") : "";
|
|
22
|
+
};
|
|
19
23
|
const sortCanonicalTree = (items) => {
|
|
20
|
-
items.
|
|
21
|
-
if (item._file) {
|
|
22
|
-
item._file = item._file.split(".").slice(0, -1).join(".");
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
const sorted = items.sort((left, right) => collator.compare(left._file || "", right._file || ""));
|
|
24
|
+
const sorted = items.sort((left, right) => collator.compare(sortBasename(left), sortBasename(right)));
|
|
26
25
|
for (const item of sorted) {
|
|
27
26
|
if (item.children?.length) {
|
|
28
27
|
sortCanonicalTree(item.children);
|
|
@@ -40,26 +39,25 @@ export const buildCanonicalNavigation = (contents, configs, fields = []) => {
|
|
|
40
39
|
...navigationFields
|
|
41
40
|
};
|
|
42
41
|
};
|
|
43
|
-
const navigation = contents.sort((left, right) => left.
|
|
44
|
-
const parts = content.
|
|
45
|
-
const idParts = content.
|
|
42
|
+
const navigation = contents.sort((left, right) => left.path.localeCompare(right.path)).reduce((nav, content) => {
|
|
43
|
+
const parts = content.path.substring(1).split("/");
|
|
44
|
+
const idParts = content.id.split(":").slice(1);
|
|
46
45
|
const isIndex = Boolean(idParts[idParts.length - 1]?.match(/([1-9][0-9]*\.)?index.md/g));
|
|
47
46
|
const navItem = {
|
|
48
47
|
title: content.title,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
_navigationPath: content._path,
|
|
48
|
+
path: content.path,
|
|
49
|
+
file: content.file,
|
|
50
|
+
id: content.id,
|
|
51
|
+
canonicalKey: content.canonicalKey,
|
|
52
|
+
locale: content.locale,
|
|
53
|
+
navigationKind: "page",
|
|
54
|
+
navigationPath: content.path,
|
|
57
55
|
children: [],
|
|
58
56
|
...pickNavigationFields(content),
|
|
59
|
-
...content.
|
|
57
|
+
...content.draft ? { draft: true } : {}
|
|
60
58
|
};
|
|
61
59
|
if (isIndex) {
|
|
62
|
-
const dirConfig = navItem.
|
|
60
|
+
const dirConfig = navItem.path ? configs[navItem.path] : void 0;
|
|
63
61
|
if (typeof dirConfig?.navigation !== "undefined" && !dirConfig.navigation) {
|
|
64
62
|
return nav;
|
|
65
63
|
}
|
|
@@ -82,14 +80,13 @@ export const buildCanonicalNavigation = (contents, configs, fields = []) => {
|
|
|
82
80
|
const canonicalKey = parentCanonicalKey(content, index);
|
|
83
81
|
parent = {
|
|
84
82
|
title: generateTitle(part),
|
|
85
|
-
_path: currentPathPart,
|
|
86
83
|
path: currentPathPart,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
file: content.file,
|
|
85
|
+
navigationKind: "folder",
|
|
86
|
+
navigationPath: currentPathPart,
|
|
90
87
|
page: false,
|
|
91
|
-
...canonicalKey ? {
|
|
92
|
-
...content.
|
|
88
|
+
...canonicalKey ? { canonicalKey } : {},
|
|
89
|
+
...content.locale ? { locale: content.locale } : {},
|
|
93
90
|
children: [],
|
|
94
91
|
...config && pickNavigationFields(config)
|
|
95
92
|
};
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import type { ContentNavigationItem, NavItem } from '../../types/content';
|
|
1
|
+
import type { ContentFileMeta, ContentNavigationItem, NavItem } from '../../types/content';
|
|
2
2
|
import { type RouteMounts } from '../localization/path';
|
|
3
3
|
export type NavigationNodeKind = 'page' | 'folder';
|
|
4
4
|
export interface CanonicalNavigationItem {
|
|
5
5
|
title: string;
|
|
6
6
|
path?: string;
|
|
7
|
-
_path?: string;
|
|
8
7
|
stem?: string;
|
|
9
8
|
page?: false;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
id?: string;
|
|
10
|
+
canonicalKey?: string;
|
|
11
|
+
locale?: string;
|
|
12
|
+
fallback?: boolean;
|
|
13
|
+
draft?: boolean;
|
|
14
|
+
file?: ContentFileMeta;
|
|
15
|
+
navigationKind?: NavigationNodeKind;
|
|
16
|
+
navigationPath?: string;
|
|
18
17
|
_collectionRoot?: string;
|
|
19
18
|
children?: CanonicalNavigationItem[];
|
|
20
19
|
[key: string]: unknown;
|
|
@@ -26,7 +25,7 @@ export interface ProjectNavigationOptions {
|
|
|
26
25
|
collection?: string;
|
|
27
26
|
canonical?: boolean;
|
|
28
27
|
}
|
|
29
|
-
export declare const getNavigationIdentity: (node: Pick<CanonicalNavigationItem, "
|
|
28
|
+
export declare const getNavigationIdentity: (node: Pick<CanonicalNavigationItem, "canonicalKey">) => string | undefined;
|
|
30
29
|
export declare const mergeCanonicalNavigation: (primary?: CanonicalNavigationItem[], fallback?: CanonicalNavigationItem[]) => CanonicalNavigationItem[];
|
|
31
30
|
export declare const markCollectionNavigationRoot: (navigation?: CanonicalNavigationItem[], collection?: string, options?: Pick<ProjectNavigationOptions, "routeMounts">) => CanonicalNavigationItem[];
|
|
32
31
|
export declare const scopeNavigationTree: (navigation?: CanonicalNavigationItem[], collection?: string) => CanonicalNavigationItem[];
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { getContentStem, normalizeContentPath, projectContentPathToLocale } from "../localization/path.js";
|
|
2
2
|
const isString = (value) => typeof value === "string" && value.length > 0;
|
|
3
3
|
export const getNavigationIdentity = (node) => {
|
|
4
|
-
if (isString(node.
|
|
5
|
-
return node.
|
|
4
|
+
if (isString(node.canonicalKey)) {
|
|
5
|
+
return node.canonicalKey;
|
|
6
6
|
}
|
|
7
7
|
return void 0;
|
|
8
8
|
};
|
|
9
9
|
const cloneFallbackNode = (node) => ({
|
|
10
10
|
...node,
|
|
11
|
-
|
|
11
|
+
fallback: true,
|
|
12
12
|
children: node.children?.map(cloneFallbackNode)
|
|
13
13
|
});
|
|
14
14
|
export const mergeCanonicalNavigation = (primary = [], fallback = []) => {
|
|
@@ -55,13 +55,13 @@ const normalizeRoutePath = (path) => {
|
|
|
55
55
|
return normalizeContentPath(path);
|
|
56
56
|
};
|
|
57
57
|
const isFolderNode = (item) => {
|
|
58
|
-
if (item.
|
|
58
|
+
if (item.navigationKind === "folder") {
|
|
59
59
|
return true;
|
|
60
60
|
}
|
|
61
|
-
if (item.
|
|
61
|
+
if (item.navigationKind === "page") {
|
|
62
62
|
return false;
|
|
63
63
|
}
|
|
64
|
-
return Boolean(item.children?.length && !item.
|
|
64
|
+
return Boolean(item.children?.length && !item.id && !item.path);
|
|
65
65
|
};
|
|
66
66
|
const matchesCollectionRootConfig = (collection, root, options) => {
|
|
67
67
|
if (!root.children?.length) {
|
|
@@ -71,7 +71,7 @@ const matchesCollectionRootConfig = (collection, root, options) => {
|
|
|
71
71
|
if (identity === collection || identity === `/${collection}`) {
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
74
|
-
const rootPath = normalizeRoutePath(root.
|
|
74
|
+
const rootPath = normalizeRoutePath(root.navigationPath || root.path);
|
|
75
75
|
if (rootPath === "/" || rootPath === `/${collection}`) {
|
|
76
76
|
return true;
|
|
77
77
|
}
|
|
@@ -102,16 +102,22 @@ export const scopeNavigationTree = (navigation = [], collection) => {
|
|
|
102
102
|
};
|
|
103
103
|
const publicFields = (item) => {
|
|
104
104
|
const {
|
|
105
|
-
children
|
|
106
|
-
path
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
_navigationPath,
|
|
105
|
+
children,
|
|
106
|
+
path,
|
|
107
|
+
stem,
|
|
108
|
+
file,
|
|
109
|
+
navigationKind,
|
|
110
|
+
navigationPath,
|
|
112
111
|
_collectionRoot,
|
|
113
112
|
...fields
|
|
114
113
|
} = item;
|
|
114
|
+
void children;
|
|
115
|
+
void path;
|
|
116
|
+
void stem;
|
|
117
|
+
void file;
|
|
118
|
+
void navigationKind;
|
|
119
|
+
void navigationPath;
|
|
120
|
+
void _collectionRoot;
|
|
115
121
|
return fields;
|
|
116
122
|
};
|
|
117
123
|
const projectNavigationItem = (item, options) => {
|
|
@@ -119,7 +125,7 @@ const projectNavigationItem = (item, options) => {
|
|
|
119
125
|
const hasChildren = Boolean(children?.length);
|
|
120
126
|
const base = {
|
|
121
127
|
...publicFields(item),
|
|
122
|
-
|
|
128
|
+
fallback: item.fallback === true
|
|
123
129
|
};
|
|
124
130
|
if (isFolderNode(item)) {
|
|
125
131
|
return {
|
|
@@ -127,20 +133,19 @@ const projectNavigationItem = (item, options) => {
|
|
|
127
133
|
...hasChildren ? { children } : {}
|
|
128
134
|
};
|
|
129
135
|
}
|
|
130
|
-
const rawPath = item.
|
|
136
|
+
const rawPath = item.navigationPath || item.path;
|
|
131
137
|
if (!rawPath) {
|
|
132
138
|
return {
|
|
133
139
|
...base,
|
|
134
140
|
...hasChildren ? { children } : {}
|
|
135
141
|
};
|
|
136
142
|
}
|
|
137
|
-
const
|
|
143
|
+
const unprefixedPath = normalizeContentPath(rawPath);
|
|
138
144
|
return {
|
|
139
145
|
...base,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
stem: item.stem || getContentStem(canonicalPath, item._file),
|
|
146
|
+
path: options.canonical ? unprefixedPath : projectContentPathToLocale(unprefixedPath, options.locale || item.locale, options.defaultLocale, options.routeMounts),
|
|
147
|
+
unprefixedPath,
|
|
148
|
+
stem: item.stem || getContentStem(unprefixedPath, item.file?.path),
|
|
144
149
|
...hasChildren ? { children } : {}
|
|
145
150
|
};
|
|
146
151
|
};
|
|
@@ -4,7 +4,7 @@ export const getNavigationItemPath = (item) => {
|
|
|
4
4
|
if (!item || item.page === false) {
|
|
5
5
|
return void 0;
|
|
6
6
|
}
|
|
7
|
-
return stringValue(item.path) || stringValue(item.
|
|
7
|
+
return stringValue(item.path) || stringValue(item.path);
|
|
8
8
|
};
|
|
9
9
|
export const resolveNavigationItem = (item) => {
|
|
10
10
|
const path = getNavigationItemPath(item);
|
|
@@ -15,16 +15,16 @@ const fieldMatches = (item, field, value) => {
|
|
|
15
15
|
if (!candidate) {
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
-
if (field === "path" || field === "
|
|
18
|
+
if (field === "path" || field === "unprefixedPath") {
|
|
19
19
|
return normalizePath(candidate) === normalizePath(value);
|
|
20
20
|
}
|
|
21
21
|
return candidate === value;
|
|
22
22
|
};
|
|
23
23
|
export const matchesNavigationItem = (item, match) => {
|
|
24
24
|
if (typeof match === "string") {
|
|
25
|
-
return fieldMatches(item, "path", match) || fieldMatches(item, "
|
|
25
|
+
return fieldMatches(item, "path", match) || fieldMatches(item, "unprefixedPath", match) || fieldMatches(item, "stem", match) || fieldMatches(item, "title", match);
|
|
26
26
|
}
|
|
27
|
-
if (match.path && !(fieldMatches(item, "path", match.path) || fieldMatches(item, "
|
|
27
|
+
if (match.path && !(fieldMatches(item, "path", match.path) || fieldMatches(item, "unprefixedPath", match.path))) {
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
30
|
if (match.stem && !fieldMatches(item, "stem", match.stem)) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export function flattenCollectionNavigation(navigation = []) {
|
|
2
2
|
return navigation.flatMap((item) => {
|
|
3
3
|
const children = item.children ? flattenCollectionNavigation(item.children) : [];
|
|
4
|
-
if (!item.
|
|
4
|
+
if (!item.unprefixedPath && !item.path) {
|
|
5
5
|
return children;
|
|
6
6
|
}
|
|
7
|
-
if (item.page === false || children.length && children.find((child) => child.
|
|
7
|
+
if (item.page === false || children.length && children.find((child) => child.unprefixedPath === item.unprefixedPath)) {
|
|
8
8
|
return children;
|
|
9
9
|
}
|
|
10
10
|
return [{ ...item, children: void 0 }, ...children];
|
|
@@ -16,7 +16,7 @@ export function createCollectionSurroundings(navigation = [], path, options = {}
|
|
|
16
16
|
const items = flattenCollectionNavigation(navigation);
|
|
17
17
|
const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
18
18
|
const index = items.findIndex((item) => {
|
|
19
|
-
const itemPath = typeof item.path === "string" ? item.path : item.
|
|
19
|
+
const itemPath = typeof item.path === "string" ? item.path : typeof item.unprefixedPath === "string" ? item.unprefixedPath : void 0;
|
|
20
20
|
if (!itemPath) {
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
@@ -28,11 +28,9 @@ const inferBacklinkFields = (source, targetCollection, runtime) => {
|
|
|
28
28
|
const targetReferenceCandidates = (doc) => {
|
|
29
29
|
const values = [
|
|
30
30
|
doc.ref,
|
|
31
|
-
doc.
|
|
32
|
-
doc.
|
|
33
|
-
doc.
|
|
34
|
-
doc._path ? doc.path : void 0,
|
|
35
|
-
doc._path ? doc.canonicalPath : void 0
|
|
31
|
+
doc.canonicalKey,
|
|
32
|
+
doc.canonicalKey ? doc.path : void 0,
|
|
33
|
+
doc.canonicalKey ? doc.unprefixedPath : void 0
|
|
36
34
|
].filter((value) => typeof value === "string" && value.length > 0).flatMap((value) => [value, normalizeReferenceValue(value)]).filter(Boolean);
|
|
37
35
|
return Array.from(new Set(values));
|
|
38
36
|
};
|
|
@@ -21,7 +21,7 @@ const explainResolution = (collection, requestedBy, normalizedBy, requestedLocal
|
|
|
21
21
|
found: Boolean(doc),
|
|
22
22
|
collection,
|
|
23
23
|
...doc?.path ? { path: doc.path } : {},
|
|
24
|
-
...doc?.
|
|
24
|
+
...doc?.unprefixedPath ? { unprefixedPath: doc.unprefixedPath } : {},
|
|
25
25
|
...doc?.ref ? { ref: doc.ref } : {},
|
|
26
26
|
...resolvedLocale ? { locale: resolvedLocale } : {}
|
|
27
27
|
},
|
|
@@ -4,7 +4,7 @@ import type { RuntimeContentConfig } from './context';
|
|
|
4
4
|
/**
|
|
5
5
|
* Decorate a raw parsed document with route metadata and locale paths.
|
|
6
6
|
*
|
|
7
|
-
* `localizePageResult` already attaches `path`, `
|
|
7
|
+
* `localizePageResult` already attaches `path`, `unprefixedPath`, `locale`,
|
|
8
8
|
* `defaultLocale`, `variants`, and `localePaths`. This helper additionally
|
|
9
9
|
* fills non-translated locales with fallback paths so app switchers can render
|
|
10
10
|
* all configured languages without another query.
|
|
@@ -20,14 +20,11 @@ export const decorateLocalizedDocument = (doc, collection, runtime, requestedLoc
|
|
|
20
20
|
const { locales, defaultLocale, routeMounts, hasLocaleConfig } = collectionLocaleConfig(collection, runtime);
|
|
21
21
|
const page = hasLocaleConfig ? doc : {
|
|
22
22
|
...doc,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
_requestedLocale: void 0,
|
|
26
|
-
_variantPaths: void 0,
|
|
27
|
-
_availableLocales: []
|
|
23
|
+
locale: "",
|
|
24
|
+
resolved: { availableLocales: [] }
|
|
28
25
|
};
|
|
29
26
|
const result = localizePageResult(page, hasLocaleConfig ? requestedLocale : void 0, defaultLocale, locales, routeMounts);
|
|
30
|
-
const fallbackLocale = doc.
|
|
27
|
+
const fallbackLocale = doc.resolved?.locale || requestedLocale || defaultLocale;
|
|
31
28
|
result.localePaths = decorateLocalePathsWithFallbacks(result.localePaths, locales, fallbackLocale, defaultLocale, routeMounts);
|
|
32
29
|
return result;
|
|
33
30
|
};
|
|
@@ -4,7 +4,7 @@ import type { ContentTreeItem, LocalizedContentDocument, NeighborsOptions, Neigh
|
|
|
4
4
|
import type { ContentQueryContext } from './context';
|
|
5
5
|
export declare const navigationSelectFields: (fields?: ReadonlyArray<string> | undefined) => string[];
|
|
6
6
|
type OneResolver = <H extends ContentCollectionHandle | string>(context: ContentQueryContext, handle: H, options: OneOptions<H>) => Promise<LocalizedContentDocument<ParsedContent> | null>;
|
|
7
|
-
type TreeResolver = <H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H, options
|
|
7
|
+
type TreeResolver = <H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H, options: Omit<TreeOptions<H>, 'fields'> & {
|
|
8
8
|
fields?: Fields;
|
|
9
9
|
}) => Promise<unknown[]>;
|
|
10
10
|
export declare function resolveTree<H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H, options?: Omit<TreeOptions<H>, 'fields'> & {
|
|
@@ -3,12 +3,12 @@ import { ensureCollectionName } from "./handles.js";
|
|
|
3
3
|
import { isCollectionRouteRoot, isNavigationRootPath } from "./localized-docs.js";
|
|
4
4
|
import { resolveFallback } from "./locale-options.js";
|
|
5
5
|
const NAVIGATION_INTERNAL_FIELDS = [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
6
|
+
"id",
|
|
7
|
+
"path",
|
|
8
|
+
"file",
|
|
9
|
+
"canonicalKey",
|
|
10
|
+
"locale",
|
|
11
|
+
"draft",
|
|
12
12
|
"navigation",
|
|
13
13
|
"title"
|
|
14
14
|
];
|
|
@@ -50,8 +50,8 @@ export async function resolveNeighbors(context, one, tree, handle, options) {
|
|
|
50
50
|
const walk = (nodes) => {
|
|
51
51
|
for (const node of nodes) {
|
|
52
52
|
const n = node;
|
|
53
|
-
if (n.path
|
|
54
|
-
flat.push({ path: n.path ||
|
|
53
|
+
if (n.path) {
|
|
54
|
+
flat.push({ path: n.path || "", item: node });
|
|
55
55
|
}
|
|
56
56
|
if (Array.isArray(n.children)) walk(n.children);
|
|
57
57
|
}
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
import { collectTopLevelReferenceFieldsByTarget } from "../../core/references/schema";
|
|
2
2
|
import { ensureCollectionName } from "./handles.js";
|
|
3
3
|
const LOCALIZED_DOC_INTERNAL_FIELDS = [
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"_requestedLocale",
|
|
11
|
-
"_fallback",
|
|
12
|
-
"_availableLocales",
|
|
13
|
-
"_variantPaths",
|
|
14
|
-
"_requestedPath",
|
|
15
|
-
"_requestedRoute",
|
|
16
|
-
"_requestedRef",
|
|
17
|
-
"_extension"
|
|
4
|
+
"id",
|
|
5
|
+
"path",
|
|
6
|
+
"file",
|
|
7
|
+
"canonicalKey",
|
|
8
|
+
"locale",
|
|
9
|
+
"resolved"
|
|
18
10
|
];
|
|
19
11
|
const wildcardReferenceTarget = "*";
|
|
20
12
|
const isRecord = (value) => {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { ParsedContent } from '../../types/content';
|
|
18
18
|
import type { ContentCollectionHandle } from '../../types/config';
|
|
19
|
-
import type { BacklinkSource, BacklinksOptions, BacklinksResult, ContentTreeItem, DocumentFromHandle, ManyOptions, LocalizedDoc, NeighborsOptions, NeighborsResult, OneOptions, PopulateSpec, PopulateFromOptions, PopulatedDocument, PaginationOptions, PaginationResult, ResolveOneOptions, ResolveOneResult, TreeOptions, ContentVariant, VariantsOptions } from '../../types/query';
|
|
19
|
+
import type { BacklinkSource, BacklinksOptions, BacklinksResult, ContentTreeItem, DocumentFromHandle, ManyOptions, LocalizedDoc, NeighborsOptions, NeighborsResult, OneOptions, OptionsArg, PopulateSpec, PopulateFromOptions, PopulatedDocument, PaginationOptions, PaginationResult, ResolveOneOptions, ResolveOneResult, TreeOptions, ContentVariant, VariantsOptions } from '../../types/query';
|
|
20
20
|
import type { ContentQueryContext } from './context';
|
|
21
21
|
export type { ContentQueryContext, ContentQueryEndpoint, RuntimeContentConfig } from './context';
|
|
22
22
|
export { navigationSelectFields } from './navigation';
|
|
@@ -31,7 +31,7 @@ export declare function one<const H extends ContentCollectionHandle | string, O
|
|
|
31
31
|
/**
|
|
32
32
|
* Resolve a list of documents matching the filter. Always returns an array.
|
|
33
33
|
*/
|
|
34
|
-
export declare function many<const H extends ContentCollectionHandle | string, O extends ManyOptions<H, PopulateSpec | undefined>>(context: ContentQueryContext, handle: H,
|
|
34
|
+
export declare function many<const H extends ContentCollectionHandle | string, O extends ManyOptions<H, PopulateSpec | undefined>>(context: ContentQueryContext, handle: H, ...args: OptionsArg<H, O>): Promise<Array<LocalizedDoc<PopulatedDocument<DocumentFromHandle<H>, PopulateFromOptions<O>>>>>;
|
|
35
35
|
/**
|
|
36
36
|
* Resolve one page of documents and preserve the query envelope metadata.
|
|
37
37
|
*/
|
|
@@ -62,9 +62,9 @@ export declare function variants<H extends ContentCollectionHandle | string>(con
|
|
|
62
62
|
* fallback locale's path). This matches legacy navigation semantics —
|
|
63
63
|
* sidebars are inherently lossy when filtered too strictly.
|
|
64
64
|
*/
|
|
65
|
-
export declare function tree<H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H,
|
|
65
|
+
export declare function tree<H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H, ...args: OptionsArg<H, Omit<TreeOptions<H>, 'fields'> & {
|
|
66
66
|
fields?: Fields;
|
|
67
|
-
}): Promise<ContentTreeItem<H extends {
|
|
67
|
+
}>): Promise<ContentTreeItem<H extends {
|
|
68
68
|
__schema: {
|
|
69
69
|
_output: infer O;
|
|
70
70
|
};
|
|
@@ -10,7 +10,8 @@ export async function resolveOne(context, handle, options) {
|
|
|
10
10
|
export async function one(context, handle, options) {
|
|
11
11
|
return resolveDocumentOnly(context, handle, options);
|
|
12
12
|
}
|
|
13
|
-
export async function many(context, handle,
|
|
13
|
+
export async function many(context, handle, ...args) {
|
|
14
|
+
const options = args[0] ?? {};
|
|
14
15
|
return resolveManyDocuments(context, one, handle, options);
|
|
15
16
|
}
|
|
16
17
|
export async function paginate(context, handle, options) {
|
|
@@ -22,7 +23,8 @@ export async function backlinks(context, targetHandle, options) {
|
|
|
22
23
|
export async function variants(context, handle, options) {
|
|
23
24
|
return resolveVariants(context, one, handle, options);
|
|
24
25
|
}
|
|
25
|
-
export async function tree(context, handle,
|
|
26
|
+
export async function tree(context, handle, ...args) {
|
|
27
|
+
const options = args[0] ?? {};
|
|
26
28
|
return resolveTree(context, handle, options);
|
|
27
29
|
}
|
|
28
30
|
export async function neighbors(context, handle, options) {
|
|
@@ -15,14 +15,14 @@ export async function resolveVariants(context, one, handle, options) {
|
|
|
15
15
|
fallback: true
|
|
16
16
|
});
|
|
17
17
|
if (!seed) return [];
|
|
18
|
-
const
|
|
18
|
+
const localePaths = seed.localePaths || {};
|
|
19
19
|
const sourceLocale = seed.locale || defaultLocale || "";
|
|
20
20
|
return requestedLocales.map((locale) => {
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
21
|
+
const entry = localePaths[locale];
|
|
22
|
+
if (entry?.translated) {
|
|
23
23
|
return {
|
|
24
24
|
locale,
|
|
25
|
-
path:
|
|
25
|
+
path: entry.path,
|
|
26
26
|
translated: true
|
|
27
27
|
};
|
|
28
28
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const itemPath = (item) => item.path || item.
|
|
2
|
-
const searchGroupId = (item, depth, index) => `content-search-group:${String(item.
|
|
1
|
+
const itemPath = (item) => item.path || item.path;
|
|
2
|
+
const searchGroupId = (item, depth, index) => `content-search-group:${String(item.canonicalKey || item.stem || `${depth}:${index}`)}`;
|
|
3
3
|
export function createContentSearchNavigation(items = [], depth = 0) {
|
|
4
4
|
return items.map((item, index) => {
|
|
5
5
|
const children = item.children ? createContentSearchNavigation(item.children, depth + 1) : [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ParsedContent } from '../../types/content';
|
|
2
2
|
import type { ContentCollectionSearchSectionsOptions, ContentSearchSection } from '../../types/query';
|
|
3
|
-
type SearchablePage = Pick<ParsedContent, '
|
|
3
|
+
type SearchablePage = Pick<ParsedContent, 'path' | 'title' | 'description' | 'body'> & Record<string, unknown>;
|
|
4
4
|
/**
|
|
5
5
|
* Backing option type for search-section generation.
|
|
6
6
|
*
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ContentSitemapEntry } from '../../types/query';
|
|
2
2
|
type ContentLikePage = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
path?: string;
|
|
4
|
+
collection?: string;
|
|
5
|
+
canonicalKey?: string;
|
|
6
|
+
locale?: string;
|
|
7
|
+
draft?: boolean;
|
|
8
8
|
sitemap?: unknown;
|
|
9
9
|
body?: unknown;
|
|
10
10
|
image?: unknown;
|
|
@@ -123,25 +123,25 @@ export async function queryCollectionsSitemapEntriesData(runtime, loaders, optio
|
|
|
123
123
|
const collectionPages = await loaders.loadCollectionPages(collection);
|
|
124
124
|
return collectionPages.map((page) => ({
|
|
125
125
|
...page,
|
|
126
|
-
|
|
126
|
+
collection: page.collection || collection
|
|
127
127
|
}));
|
|
128
128
|
}))).flat().filter((page) => {
|
|
129
129
|
if (page.sitemap === false) {
|
|
130
130
|
return false;
|
|
131
131
|
}
|
|
132
|
-
return shouldIncludeDrafts || !page.
|
|
132
|
+
return shouldIncludeDrafts || !page.draft;
|
|
133
133
|
});
|
|
134
134
|
const uniquePages = Array.from(new Map(
|
|
135
135
|
pages.map((page) => [
|
|
136
|
-
`${page.
|
|
136
|
+
`${page.collection || ""}:${page.canonicalKey || page.path || ""}`,
|
|
137
137
|
page
|
|
138
138
|
])
|
|
139
139
|
).values());
|
|
140
140
|
const rawEntries = await Promise.all(uniquePages.map(async (page) => {
|
|
141
|
-
if (!page.
|
|
141
|
+
if (!page.path || !page.collection) {
|
|
142
142
|
return [];
|
|
143
143
|
}
|
|
144
|
-
const meta = await loaders.loadRouteMeta(page.
|
|
144
|
+
const meta = await loaders.loadRouteMeta(page.collection, page.path, page.locale);
|
|
145
145
|
if (!meta) {
|
|
146
146
|
return [];
|
|
147
147
|
}
|
|
@@ -149,7 +149,7 @@ export async function queryCollectionsSitemapEntriesData(runtime, loaders, optio
|
|
|
149
149
|
const localizedVariants = variants.filter((variant) => variant.locale);
|
|
150
150
|
const alternatives = localizedVariants.length > 1 ? buildAlternatives(siteUrl, meta.defaultLocale, localeToLanguage, variants) : void 0;
|
|
151
151
|
return await Promise.all(variants.map(async (variant) => {
|
|
152
|
-
const variantPage = await loaders.loadPage(page.
|
|
152
|
+
const variantPage = await loaders.loadPage(page.collection, variant.path, variant.locale);
|
|
153
153
|
const images = toPageSitemapImages(
|
|
154
154
|
siteUrl,
|
|
155
155
|
variantPage ? { ...page, ...variantPage } : page,
|