@lupinum/ginko-content 0.3.1 → 0.3.3
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/dist/core/content/graph.d.ts +15 -6
- package/dist/core/content/graph.js +20 -2
- package/dist/features/validation/links.js +4 -4
- package/dist/module.json +1 -1
- package/dist/module.mjs +43 -10
- package/dist/runtime/app/composables/query-api.js +8 -2
- package/dist/runtime/app/composables/utils.d.ts +7 -7
- package/dist/runtime/app/composables/utils.js +12 -29
- package/dist/runtime/app/plugins/hot-reload.d.ts +4 -0
- package/dist/runtime/app/plugins/hot-reload.js +12 -4
- package/dist/storage/references.js +5 -18
- package/dist/types/virtual.d.ts +1 -0
- package/dist/web-types.json +1 -1
- package/package.json +1 -1
- package/dist/runtime/app/composables/hot-reload.d.ts +0 -5
- package/dist/runtime/app/composables/hot-reload.js +0 -15
|
@@ -18,10 +18,9 @@
|
|
|
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.
|
|
21
|
-
* - **`referenceTargets`**:
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* key.
|
|
21
|
+
* - **`referenceTargets`**: every unambiguous shape the user might write
|
|
22
|
+
* (canonical name, locale-prefixed path, short slug) pre-resolved to its
|
|
23
|
+
* canonical key and owning collection.
|
|
25
24
|
*
|
|
26
25
|
* The graph is rebuilt from scratch on every request in dev; in production
|
|
27
26
|
* it is memoized per-request via `memoizeRuntimeValue(event, 'graph', ...)`.
|
|
@@ -32,6 +31,10 @@ import type { ContentVariantIdentity, ResolvedVariant } from '../../types/runtim
|
|
|
32
31
|
export interface ContentGraphVariant extends ContentVariantIdentity {
|
|
33
32
|
document: ParsedContent;
|
|
34
33
|
}
|
|
34
|
+
export interface ContentGraphReferenceTarget {
|
|
35
|
+
readonly canonicalKey: string;
|
|
36
|
+
readonly collection: string;
|
|
37
|
+
}
|
|
35
38
|
export interface ContentGraph {
|
|
36
39
|
documents: ParsedContent[];
|
|
37
40
|
/** id → document. Keys include the locale suffix; one entry per source file. */
|
|
@@ -52,8 +55,8 @@ export interface ContentGraph {
|
|
|
52
55
|
byRef: Record<string, string>;
|
|
53
56
|
/** navigation path → `{ [locale]: document }`. Drives `.navigation.yml` merging. */
|
|
54
57
|
byNavigationPath: Record<string, Record<string, ParsedContent>>;
|
|
55
|
-
/** Every user-writable reference shape
|
|
56
|
-
referenceTargets: Map<string,
|
|
58
|
+
/** Every unambiguous user-writable reference shape with its collection scope intact. */
|
|
59
|
+
referenceTargets: Map<string, ContentGraphReferenceTarget>;
|
|
57
60
|
/** Exact collection-scoped user-writable reference targets. */
|
|
58
61
|
referenceTargetsByCollection: Record<string, Map<string, string>>;
|
|
59
62
|
}
|
|
@@ -134,6 +137,12 @@ export declare const resolveGraphRouteVariant: (graph: ContentGraph, routePath:
|
|
|
134
137
|
* leak through.
|
|
135
138
|
*/
|
|
136
139
|
export declare const resolveGraphCanonicalKey: (graph: ContentGraph, identity: string, collection?: string) => string | null;
|
|
140
|
+
/**
|
|
141
|
+
* Resolve a user-authored reference without discarding the collection that
|
|
142
|
+
* made the identity unambiguous. Canonical keys are collection-scoped, so
|
|
143
|
+
* callers that subsequently resolve a locale variant must carry both values.
|
|
144
|
+
*/
|
|
145
|
+
export declare const resolveGraphReferenceTarget: (graph: ContentGraph, identity: string, collection?: string) => ContentGraphReferenceTarget | null;
|
|
137
146
|
export declare const resolveGraphCollectionLocales: (graph: ContentGraph, identity: string, collection?: string) => ContentLocaleEntry[];
|
|
138
147
|
export declare const selectGraphDocuments: (graph: ContentGraph, options?: {
|
|
139
148
|
collection?: string;
|
|
@@ -100,7 +100,10 @@ export const buildContentGraph = (documents, options = {}) => {
|
|
|
100
100
|
}
|
|
101
101
|
const referenceTargets = /* @__PURE__ */ new Map();
|
|
102
102
|
for (const [identity, collections] of referenceTargetCollections) {
|
|
103
|
-
if (collections.length
|
|
103
|
+
if (collections.length !== 1) continue;
|
|
104
|
+
const collection = collections[0];
|
|
105
|
+
const canonicalKey = referenceTargetsByCollection[collection].get(identity);
|
|
106
|
+
if (canonicalKey) referenceTargets.set(identity, { canonicalKey, collection });
|
|
104
107
|
}
|
|
105
108
|
return {
|
|
106
109
|
documents,
|
|
@@ -180,9 +183,24 @@ export const resolveGraphCanonicalKey = (graph, identity, collection) => {
|
|
|
180
183
|
if (collection && !(graph.byCollection[collection] || []).length) {
|
|
181
184
|
return null;
|
|
182
185
|
}
|
|
183
|
-
const targetCanonicalKey = collection ? graph.referenceTargetsByCollection[collection]?.get(normalizedIdentity) : graph.referenceTargets.get(normalizedIdentity);
|
|
186
|
+
const targetCanonicalKey = collection ? graph.referenceTargetsByCollection[collection]?.get(normalizedIdentity) : graph.referenceTargets.get(normalizedIdentity)?.canonicalKey;
|
|
184
187
|
return targetCanonicalKey && hasCollectionVariant(targetCanonicalKey) ? targetCanonicalKey : null;
|
|
185
188
|
};
|
|
189
|
+
export const resolveGraphReferenceTarget = (graph, identity, collection) => {
|
|
190
|
+
const normalizedIdentity = normalizeReferenceValue(identity);
|
|
191
|
+
if (!normalizedIdentity) return null;
|
|
192
|
+
if (collection) {
|
|
193
|
+
const canonicalKey = resolveGraphCanonicalKey(graph, normalizedIdentity, collection);
|
|
194
|
+
return canonicalKey ? { canonicalKey, collection } : null;
|
|
195
|
+
}
|
|
196
|
+
const canonicalVariants = graph.byCanonical[normalizedIdentity];
|
|
197
|
+
if (canonicalVariants) {
|
|
198
|
+
const targetCollection = Object.values(canonicalVariants)[0]?.document.collection || "content";
|
|
199
|
+
return { canonicalKey: normalizedIdentity, collection: targetCollection };
|
|
200
|
+
}
|
|
201
|
+
const target = graph.referenceTargets.get(normalizedIdentity);
|
|
202
|
+
return target && getGraphCanonicalVariants(graph, target.canonicalKey, target.collection) ? target : null;
|
|
203
|
+
};
|
|
186
204
|
export const resolveGraphCollectionLocales = (graph, identity, collection) => {
|
|
187
205
|
const canonicalKey = resolveGraphCanonicalKey(graph, identity, collection);
|
|
188
206
|
if (!canonicalKey) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getGraphCanonicalVariants, resolveGraphReferenceTarget } from "../../core/content/graph.js";
|
|
2
2
|
import { parseRefLink } from "../../core/references/resolve.js";
|
|
3
3
|
const normalizePath = (path) => {
|
|
4
4
|
const normalized = path.replace(/\/{2,}/g, "/").replace(/\/$/, "");
|
|
@@ -98,11 +98,11 @@ export const validateContentLinks = async (documents, options) => {
|
|
|
98
98
|
}
|
|
99
99
|
continue;
|
|
100
100
|
}
|
|
101
|
-
const
|
|
102
|
-
const variants =
|
|
101
|
+
const target = resolveGraphReferenceTarget(options.graph, parsedRef.ref);
|
|
102
|
+
const variants = target ? getGraphCanonicalVariants(options.graph, target.canonicalKey, target.collection) : void 0;
|
|
103
103
|
const variant = variants?.[document.locale || ""] || variants?.[options.defaultLocale || ""] || Object.values(variants || {})[0];
|
|
104
104
|
const targetDocument2 = variant ? options.graph.byId[variant.contentId] : void 0;
|
|
105
|
-
const targetRoute = targetDocument2 ? routeByIdentity.get(identityKey(
|
|
105
|
+
const targetRoute = target && targetDocument2 ? routeByIdentity.get(identityKey(target.collection, target.canonicalKey, variant?.locale)) : void 0;
|
|
106
106
|
if (!targetRoute) {
|
|
107
107
|
addBroken(sourceFile, authoredValue);
|
|
108
108
|
continue;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -4,7 +4,8 @@ import { readFile, readdir, rm } from 'node:fs/promises';
|
|
|
4
4
|
import { join as join$1, basename, resolve as resolve$1, dirname, isAbsolute as isAbsolute$1 } from 'node:path';
|
|
5
5
|
import { buildResolvedContentContract } from '../dist/cms-contract/index.js';
|
|
6
6
|
import fs, { existsSync } from 'fs';
|
|
7
|
-
import {
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import { join, relative, isAbsolute, resolve } from 'pathe';
|
|
8
9
|
import jiti from 'jiti';
|
|
9
10
|
import { genSafeVariableName, genImport } from 'knitwork';
|
|
10
11
|
import { hash } from 'ohash';
|
|
@@ -29,7 +30,7 @@ import { createRouterMatcher } from 'vue-router';
|
|
|
29
30
|
import { globby } from 'globby';
|
|
30
31
|
|
|
31
32
|
const name = "@lupinum/ginko-content";
|
|
32
|
-
const version = "0.3.
|
|
33
|
+
const version = "0.3.3";
|
|
33
34
|
const peerDependencies = {
|
|
34
35
|
nuxt: ">=4.4.7 <5"};
|
|
35
36
|
|
|
@@ -40,6 +41,17 @@ const CONFIG_FILES = [
|
|
|
40
41
|
"content.config.mjs",
|
|
41
42
|
"content.config.cjs"
|
|
42
43
|
];
|
|
44
|
+
const isLocalModule = (filename, rootDir) => {
|
|
45
|
+
const localPath = relative(rootDir, filename);
|
|
46
|
+
return Boolean(localPath) && !localPath.startsWith("../") && !isAbsolute(localPath) && !localPath.split("/").includes("node_modules");
|
|
47
|
+
};
|
|
48
|
+
const clearLocalNativeModules = (cache, rootDir) => {
|
|
49
|
+
for (const [id, entry] of Object.entries(cache)) {
|
|
50
|
+
if (entry && isLocalModule(entry.filename, rootDir)) {
|
|
51
|
+
Reflect.deleteProperty(cache, id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
43
55
|
function resolveContentConfigPath(nuxt) {
|
|
44
56
|
return CONFIG_FILES.map((name) => join(nuxt.options.rootDir, name)).find((path) => existsSync(path));
|
|
45
57
|
}
|
|
@@ -48,8 +60,21 @@ async function loadContentConfig(nuxt) {
|
|
|
48
60
|
if (!configPath) {
|
|
49
61
|
return {};
|
|
50
62
|
}
|
|
51
|
-
const
|
|
52
|
-
|
|
63
|
+
const nativeRequire = createRequire(configPath);
|
|
64
|
+
clearLocalNativeModules(nativeRequire.cache, nuxt.options.rootDir);
|
|
65
|
+
const importer = jiti(nuxt.options.rootDir, {
|
|
66
|
+
interopDefault: true,
|
|
67
|
+
// Nuxt reloads module setup in the same process for `options.watch`
|
|
68
|
+
// changes. The authored config and its imports must not come from the
|
|
69
|
+
// previous setup's module cache.
|
|
70
|
+
moduleCache: false
|
|
71
|
+
});
|
|
72
|
+
let loaded;
|
|
73
|
+
try {
|
|
74
|
+
loaded = importer(configPath);
|
|
75
|
+
} finally {
|
|
76
|
+
clearLocalNativeModules(nativeRequire.cache, nuxt.options.rootDir);
|
|
77
|
+
}
|
|
53
78
|
return loaded?.default || loaded || {};
|
|
54
79
|
}
|
|
55
80
|
|
|
@@ -193,11 +218,8 @@ const registerContentDevRuntime = (nuxt, options, contentContext) => {
|
|
|
193
218
|
const isIgnored = makeIgnored(contentContext.ignores);
|
|
194
219
|
let viteServer;
|
|
195
220
|
if (options.watch !== false) {
|
|
196
|
-
nuxt.
|
|
197
|
-
|
|
198
|
-
nuxt.options.vite.plugins.push({
|
|
199
|
-
name: "ginko-content-hmr",
|
|
200
|
-
configureServer(server) {
|
|
221
|
+
nuxt.hook("vite:serverCreated", (server, environment) => {
|
|
222
|
+
if (environment.isClient) {
|
|
201
223
|
viteServer = server;
|
|
202
224
|
}
|
|
203
225
|
});
|
|
@@ -1868,6 +1890,12 @@ const module$1 = defineNuxtModule({
|
|
|
1868
1890
|
noExternal: runtimeInlineDependencies
|
|
1869
1891
|
});
|
|
1870
1892
|
const contentConfigPath = resolveContentConfigPath(nuxt);
|
|
1893
|
+
if (nuxt.options.dev && options.watch !== false && contentConfigPath) {
|
|
1894
|
+
nuxt.options.watch ||= [];
|
|
1895
|
+
if (!nuxt.options.watch.includes(contentConfigPath)) {
|
|
1896
|
+
nuxt.options.watch.push(contentConfigPath);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1871
1899
|
const appContentConfig = await loadContentConfig(nuxt);
|
|
1872
1900
|
if (!contentConfigPath || !appContentConfig.collections || !Object.keys(appContentConfig.collections).length) {
|
|
1873
1901
|
throw new Error("@lupinum/ginko-content requires a content.config.ts with at least one collection. Define collections with defineContentConfig({ collections: { ... } }).");
|
|
@@ -1935,7 +1963,12 @@ const module$1 = defineNuxtModule({
|
|
|
1935
1963
|
search: resolvedSearch,
|
|
1936
1964
|
validation: options.validation || "report"
|
|
1937
1965
|
};
|
|
1938
|
-
|
|
1966
|
+
const contentCacheDir = resolve$1(nuxt.options.buildDir, "content-cache");
|
|
1967
|
+
if (nuxt.options.dev) {
|
|
1968
|
+
await rm(contentCacheDir, { recursive: true, force: true });
|
|
1969
|
+
} else {
|
|
1970
|
+
await rm(resolve$1(contentCacheDir, "validation.json"), { force: true });
|
|
1971
|
+
}
|
|
1939
1972
|
const layers = nuxt.options._layers || [{ cwd: nuxt.options.rootDir, config: {} }];
|
|
1940
1973
|
const nitroPublicAssets = nuxt.options.nitro?.publicAssets || [];
|
|
1941
1974
|
contentContext.validationPublicAssets = await collectContentValidationPublicAssets({
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createPrerenderPathAdder,
|
|
3
|
+
fetchContentApi,
|
|
4
|
+
getContentApiFetcher,
|
|
5
|
+
getPreviewToken
|
|
6
|
+
} from "./utils.js";
|
|
2
7
|
import { getContentRuntime } from "./runtime.js";
|
|
3
8
|
import {
|
|
4
9
|
backlinks as backlinksWithContext,
|
|
@@ -13,13 +18,14 @@ export const createClientContentQueryContext = () => {
|
|
|
13
18
|
const runtime = getContentRuntime();
|
|
14
19
|
const fetcher = getContentApiFetcher();
|
|
15
20
|
const previewToken = getPreviewToken() ?? null;
|
|
21
|
+
const addPrerenderPath = createPrerenderPathAdder();
|
|
16
22
|
return {
|
|
17
23
|
runtime,
|
|
18
24
|
transport: async (endpoint, params) => {
|
|
19
25
|
return await fetchContentApi(
|
|
20
26
|
endpoint,
|
|
21
27
|
params,
|
|
22
|
-
{ fetcher, runtime, previewToken }
|
|
28
|
+
{ fetcher, runtime, previewToken, addPrerenderPath }
|
|
23
29
|
);
|
|
24
30
|
}
|
|
25
31
|
};
|
|
@@ -7,17 +7,17 @@ interface ContentRuntimeShape {
|
|
|
7
7
|
}
|
|
8
8
|
export declare const withContentBase: (url: string) => string;
|
|
9
9
|
export declare const navigationDisabled: () => never;
|
|
10
|
-
export declare const
|
|
10
|
+
export declare const createPrerenderPathAdder: () => ((path: string) => void) | undefined;
|
|
11
11
|
export type ContentApiEndpoint = 'query' | 'navigation';
|
|
12
12
|
export type ContentApiFetcher = (request: string, init?: Record<string, unknown>) => Promise<unknown>;
|
|
13
13
|
export declare const getPreviewToken: () => any;
|
|
14
14
|
export declare const getContentApiFetcher: (fetcher?: ContentApiFetcher) => ContentApiFetcher;
|
|
15
|
-
export declare const buildContentApiPath: (endpoint: ContentApiEndpoint, params: ContentProviderQueryInput, runtime
|
|
15
|
+
export declare const buildContentApiPath: (endpoint: ContentApiEndpoint, params: ContentProviderQueryInput, runtime: ContentRuntimeShape) => string;
|
|
16
16
|
export declare const isHtmlFallbackResponse: (data: unknown) => data is string;
|
|
17
|
-
export declare function fetchContentApi<T>(endpoint: ContentApiEndpoint, params: ContentProviderQueryInput, options
|
|
18
|
-
fetcher
|
|
19
|
-
runtime
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
export declare function fetchContentApi<T>(endpoint: ContentApiEndpoint, params: ContentProviderQueryInput, options: {
|
|
18
|
+
fetcher: ContentApiFetcher;
|
|
19
|
+
runtime: ContentRuntimeShape;
|
|
20
|
+
previewToken: string | null;
|
|
21
|
+
addPrerenderPath?: (path: string) => void;
|
|
22
22
|
}): Promise<T>;
|
|
23
23
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { withBase } from "ufo";
|
|
2
2
|
import { hash } from "ohash";
|
|
3
|
-
import { useRequestEvent, useRequestFetch } from "#imports";
|
|
3
|
+
import { tryUseNuxtApp, useRequestEvent, useRequestFetch } from "#imports";
|
|
4
4
|
import { encodeQueryParams } from "../../utils/query.js";
|
|
5
5
|
import { useContentPreview } from "./preview.js";
|
|
6
6
|
import { getContentRuntime } from "./runtime.js";
|
|
@@ -11,13 +11,6 @@ export const navigationDisabled = () => {
|
|
|
11
11
|
console.warn("Learn more in the Ginko navigation documentation.");
|
|
12
12
|
throw new Error("Navigation is only accessible when you enable it in module options.");
|
|
13
13
|
};
|
|
14
|
-
const lookupRequestEvent = () => {
|
|
15
|
-
try {
|
|
16
|
-
return useRequestEvent();
|
|
17
|
-
} catch {
|
|
18
|
-
return void 0;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
14
|
const addPathToEvent = (event, path) => {
|
|
22
15
|
event.node.res.setHeader(
|
|
23
16
|
"x-nitro-prerender",
|
|
@@ -27,16 +20,12 @@ const addPathToEvent = (event, path) => {
|
|
|
27
20
|
].filter(Boolean).join(",")
|
|
28
21
|
);
|
|
29
22
|
};
|
|
30
|
-
const createPrerenderPathAdder = () => {
|
|
31
|
-
|
|
23
|
+
export const createPrerenderPathAdder = () => {
|
|
24
|
+
if (import.meta.dev || !import.meta.server) return void 0;
|
|
25
|
+
const nuxtApp = tryUseNuxtApp();
|
|
26
|
+
const event = nuxtApp ? useRequestEvent(nuxtApp) : void 0;
|
|
32
27
|
return event ? (path) => addPathToEvent(event, path) : void 0;
|
|
33
28
|
};
|
|
34
|
-
export const addPrerenderPath = (path) => {
|
|
35
|
-
const event = lookupRequestEvent();
|
|
36
|
-
if (event) {
|
|
37
|
-
addPathToEvent(event, path);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
29
|
export const getPreviewToken = () => useContentPreview().getPreviewToken();
|
|
41
30
|
export const getContentApiFetcher = (fetcher) => {
|
|
42
31
|
if (fetcher) {
|
|
@@ -48,32 +37,26 @@ export const getContentApiFetcher = (fetcher) => {
|
|
|
48
37
|
return $fetch;
|
|
49
38
|
};
|
|
50
39
|
export const buildContentApiPath = (endpoint, params, runtime) => {
|
|
51
|
-
const content = runtime || readContentRuntime();
|
|
52
40
|
const encodedParams = encodeQueryParams(params);
|
|
53
|
-
const requestKey = import.meta.dev ? "_" : `${hash(params)}.${
|
|
54
|
-
return withBase(`/${endpoint}/${requestKey}/${encodedParams}.json`,
|
|
41
|
+
const requestKey = import.meta.dev ? "_" : `${hash(params)}.${runtime.integrity}`;
|
|
42
|
+
return withBase(`/${endpoint}/${requestKey}/${encodedParams}.json`, runtime.api.baseURL);
|
|
55
43
|
};
|
|
56
44
|
export const isHtmlFallbackResponse = (data) => {
|
|
57
45
|
return typeof data === "string" && data.startsWith("<!DOCTYPE html>");
|
|
58
46
|
};
|
|
59
|
-
export async function fetchContentApi(endpoint, params, options
|
|
47
|
+
export async function fetchContentApi(endpoint, params, options) {
|
|
60
48
|
const apiPath = buildContentApiPath(endpoint, params, options.runtime);
|
|
61
|
-
const
|
|
62
|
-
const addPrerenderPathOnSuccess = !import.meta.dev && import.meta.server ? createPrerenderPathAdder() : void 0;
|
|
63
|
-
const fetcher = getContentApiFetcher(options.fetcher);
|
|
64
|
-
const data = await fetcher(apiPath, {
|
|
49
|
+
const data = await options.fetcher(apiPath, {
|
|
65
50
|
method: "GET",
|
|
66
51
|
responseType: "json",
|
|
67
|
-
...previewToken ? { headers: { "x-nuxt-content-preview": previewToken } } : {}
|
|
52
|
+
...options.previewToken ? { headers: { "x-nuxt-content-preview": options.previewToken } } : {}
|
|
68
53
|
});
|
|
69
54
|
if (isHtmlFallbackResponse(data)) {
|
|
70
|
-
throw new Error(
|
|
55
|
+
throw new Error("Not found");
|
|
71
56
|
}
|
|
72
57
|
if (data === void 0 || data === null) {
|
|
73
58
|
throw new TypeError("Invalid content API response: expected a non-empty JSON body.");
|
|
74
59
|
}
|
|
75
|
-
|
|
76
|
-
addPrerenderPathOnSuccess?.(apiPath);
|
|
77
|
-
}
|
|
60
|
+
options.addPrerenderPath?.(apiPath);
|
|
78
61
|
return data;
|
|
79
62
|
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
type ContentHot = {
|
|
2
|
+
on: (event: 'ginko-content:update', callback: (data: unknown) => void) => void;
|
|
3
|
+
};
|
|
4
|
+
export declare function registerContentHotReload(hot: ContentHot | undefined, isClient: boolean, refresh: () => unknown): void;
|
|
1
5
|
declare const _default: any;
|
|
2
6
|
export default _default;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { defineNuxtPlugin } from "#imports";
|
|
2
|
-
export
|
|
3
|
-
if (
|
|
4
|
-
|
|
1
|
+
import { defineNuxtPlugin, refreshNuxtData } from "#imports";
|
|
2
|
+
export function registerContentHotReload(hot, isClient, refresh) {
|
|
3
|
+
if (!hot || !isClient) {
|
|
4
|
+
return;
|
|
5
5
|
}
|
|
6
|
+
hot.on("ginko-content:update", (data) => {
|
|
7
|
+
if (data && typeof data === "object") {
|
|
8
|
+
refresh();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export default defineNuxtPlugin(() => {
|
|
13
|
+
registerContentHotReload(import.meta.hot, import.meta.client, refreshNuxtData);
|
|
6
14
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { resolveGraphReferenceTarget } from "../core/content/graph.js";
|
|
1
2
|
import { collectMarkdownRefLinks, parseRefLink } from "../core/references/resolve.js";
|
|
2
3
|
import { projectContentRoute } from "../features/localization/route-projector.js";
|
|
3
4
|
import { resolveRuntimeCollectionLocalePolicy } from "../features/localization/config.js";
|
|
4
5
|
import { contentConfig } from "./driver.js";
|
|
5
|
-
import { getContentGraph,
|
|
6
|
+
import { getContentGraph, resolveVariant } from "./graph.js";
|
|
6
7
|
const isConfiguredQuickLink = (href) => {
|
|
7
8
|
const parsed = parseRefLink(href);
|
|
8
9
|
if (!parsed) {
|
|
@@ -17,19 +18,6 @@ const isConfiguredQuickLink = (href) => {
|
|
|
17
18
|
const links = contentConfig().links;
|
|
18
19
|
return Boolean(links?.[namespace]?.[key]);
|
|
19
20
|
};
|
|
20
|
-
const resolveReferenceTarget = async (event, identity, collections) => {
|
|
21
|
-
const canonicalKey = await resolveCanonicalKey(event, identity);
|
|
22
|
-
if (canonicalKey) {
|
|
23
|
-
return { canonicalKey };
|
|
24
|
-
}
|
|
25
|
-
const scopedMatches = (await Promise.all(
|
|
26
|
-
Object.keys(collections).map(async (collection) => {
|
|
27
|
-
const scopedCanonicalKey = await resolveCanonicalKey(event, identity, collection);
|
|
28
|
-
return scopedCanonicalKey ? { canonicalKey: scopedCanonicalKey, collection } : null;
|
|
29
|
-
})
|
|
30
|
-
)).filter((match) => Boolean(match));
|
|
31
|
-
return scopedMatches.length === 1 ? scopedMatches[0] : null;
|
|
32
|
-
};
|
|
33
21
|
const resolveDocumentRefLinks = async (event, content, requestedLocale) => {
|
|
34
22
|
if (!content || content.type !== "markdown" || !content.body) {
|
|
35
23
|
return void 0;
|
|
@@ -46,7 +34,7 @@ const resolveDocumentRefLinks = async (event, content, requestedLocale) => {
|
|
|
46
34
|
if (!parsed) {
|
|
47
35
|
return null;
|
|
48
36
|
}
|
|
49
|
-
const target =
|
|
37
|
+
const target = resolveGraphReferenceTarget(graph, parsed.ref);
|
|
50
38
|
if (!target) {
|
|
51
39
|
if (isConfiguredQuickLink(href)) {
|
|
52
40
|
return [href, href];
|
|
@@ -75,10 +63,9 @@ const resolveDocumentRefLinks = async (event, content, requestedLocale) => {
|
|
|
75
63
|
);
|
|
76
64
|
}
|
|
77
65
|
const routeLocale = variant.fallback && requestedLocale ? requestedLocale : variant.resolvedLocale;
|
|
78
|
-
const
|
|
79
|
-
const targetPolicy = targetCollection ? resolveRuntimeCollectionLocalePolicy(targetCollection, config) : void 0;
|
|
66
|
+
const targetPolicy = resolveRuntimeCollectionLocalePolicy(target.collection, config);
|
|
80
67
|
if (!targetPolicy) {
|
|
81
|
-
throw new Error(`Missing resolved locale policy for content collection "${
|
|
68
|
+
throw new Error(`Missing resolved locale policy for content collection "${target.collection}".`);
|
|
82
69
|
}
|
|
83
70
|
return [
|
|
84
71
|
href,
|
package/dist/types/virtual.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ declare module '#imports' {
|
|
|
51
51
|
export const useFetch: typeof import('#app').useFetch
|
|
52
52
|
export const useHead: typeof import('#app').useHead
|
|
53
53
|
export const useNuxtApp: typeof import('#app').useNuxtApp
|
|
54
|
+
export const tryUseNuxtApp: typeof import('#app').tryUseNuxtApp
|
|
54
55
|
export const useCookie: typeof import('#app').useCookie
|
|
55
56
|
export const useRequestEvent: typeof import('#app').useRequestEvent
|
|
56
57
|
export const useRequestFetch: typeof import('#app').useRequestFetch
|
package/dist/web-types.json
CHANGED
package/package.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { refreshNuxtData } from "#imports";
|
|
2
|
-
let registered = false;
|
|
3
|
-
const onContentUpdate = (data) => {
|
|
4
|
-
if (!data || typeof data !== "object") {
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
refreshNuxtData();
|
|
8
|
-
};
|
|
9
|
-
export function registerContentHotReload(hot = import.meta.hot, isClient = import.meta.client) {
|
|
10
|
-
if (!hot || !isClient || registered) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
registered = true;
|
|
14
|
-
hot.on("ginko-content:update", onContentUpdate);
|
|
15
|
-
}
|