@lupinum/ginko-content 0.1.2 → 0.1.4
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 +18 -4
- package/compatibility.json +1 -1
- package/dist/cli.mjs +317 -294
- package/dist/cms-import/index.js +5 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +1 -1
- package/dist/core/cache-hints.d.ts +9 -1
- package/dist/core/content/collection.js +1 -1
- package/dist/core/content/path.js +1 -1
- package/dist/core/errors.js +5 -1
- package/dist/core/provider-errors +1 -0
- package/dist/core/provider-errors.d.ts +10 -0
- package/dist/core/provider-errors.js +27 -0
- package/dist/core/query/execute.js +12 -3
- package/dist/core/query/filter.js +2 -2
- package/dist/core/query/lower.js +5 -4
- package/dist/features/navigation/build.js +14 -6
- package/dist/features/navigation/canonical.js +1 -1
- package/dist/features/sitemap/query.js +2 -2
- package/dist/integrations/nitro/ingest.d.ts +3 -3
- package/dist/integrations/nitro/ingest.js +3 -3
- package/dist/integrations/nitro/storage.js +3 -1
- package/dist/module.d.mts +151 -526
- package/dist/module.json +1 -1
- package/dist/module.mjs +1083 -730
- package/dist/parsers/csv.js +4 -3
- package/dist/parsers/index.d.ts +2 -5
- package/dist/parsers/index.js +2 -2
- package/dist/parsers/markdown-plugins.d.ts +1 -0
- package/dist/parsers/markdown-plugins.js +83 -1
- package/dist/parsers/markdown.js +1 -1
- package/dist/public/client.d.ts +3 -2
- package/dist/public/client.js +2 -2
- package/dist/public/provider-errors.d.ts +2 -1
- package/dist/public/provider-errors.js +1 -18
- package/dist/public/provider.d.ts +3 -10
- package/dist/public/server.d.ts +6 -1
- package/dist/public/server.js +33 -0
- package/dist/runtime/agent-paths +1 -0
- package/dist/runtime/agent-paths.d.ts +6 -0
- package/dist/runtime/agent-paths.js +41 -0
- package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +1 -1
- package/dist/runtime/app/composables/head.d.ts +3 -0
- package/dist/runtime/app/composables/head.js +2 -1
- package/dist/runtime/app/composables/hot-reload +1 -0
- package/dist/runtime/app/composables/hot-reload.d.ts +5 -0
- package/dist/runtime/app/composables/hot-reload.js +15 -0
- package/dist/runtime/app/composables/locale-context.d.ts +1 -1
- package/dist/runtime/app/composables/locale-context.js +2 -1
- package/dist/runtime/app/composables/locale.js +2 -2
- package/dist/runtime/app/composables/search.js +10 -6
- package/dist/runtime/app/composables/use-content-document +1 -0
- package/dist/runtime/app/composables/use-content-document.d.ts +29 -0
- package/dist/runtime/app/composables/use-content-document.js +44 -0
- package/dist/runtime/app/composables/use-content-list +1 -0
- package/dist/runtime/app/composables/use-content-list.d.ts +43 -0
- package/dist/runtime/app/composables/use-content-list.js +98 -0
- package/dist/runtime/app/composables/use-content-navigation +1 -0
- package/dist/runtime/app/composables/use-content-navigation.d.ts +40 -0
- package/dist/runtime/app/composables/use-content-navigation.js +102 -0
- package/dist/runtime/app/composables/use-content-page +1 -0
- package/dist/runtime/app/composables/use-content-page.d.ts +47 -0
- package/dist/runtime/app/composables/use-content-page.js +142 -0
- package/dist/runtime/app/composables/use-content-shared +1 -0
- package/dist/runtime/app/composables/use-content-shared.d.ts +13 -0
- package/dist/runtime/app/composables/use-content-shared.js +29 -0
- package/dist/runtime/app/composables/use-content.d.ts +11 -206
- package/dist/runtime/app/composables/use-content.js +4 -377
- package/dist/runtime/app/plugins/hot-reload +1 -0
- package/dist/runtime/app/plugins/hot-reload.js +6 -0
- package/dist/runtime/query/backlinks +1 -0
- package/dist/runtime/query/backlinks.d.ts +8 -0
- package/dist/runtime/query/backlinks.js +90 -0
- package/dist/runtime/query/context +1 -0
- package/dist/runtime/query/context.d.ts +20 -0
- package/dist/runtime/query/context.js +0 -0
- package/dist/runtime/query/documents +1 -0
- package/dist/runtime/query/documents.d.ts +6 -0
- package/dist/runtime/query/documents.js +98 -0
- package/dist/runtime/query/errors +1 -0
- package/dist/runtime/query/errors.d.ts +1 -0
- package/dist/runtime/query/errors.js +4 -0
- package/dist/runtime/query/handles +1 -0
- package/dist/runtime/query/handles.d.ts +2 -0
- package/dist/runtime/query/handles.js +7 -0
- package/dist/runtime/query/locale-options +1 -0
- package/dist/runtime/query/locale-options.d.ts +5 -0
- package/dist/runtime/query/locale-options.js +14 -0
- package/dist/runtime/query/localized-docs +1 -0
- package/dist/runtime/query/localized-docs.d.ts +17 -0
- package/dist/runtime/query/localized-docs.js +44 -0
- package/dist/runtime/query/navigation +1 -0
- package/dist/runtime/query/navigation.d.ts +22 -0
- package/dist/runtime/query/navigation.js +73 -0
- package/dist/runtime/query/pagination +1 -0
- package/dist/runtime/query/pagination.d.ts +7 -0
- package/dist/runtime/query/pagination.js +78 -0
- package/dist/runtime/query/populate +1 -0
- package/dist/runtime/query/populate.d.ts +9 -0
- package/dist/runtime/query/populate.js +106 -0
- package/dist/runtime/query/responses +1 -0
- package/dist/runtime/query/responses.d.ts +10 -0
- package/dist/runtime/query/responses.js +47 -0
- package/dist/runtime/query/unified.d.ts +4 -20
- package/dist/runtime/query/unified.js +14 -544
- package/dist/runtime/query/variants +1 -0
- package/dist/runtime/query/variants.d.ts +11 -0
- package/dist/runtime/query/variants.js +36 -0
- package/dist/runtime/server/agent-http +1 -0
- package/dist/runtime/server/agent-http.d.ts +7 -0
- package/dist/runtime/server/agent-http.js +36 -0
- package/dist/runtime/server/agent-markdown +1 -0
- package/dist/runtime/server/agent-markdown.d.ts +83 -0
- package/dist/runtime/server/agent-markdown.js +449 -0
- package/dist/runtime/server/agent-site +1 -0
- package/dist/runtime/server/agent-site.d.ts +38 -0
- package/dist/runtime/server/agent-site.js +272 -0
- package/dist/runtime/server/api/agent-llms +1 -0
- package/dist/runtime/server/api/agent-llms-full +1 -0
- package/dist/runtime/server/api/agent-llms-full.d.ts +2 -0
- package/dist/runtime/server/api/agent-llms-full.js +13 -0
- package/dist/runtime/server/api/agent-llms.d.ts +2 -0
- package/dist/runtime/server/api/agent-llms.js +14 -0
- package/dist/runtime/server/api/agent-raw +1 -0
- package/dist/runtime/server/api/agent-raw.d.ts +2 -0
- package/dist/runtime/server/api/agent-raw.js +17 -0
- package/dist/runtime/server/api/locales.d.ts +2 -2
- package/dist/runtime/server/api/locales.js +4 -2
- package/dist/runtime/server/api/navigation.d.ts +1 -1
- package/dist/runtime/server/api/query.d.ts +1 -1
- package/dist/runtime/server/api/query.js +4 -1
- package/dist/runtime/server/api/revalidate.js +2 -2
- package/dist/runtime/server/api/site-data.d.ts +1 -1
- package/dist/runtime/server/collection-helpers.js +2 -1
- package/dist/runtime/server/middleware/agent-link-headers +1 -0
- package/dist/runtime/server/middleware/agent-link-headers.d.ts +2 -0
- package/dist/runtime/server/middleware/agent-link-headers.js +41 -0
- package/dist/runtime/server/middleware/agent-markdown +1 -0
- package/dist/runtime/server/middleware/agent-markdown.d.ts +2 -0
- package/dist/runtime/server/middleware/agent-markdown.js +43 -0
- package/dist/runtime/server/plugins/sitemap.js +1 -0
- package/dist/runtime/server/provider-query.d.ts +8 -5
- package/dist/runtime/server/provider-query.js +50 -8
- package/dist/runtime/server/provider-result.d.ts +19 -2
- package/dist/runtime/server/providers/filesystem.js +4 -1
- package/dist/runtime/server/providers/index.d.ts +3 -1
- package/dist/runtime/server/providers/index.js +2 -2
- package/dist/runtime/server/query-api.js +2 -1
- package/dist/runtime/server/query-executor.d.ts +3 -2
- package/dist/runtime/server/query-executor.js +13 -5
- package/dist/runtime/server/search.js +1 -1
- package/dist/runtime/server/sitemap-provider.js +40 -1
- package/dist/runtime/server/sitemap.js +3 -2
- package/dist/runtime/transformers/component-resolver.js +2 -1
- package/dist/runtime/utils/content-components.d.ts +0 -5
- package/dist/storage/content.d.ts +2 -9
- package/dist/storage/references.d.ts +1 -8
- package/dist/storage/references.js +9 -4
- package/dist/testing/provider-contract.js +3 -4
- package/dist/testing/provider-fixture.d.ts +3 -1
- package/dist/testing/provider-fixture.js +27 -14
- package/dist/types/config.d.ts +77 -0
- package/dist/types/config.js +23 -0
- package/dist/types/module.d.ts +15 -5
- package/dist/types/query-parts/collections +1 -0
- package/dist/types/query-parts/collections.d.ts +15 -0
- package/dist/types/query-parts/collections.js +0 -0
- package/dist/types/query-parts/public +1 -0
- package/dist/types/query-parts/public.d.ts +202 -0
- package/dist/types/query-parts/public.js +0 -0
- package/dist/types/query-parts/results +1 -0
- package/dist/types/query-parts/results.d.ts +95 -0
- package/dist/types/query-parts/results.js +0 -0
- package/dist/types/query-parts/transport +1 -0
- package/dist/types/query-parts/transport.d.ts +103 -0
- package/dist/types/query-parts/transport.js +0 -0
- package/dist/types/query.d.ts +4 -870
- package/dist/types/query.js +4 -0
- package/dist/types/runtime.d.ts +2 -2
- package/dist/types/virtual.d.ts +54 -0
- package/dist/types.d.mts +2 -2
- package/dist/web-types.json +1 -1
- package/package.json +5 -5
- package/dist/runtime/app/composables/web-socket +0 -1
- package/dist/runtime/app/composables/web-socket.d.ts +0 -3
- package/dist/runtime/app/composables/web-socket.js +0 -65
- package/dist/runtime/app/plugins/ws +0 -1
- package/dist/runtime/app/plugins/ws.js +0 -7
- /package/dist/runtime/app/plugins/{ws.d.ts → hot-reload.d.ts} +0 -0
package/dist/module.mjs
CHANGED
|
@@ -1,103 +1,36 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join as join$1, basename, resolve as resolve$1, relative as relative$1, dirname } from 'node:path';
|
|
3
|
-
import { pathToFileURL } from 'node:url';
|
|
4
1
|
import { addTypeTemplate, addImports, addServerImports, addComponentsDir, addPlugin, addServerHandler, defineNuxtModule, createResolver, useLogger, addTemplate } from '@nuxt/kit';
|
|
5
2
|
import { defu } from 'defu';
|
|
3
|
+
import fs, { existsSync } from 'fs';
|
|
4
|
+
import { join, relative, resolve, isAbsolute } from 'pathe';
|
|
5
|
+
import jiti from 'jiti';
|
|
6
|
+
import { genSafeVariableName, genImport } from 'knitwork';
|
|
6
7
|
import { hash } from 'ohash';
|
|
7
|
-
import { resolve, join, relative, isAbsolute } from 'pathe';
|
|
8
|
-
import { withTrailingSlash } from 'ufo';
|
|
9
|
-
import { normalizeContentConfigCollectionNames } from '../dist/types/config';
|
|
10
|
-
export { defineCollection, defineContentConfig, reference } from '../dist/types/config';
|
|
11
8
|
import 'unstorage/drivers/fs';
|
|
12
9
|
import 'unstorage/drivers/http';
|
|
13
10
|
import 'unstorage/drivers/github';
|
|
14
|
-
import { WebSocketServer } from 'ws';
|
|
15
11
|
import { consola } from 'consola';
|
|
16
|
-
import fs, { existsSync } from 'fs';
|
|
17
|
-
import jiti from 'jiti';
|
|
18
|
-
import { createRequire } from 'node:module';
|
|
19
|
-
import { genSafeVariableName, genImport } from 'knitwork';
|
|
20
|
-
import { listen } from 'listhen';
|
|
21
12
|
import { makeIgnored } from '../dist/core/content/ignore';
|
|
22
|
-
import { readFile, readdir } from 'node:fs/promises';
|
|
23
|
-
import { resolveContentSitemapSource, GINKO_SITEMAP_SOURCE_NAME } from '../dist/runtime/utils/sitemap-source';
|
|
24
13
|
import { resolveCollectionI18nConfig } from '../dist/features/localization/config';
|
|
14
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
15
|
+
import { join as join$1, basename, resolve as resolve$1, relative as relative$1, dirname } from 'node:path';
|
|
25
16
|
import { globby } from 'globby';
|
|
26
|
-
import { transformContent } from '../dist/parsers/index';
|
|
27
|
-
import { expandDataLocaleVariants } from '../dist/core/content/locale';
|
|
28
17
|
import { buildContentGraph } from '../dist/core/content/graph';
|
|
18
|
+
import { expandDataLocaleVariants } from '../dist/core/content/locale';
|
|
29
19
|
import { normalizeCollectionSources, normalizeCollectionExcludes } from '../dist/core/content/sources';
|
|
30
|
-
import { resolveCollectionI18n, prefixPathWithLocale } from '../dist/features/localization/path';
|
|
31
20
|
import { resolveCollection } from '../dist/core/content/collection';
|
|
21
|
+
import { transformContent } from '../dist/parsers/index';
|
|
22
|
+
import { resolveCollectionI18n, prefixPathWithLocale } from '../dist/features/localization/path';
|
|
23
|
+
import { resolveContentSitemapSource, GINKO_SITEMAP_SOURCE_NAME } from '../dist/runtime/utils/sitemap-source';
|
|
32
24
|
import { normalizeRouteMounts, normalizeContentPath } from '../dist/core/content/path';
|
|
25
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import { pathToFileURL } from 'node:url';
|
|
27
|
+
import { withTrailingSlash } from 'ufo';
|
|
28
|
+
import { normalizeContentConfigCollectionNames } from '../dist/types/config';
|
|
29
|
+
export { agentMetadataFields, defineAgentAppPage, defineAgentMarkdownPolicy, defineAgentMetadataFields, defineAgentSection, defineCollection, defineContentConfig, reference } from '../dist/types/config';
|
|
33
30
|
import { collectTopLevelReferenceFieldsByTarget } from '../dist/core/references/schema';
|
|
34
31
|
|
|
35
32
|
const name = "@lupinum/ginko-content";
|
|
36
|
-
const version = "0.1.
|
|
37
|
-
|
|
38
|
-
const logger = consola.withTag("@lupinum/ginko-content");
|
|
39
|
-
const CACHE_VERSION = 3;
|
|
40
|
-
const MOUNT_PREFIX = "content:source:";
|
|
41
|
-
function useContentMounts(nuxt, storages) {
|
|
42
|
-
const key = (path, prefix = "") => `${MOUNT_PREFIX}${path.replace(/[/:]/g, "_")}${prefix.replace(/\//g, ":")}`;
|
|
43
|
-
const baseDir = nuxt.options.future?.compatibilityVersion === 4 ? nuxt.options.rootDir : nuxt.options.srcDir;
|
|
44
|
-
storages = Object.entries(storages).reduce((mounts, [name, storage]) => {
|
|
45
|
-
mounts[key(storage.name || name, storage.prefix)] = storage;
|
|
46
|
-
return mounts;
|
|
47
|
-
}, {});
|
|
48
|
-
const defaultStorage = key("content");
|
|
49
|
-
if (!storages[defaultStorage]) {
|
|
50
|
-
storages[defaultStorage] = {
|
|
51
|
-
name: defaultStorage,
|
|
52
|
-
driver: "fs",
|
|
53
|
-
base: resolve(baseDir, "content")
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
return storages;
|
|
57
|
-
}
|
|
58
|
-
function createWebSocket() {
|
|
59
|
-
const wss = new WebSocketServer({ noServer: true });
|
|
60
|
-
const serve = (req, socket = req.socket, head = "") => wss.handleUpgrade(req, socket, head, (client) => wss.emit("connection", client, req));
|
|
61
|
-
const broadcast = (data) => {
|
|
62
|
-
data = JSON.stringify(data);
|
|
63
|
-
for (const client of wss.clients) {
|
|
64
|
-
try {
|
|
65
|
-
client.send(data);
|
|
66
|
-
} catch {
|
|
67
|
-
logger.debug("Skipping websocket client that is not ready to receive content refresh events.");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
return {
|
|
72
|
-
serve,
|
|
73
|
-
broadcast,
|
|
74
|
-
close: () => {
|
|
75
|
-
wss.clients.forEach((client) => client.close());
|
|
76
|
-
return new Promise((resolve2) => wss.close(resolve2));
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function processMarkdownOptions(options) {
|
|
81
|
-
const anchorLinks = typeof options.anchorLinks === "boolean" ? { depth: options.anchorLinks ? 6 : 0, exclude: [] } : { depth: 4, exclude: [1], ...options.anchorLinks };
|
|
82
|
-
const plugins = options.plugins?.length ? options.plugins : [
|
|
83
|
-
["toc", { depth: 2, searchDepth: 2 }],
|
|
84
|
-
"summary"
|
|
85
|
-
];
|
|
86
|
-
return {
|
|
87
|
-
...options,
|
|
88
|
-
anchorLinks,
|
|
89
|
-
plugins: resolveMarkdownPlugins(plugins)
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function resolveMarkdownPlugins(plugins) {
|
|
93
|
-
return (plugins || []).map((plugin) => {
|
|
94
|
-
const [name, options] = Array.isArray(plugin) ? plugin : [plugin, {}];
|
|
95
|
-
return {
|
|
96
|
-
name,
|
|
97
|
-
options
|
|
98
|
-
};
|
|
99
|
-
});
|
|
100
|
-
}
|
|
33
|
+
const version = "0.1.4";
|
|
101
34
|
|
|
102
35
|
const CONFIG_FILES = [
|
|
103
36
|
"content.config.ts",
|
|
@@ -119,8 +52,6 @@ async function loadContentConfig(nuxt) {
|
|
|
119
52
|
return loaded?.default || loaded || {};
|
|
120
53
|
}
|
|
121
54
|
|
|
122
|
-
const require$1 = createRequire(import.meta.url);
|
|
123
|
-
const jitiImportSpecifier = pathToFileURL(require$1.resolve("jiti")).href;
|
|
124
55
|
const createVirtualContentTemplates = (contentContext, nuxt, contentConfigPath, addTemplateImpl) => {
|
|
125
56
|
const transformersTemplate = addTemplateImpl({
|
|
126
57
|
filename: "content/virtual-transformers.mjs",
|
|
@@ -143,10 +74,8 @@ const createVirtualContentTemplates = (contentContext, nuxt, contentConfigPath,
|
|
|
143
74
|
filename: "content/virtual-config.mjs",
|
|
144
75
|
write: true,
|
|
145
76
|
getContents: () => contentConfigPath ? [
|
|
146
|
-
`import
|
|
147
|
-
|
|
148
|
-
`const config = await importer.import(${JSON.stringify(contentConfigPath)})`,
|
|
149
|
-
"export default config?.default || config || {}"
|
|
77
|
+
`import config from ${JSON.stringify(contentConfigPath)}`,
|
|
78
|
+
"export default config || {}"
|
|
150
79
|
].join("\n") : "export default {}"
|
|
151
80
|
}).dst;
|
|
152
81
|
const virtualProvidersTemplate = addTemplateImpl({
|
|
@@ -175,7 +104,7 @@ const createVirtualContentTemplates = (contentContext, nuxt, contentConfigPath,
|
|
|
175
104
|
write: true,
|
|
176
105
|
getContents: () => {
|
|
177
106
|
const cache = contentContext.cache;
|
|
178
|
-
if (!cache
|
|
107
|
+
if (!cache) {
|
|
179
108
|
return [
|
|
180
109
|
"export const loadContentCacheAdapter = () => undefined",
|
|
181
110
|
"export default {}"
|
|
@@ -211,14 +140,66 @@ const registerVirtualContentAliases = (nuxt, transformersTemplate, virtualConfig
|
|
|
211
140
|
});
|
|
212
141
|
};
|
|
213
142
|
|
|
143
|
+
consola.withTag("@lupinum/ginko-content");
|
|
144
|
+
const CACHE_VERSION = 3;
|
|
145
|
+
const MOUNT_PREFIX = "content:source:";
|
|
146
|
+
function useContentMounts(nuxt, storages) {
|
|
147
|
+
const key = (path, prefix = "") => `${MOUNT_PREFIX}${path.replace(/[/:]/g, "_")}${prefix.replace(/\//g, ":")}`;
|
|
148
|
+
const baseDir = nuxt.options.future?.compatibilityVersion === 4 ? nuxt.options.rootDir : nuxt.options.srcDir;
|
|
149
|
+
storages = Object.entries(storages).reduce((mounts, [name, storage]) => {
|
|
150
|
+
mounts[key(storage.name || name, storage.prefix)] = storage;
|
|
151
|
+
return mounts;
|
|
152
|
+
}, {});
|
|
153
|
+
const defaultStorage = key("content");
|
|
154
|
+
if (!storages[defaultStorage]) {
|
|
155
|
+
storages[defaultStorage] = {
|
|
156
|
+
name: defaultStorage,
|
|
157
|
+
driver: "fs",
|
|
158
|
+
base: resolve(baseDir, "content")
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return storages;
|
|
162
|
+
}
|
|
163
|
+
function processMarkdownOptions(options) {
|
|
164
|
+
const anchorLinks = typeof options.anchorLinks === "boolean" ? { depth: options.anchorLinks ? 6 : 0, exclude: [] } : { depth: 4, exclude: [1], ...options.anchorLinks };
|
|
165
|
+
const plugins = options.plugins?.length ? options.plugins : [
|
|
166
|
+
["toc", { depth: 2, searchDepth: 2 }],
|
|
167
|
+
"summary"
|
|
168
|
+
];
|
|
169
|
+
return {
|
|
170
|
+
anchorLinks,
|
|
171
|
+
tags: options.tags || {},
|
|
172
|
+
image: options.image,
|
|
173
|
+
plugins: resolveMarkdownPlugins(plugins)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function resolveMarkdownPlugins(plugins) {
|
|
177
|
+
return (plugins || []).map((plugin) => {
|
|
178
|
+
const [name, options] = Array.isArray(plugin) ? plugin : [plugin, {}];
|
|
179
|
+
return {
|
|
180
|
+
name,
|
|
181
|
+
options
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
214
186
|
const registerContentDevRuntime = (nuxt, options, contentContext) => {
|
|
215
187
|
const isIgnored = makeIgnored(contentContext.ignores);
|
|
188
|
+
let viteServer;
|
|
189
|
+
if (options.watch !== false) {
|
|
190
|
+
nuxt.options.vite ||= {};
|
|
191
|
+
nuxt.options.vite.plugins ||= [];
|
|
192
|
+
nuxt.options.vite.plugins.push({
|
|
193
|
+
name: "ginko-content-hmr",
|
|
194
|
+
configureServer(server) {
|
|
195
|
+
viteServer = server;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
216
199
|
nuxt.hook("nitro:init", async (nitro) => {
|
|
217
|
-
if (
|
|
200
|
+
if (options.watch === false) {
|
|
218
201
|
return;
|
|
219
202
|
}
|
|
220
|
-
const ws = createWebSocket();
|
|
221
|
-
const { server, url } = await listen(() => "Ginko", options.watch.ws);
|
|
222
203
|
const unwatch = await nitro.storage.watch(async (event, key) => {
|
|
223
204
|
if (!key.startsWith(MOUNT_PREFIX) || isIgnored(key)) {
|
|
224
205
|
return;
|
|
@@ -227,56 +208,85 @@ const registerContentDevRuntime = (nuxt, options, contentContext) => {
|
|
|
227
208
|
await nitro.storage.removeItem("cache:content:_manifest.json");
|
|
228
209
|
await nitro.storage.removeItem("cache:content:_nav.json");
|
|
229
210
|
await nitro.storage.removeItem("cache:content:_meta.json");
|
|
230
|
-
|
|
211
|
+
await nitro.storage.removeItem(`cache:content:parsed:${key}`);
|
|
212
|
+
const payload = { event, key };
|
|
213
|
+
viteServer?.ws.send({
|
|
214
|
+
type: "custom",
|
|
215
|
+
event: "ginko-content:update",
|
|
216
|
+
data: payload
|
|
217
|
+
});
|
|
231
218
|
});
|
|
232
219
|
nitro.hooks.hook("close", async () => {
|
|
233
220
|
await unwatch();
|
|
234
|
-
await ws.close();
|
|
235
|
-
await server.close();
|
|
236
221
|
});
|
|
237
|
-
server.on("upgrade", ws.serve);
|
|
238
|
-
nitro.options.runtimeConfig.public.content.wsUrl = url.replace("http", "ws");
|
|
239
222
|
await nitro.storage.removeItem("cache:content:_manifest.json");
|
|
240
223
|
await nitro.storage.removeItem("cache:content:_nav.json");
|
|
241
224
|
await nitro.storage.removeItem("cache:content:_meta.json");
|
|
242
225
|
});
|
|
243
226
|
};
|
|
244
227
|
|
|
228
|
+
const runtimeAppImportSpecs = [
|
|
229
|
+
{ name: "getCollectionPath", as: "getCollectionPath", from: "./query/routes.js" },
|
|
230
|
+
{ name: "useContentHead", as: "useContentHead", from: "./app/composables/head.js" },
|
|
231
|
+
{ name: "useContentPage", as: "useContentPage", from: "./app/composables/use-content.js" },
|
|
232
|
+
{ name: "useContentOne", as: "useContentOne", from: "./app/composables/use-content.js" },
|
|
233
|
+
{ name: "useContentMany", as: "useContentMany", from: "./app/composables/use-content.js" },
|
|
234
|
+
{ name: "useContentPagination", as: "useContentPagination", from: "./app/composables/use-content.js" },
|
|
235
|
+
{ name: "useContentBacklinks", as: "useContentBacklinks", from: "./app/composables/use-content.js" },
|
|
236
|
+
{ name: "useContentResolveOne", as: "useContentResolveOne", from: "./app/composables/use-content.js" },
|
|
237
|
+
{ name: "useContentVariants", as: "useContentVariants", from: "./app/composables/use-content.js" },
|
|
238
|
+
{ name: "useContentTree", as: "useContentTree", from: "./app/composables/use-content.js" },
|
|
239
|
+
{ name: "useContentNavigation", as: "useContentNavigation", from: "./app/composables/use-content.js" },
|
|
240
|
+
{ name: "useContentNeighbors", as: "useContentNeighbors", from: "./app/composables/use-content.js" },
|
|
241
|
+
{ name: "useContentSwitchLocalePath", as: "useContentSwitchLocalePath", from: "./app/composables/route.js" },
|
|
242
|
+
{ name: "useContentSearchData", as: "useContentSearchData", from: "./app/composables/search.js" },
|
|
243
|
+
{ name: "useContentSearchResults", as: "useContentSearchResults", from: "./app/composables/search.js" },
|
|
244
|
+
{ name: "querySiteData", as: "querySiteData", from: "./app/composables/site-data.js" }
|
|
245
|
+
];
|
|
246
|
+
const runtimeServerImportSpecs = [
|
|
247
|
+
{ name: "one", as: "one" },
|
|
248
|
+
{ name: "many", as: "many" },
|
|
249
|
+
{ name: "paginate", as: "paginate" },
|
|
250
|
+
{ name: "backlinks", as: "backlinks" },
|
|
251
|
+
{ name: "resolveOne", as: "resolveOne" },
|
|
252
|
+
{ name: "variants", as: "variants" },
|
|
253
|
+
{ name: "tree", as: "tree" },
|
|
254
|
+
{ name: "neighbors", as: "neighbors" },
|
|
255
|
+
{ name: "getCollectionPath", as: "getCollectionPath" },
|
|
256
|
+
{ name: "queryCollectionsSitemapEntries", as: "queryCollectionsSitemapEntries" }
|
|
257
|
+
];
|
|
258
|
+
const generatedContentServerValueNames = [
|
|
259
|
+
...runtimeServerImportSpecs.map((spec) => spec.name),
|
|
260
|
+
"contentCacheHeaders",
|
|
261
|
+
"noopContentCache",
|
|
262
|
+
"vercelContentCache",
|
|
263
|
+
"clearContentCacheHint",
|
|
264
|
+
"collectContentCacheHint",
|
|
265
|
+
"getContentCacheHint",
|
|
266
|
+
"withContentCache",
|
|
267
|
+
"createContentProviderError"
|
|
268
|
+
];
|
|
269
|
+
const generatedContentServerTypeSpecs = [
|
|
270
|
+
{ local: "ContentCacheAdapter", exported: "ContentCacheAdapter" },
|
|
271
|
+
{ local: "ContentCacheHint", exported: "ContentCacheHint" },
|
|
272
|
+
{ local: "ContentCacheHintInput", exported: "ContentCacheHintInput" },
|
|
273
|
+
{ local: "ContentCacheInvalidateInput", exported: "ContentCacheInvalidateInput" },
|
|
274
|
+
{ local: "ContentProvider", exported: "ContentProvider" },
|
|
275
|
+
{ local: "ContentProviderCapabilities", exported: "ContentProviderCapabilities" },
|
|
276
|
+
{ local: "ContentProviderResult<T>", exported: "ContentProviderResult<T>" },
|
|
277
|
+
{ local: "MaybeContentProviderResult<T>", exported: "MaybeContentProviderResult<T>" },
|
|
278
|
+
{ local: "ContentProviderErrorCode", exported: "ContentProviderErrorCode" },
|
|
279
|
+
{ local: "VercelContentCacheOptions", exported: "VercelContentCacheOptions" }
|
|
280
|
+
];
|
|
245
281
|
const registerRuntimeImports = (resolveRuntimeModule) => {
|
|
246
|
-
addImports(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
{ name: "useContentBacklinks", as: "useContentBacklinks", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
255
|
-
{ name: "useContentResolveOne", as: "useContentResolveOne", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
256
|
-
{ name: "useContentVariants", as: "useContentVariants", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
257
|
-
{ name: "useContentTree", as: "useContentTree", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
258
|
-
{ name: "useContentNavigation", as: "useContentNavigation", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
259
|
-
{ name: "useContentNeighbors", as: "useContentNeighbors", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
260
|
-
{ name: "useContentLocaleSwitch", as: "useContentLocaleSwitch", from: resolveRuntimeModule("./app/composables/use-content.js") },
|
|
261
|
-
{ name: "useContentSwitchLocalePath", as: "useContentSwitchLocalePath", from: resolveRuntimeModule("./app/composables/route.js") },
|
|
262
|
-
// Search & site data — keep the headless useContentSearch export explicit
|
|
263
|
-
// because Nuxt UI owns the same auto-import name.
|
|
264
|
-
{ name: "useContentSearchData", as: "useContentSearchData", from: resolveRuntimeModule("./app/composables/search.js") },
|
|
265
|
-
{ name: "useContentSearchResults", as: "useContentSearchResults", from: resolveRuntimeModule("./app/composables/search.js") },
|
|
266
|
-
{ name: "querySiteData", as: "querySiteData", from: resolveRuntimeModule("./app/composables/site-data.js") }
|
|
267
|
-
]);
|
|
268
|
-
addServerImports([
|
|
269
|
-
{ name: "one", as: "one", from: resolveRuntimeModule("./server/index.js") },
|
|
270
|
-
{ name: "many", as: "many", from: resolveRuntimeModule("./server/index.js") },
|
|
271
|
-
{ name: "paginate", as: "paginate", from: resolveRuntimeModule("./server/index.js") },
|
|
272
|
-
{ name: "backlinks", as: "backlinks", from: resolveRuntimeModule("./server/index.js") },
|
|
273
|
-
{ name: "resolveOne", as: "resolveOne", from: resolveRuntimeModule("./server/index.js") },
|
|
274
|
-
{ name: "variants", as: "variants", from: resolveRuntimeModule("./server/index.js") },
|
|
275
|
-
{ name: "tree", as: "tree", from: resolveRuntimeModule("./server/index.js") },
|
|
276
|
-
{ name: "neighbors", as: "neighbors", from: resolveRuntimeModule("./server/index.js") },
|
|
277
|
-
{ name: "getCollectionPath", as: "getCollectionPath", from: resolveRuntimeModule("./server/index.js") },
|
|
278
|
-
{ name: "queryCollectionsSitemapEntries", as: "queryCollectionsSitemapEntries", from: resolveRuntimeModule("./server/index.js") }
|
|
279
|
-
]);
|
|
282
|
+
addImports(runtimeAppImportSpecs.map((spec) => ({
|
|
283
|
+
...spec,
|
|
284
|
+
from: resolveRuntimeModule(spec.from)
|
|
285
|
+
})));
|
|
286
|
+
addServerImports(runtimeServerImportSpecs.map((spec) => ({
|
|
287
|
+
...spec,
|
|
288
|
+
from: resolveRuntimeModule("./server/index.js")
|
|
289
|
+
})));
|
|
280
290
|
};
|
|
281
291
|
const registerRuntimeComponents = (resolve) => {
|
|
282
292
|
addComponentsDir({
|
|
@@ -332,11 +342,11 @@ const registerContentI18nTemplate = (addTemplateImpl, hasNuxtI18nModule) => {
|
|
|
332
342
|
].join("\n")
|
|
333
343
|
});
|
|
334
344
|
};
|
|
335
|
-
const registerUserContentComponents = async (nuxt,
|
|
345
|
+
const registerUserContentComponents = async (nuxt, _resolve) => {
|
|
336
346
|
const layers = [...nuxt.options._layers];
|
|
337
347
|
for (const layer of layers) {
|
|
338
348
|
const srcDir = layer.config.srcDir;
|
|
339
|
-
const globalComponents =
|
|
349
|
+
const globalComponents = join(srcDir, "components/content");
|
|
340
350
|
const dirStat = await fs.promises.stat(globalComponents).catch((error) => {
|
|
341
351
|
if (error.code === "ENOENT") {
|
|
342
352
|
return null;
|
|
@@ -362,6 +372,12 @@ const registerGeneratedTypes = (contentConfigPath, resolveRuntimeModuleRoot, col
|
|
|
362
372
|
const key = JSON.stringify(name);
|
|
363
373
|
return ` ${key}: StrictParsedContent & __GeneratedCollectionSchema<__ContentCollectionExport<${key}>>`;
|
|
364
374
|
});
|
|
375
|
+
const contentServerValueDeclarations = generatedContentServerValueNames.map(
|
|
376
|
+
(name) => ` const ${name}: typeof import('${resolveRuntimeModuleRoot("./server")}').${name}`
|
|
377
|
+
);
|
|
378
|
+
const contentServerTypeDeclarations = generatedContentServerTypeSpecs.map(
|
|
379
|
+
(spec) => ` type ${spec.local} = import('${resolveRuntimeModuleRoot("./server")}').${spec.exported}`
|
|
380
|
+
);
|
|
365
381
|
return addTypeTemplate({
|
|
366
382
|
filename: "types/content.d.ts",
|
|
367
383
|
getContents: () => [
|
|
@@ -418,42 +434,36 @@ const registerGeneratedTypes = (contentConfigPath, resolveRuntimeModuleRoot, col
|
|
|
418
434
|
" interface ContentCollectionI18nMap extends Pick<__GeneratedContentCollectionMap, __GeneratedI18nCollectionNames> {}",
|
|
419
435
|
"}",
|
|
420
436
|
"declare module '#content/server' {",
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
` const paginate: typeof import('${resolveRuntimeModuleRoot("./server")}').paginate`,
|
|
424
|
-
` const backlinks: typeof import('${resolveRuntimeModuleRoot("./server")}').backlinks`,
|
|
425
|
-
` const resolveOne: typeof import('${resolveRuntimeModuleRoot("./server")}').resolveOne`,
|
|
426
|
-
` const variants: typeof import('${resolveRuntimeModuleRoot("./server")}').variants`,
|
|
427
|
-
` const tree: typeof import('${resolveRuntimeModuleRoot("./server")}').tree`,
|
|
428
|
-
` const neighbors: typeof import('${resolveRuntimeModuleRoot("./server")}').neighbors`,
|
|
429
|
-
` const queryCollectionsSitemapEntries: typeof import('${resolveRuntimeModuleRoot("./server")}').queryCollectionsSitemapEntries`,
|
|
430
|
-
` const contentCacheHeaders: typeof import('${resolveRuntimeModuleRoot("./server")}').contentCacheHeaders`,
|
|
431
|
-
` const noopContentCache: typeof import('${resolveRuntimeModuleRoot("./server")}').noopContentCache`,
|
|
432
|
-
` const vercelContentCache: typeof import('${resolveRuntimeModuleRoot("./server")}').vercelContentCache`,
|
|
433
|
-
` const clearContentCacheHint: typeof import('${resolveRuntimeModuleRoot("./server")}').clearContentCacheHint`,
|
|
434
|
-
` const collectContentCacheHint: typeof import('${resolveRuntimeModuleRoot("./server")}').collectContentCacheHint`,
|
|
435
|
-
` const getContentCacheHint: typeof import('${resolveRuntimeModuleRoot("./server")}').getContentCacheHint`,
|
|
436
|
-
` const withContentCache: typeof import('${resolveRuntimeModuleRoot("./server")}').withContentCache`,
|
|
437
|
-
` const createContentProviderError: typeof import('${resolveRuntimeModuleRoot("./server")}').createContentProviderError`,
|
|
438
|
-
` type ContentCacheAdapter = import('${resolveRuntimeModuleRoot("./server")}').ContentCacheAdapter`,
|
|
439
|
-
` type ContentCacheHint = import('${resolveRuntimeModuleRoot("./server")}').ContentCacheHint`,
|
|
440
|
-
` type ContentCacheHintInput = import('${resolveRuntimeModuleRoot("./server")}').ContentCacheHintInput`,
|
|
441
|
-
` type ContentCacheInvalidateInput = import('${resolveRuntimeModuleRoot("./server")}').ContentCacheInvalidateInput`,
|
|
442
|
-
` type ContentProvider = import('${resolveRuntimeModuleRoot("./server")}').ContentProvider`,
|
|
443
|
-
` type ContentProviderCapabilities = import('${resolveRuntimeModuleRoot("./server")}').ContentProviderCapabilities`,
|
|
444
|
-
` type ContentProviderResult<T> = import('${resolveRuntimeModuleRoot("./server")}').ContentProviderResult<T>`,
|
|
445
|
-
` type MaybeContentProviderResult<T> = import('${resolveRuntimeModuleRoot("./server")}').MaybeContentProviderResult<T>`,
|
|
446
|
-
` type ContentProviderErrorCode = import('${resolveRuntimeModuleRoot("./server")}').ContentProviderErrorCode`,
|
|
447
|
-
` type VercelContentCacheOptions = import('${resolveRuntimeModuleRoot("./server")}').VercelContentCacheOptions`,
|
|
437
|
+
...contentServerValueDeclarations,
|
|
438
|
+
...contentServerTypeDeclarations,
|
|
448
439
|
"}"
|
|
449
440
|
].filter(Boolean).join("\n")
|
|
450
441
|
});
|
|
451
442
|
};
|
|
452
443
|
const registerDevRuntimePlugin = (resolveRuntimeModule) => {
|
|
453
|
-
addPlugin(resolveRuntimeModule("./app/plugins/
|
|
444
|
+
addPlugin(resolveRuntimeModule("./app/plugins/hot-reload.js"));
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const normalizeAgentRouteOptions = (options) => {
|
|
448
|
+
if (options.agent === false) {
|
|
449
|
+
return {
|
|
450
|
+
routes: false,
|
|
451
|
+
linkHeaders: false,
|
|
452
|
+
markdownNegotiation: false,
|
|
453
|
+
prerender: false
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
routes: options.agent?.routes !== false,
|
|
458
|
+
linkHeaders: options.agent?.linkHeaders !== false,
|
|
459
|
+
markdownNegotiation: options.agent?.markdownNegotiation !== false,
|
|
460
|
+
prerender: options.agent?.prerender !== false
|
|
461
|
+
};
|
|
454
462
|
};
|
|
455
463
|
|
|
456
464
|
const registerContentServerHandlers = (nuxt, options, resolveRuntimeModule, buildIntegrity) => {
|
|
465
|
+
const revalidate = options.revalidate === false ? void 0 : options.revalidate;
|
|
466
|
+
const sitemap = options.sitemap === false ? false : options.sitemap === true ? { path: "/sitemap" } : options.sitemap;
|
|
457
467
|
addServerHandler({
|
|
458
468
|
method: "get",
|
|
459
469
|
route: `${options.api.baseURL}/query/**:params`,
|
|
@@ -474,7 +484,7 @@ const registerContentServerHandlers = (nuxt, options, resolveRuntimeModule, buil
|
|
|
474
484
|
route: `${options.api.baseURL}/site-data`,
|
|
475
485
|
handler: resolveRuntimeModule("./server/api/site-data.js")
|
|
476
486
|
});
|
|
477
|
-
if (
|
|
487
|
+
if (revalidate?.token) {
|
|
478
488
|
addServerHandler({
|
|
479
489
|
method: "post",
|
|
480
490
|
route: `${options.api.baseURL}/revalidate`,
|
|
@@ -486,10 +496,10 @@ const registerContentServerHandlers = (nuxt, options, resolveRuntimeModule, buil
|
|
|
486
496
|
route: nuxt.options.dev ? `${options.api.baseURL}/cache.json` : `${options.api.baseURL}/cache.${buildIntegrity}.json`,
|
|
487
497
|
handler: resolveRuntimeModule("./server/api/cache.js")
|
|
488
498
|
});
|
|
489
|
-
if (
|
|
499
|
+
if (sitemap !== false) {
|
|
490
500
|
addServerHandler({
|
|
491
501
|
method: "get",
|
|
492
|
-
route: `${options.api.baseURL}${
|
|
502
|
+
route: `${options.api.baseURL}${sitemap.path || "/sitemap"}`,
|
|
493
503
|
handler: resolveRuntimeModule("./server/api/sitemap.js")
|
|
494
504
|
});
|
|
495
505
|
}
|
|
@@ -505,6 +515,46 @@ const registerContentServerHandlers = (nuxt, options, resolveRuntimeModule, buil
|
|
|
505
515
|
handler: resolveRuntimeModule("./server/api/navigation.js")
|
|
506
516
|
});
|
|
507
517
|
}
|
|
518
|
+
const agent = normalizeAgentRouteOptions(options);
|
|
519
|
+
if (agent.routes) {
|
|
520
|
+
addServerHandler({
|
|
521
|
+
method: "get",
|
|
522
|
+
route: "/llms.txt",
|
|
523
|
+
handler: resolveRuntimeModule("./server/api/agent-llms.js")
|
|
524
|
+
});
|
|
525
|
+
addServerHandler({
|
|
526
|
+
method: "get",
|
|
527
|
+
route: "/llms-full.txt",
|
|
528
|
+
handler: resolveRuntimeModule("./server/api/agent-llms-full.js")
|
|
529
|
+
});
|
|
530
|
+
addServerHandler({
|
|
531
|
+
method: "get",
|
|
532
|
+
route: "/:locale/llms.txt",
|
|
533
|
+
handler: resolveRuntimeModule("./server/api/agent-llms.js")
|
|
534
|
+
});
|
|
535
|
+
addServerHandler({
|
|
536
|
+
method: "get",
|
|
537
|
+
route: "/:locale/llms-full.txt",
|
|
538
|
+
handler: resolveRuntimeModule("./server/api/agent-llms-full.js")
|
|
539
|
+
});
|
|
540
|
+
addServerHandler({
|
|
541
|
+
method: "get",
|
|
542
|
+
route: "/raw/**:slug",
|
|
543
|
+
handler: resolveRuntimeModule("./server/api/agent-raw.js")
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
if (agent.markdownNegotiation) {
|
|
547
|
+
addServerHandler({
|
|
548
|
+
middleware: true,
|
|
549
|
+
handler: resolveRuntimeModule("./server/middleware/agent-markdown.js")
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
if (agent.linkHeaders) {
|
|
553
|
+
addServerHandler({
|
|
554
|
+
middleware: true,
|
|
555
|
+
handler: resolveRuntimeModule("./server/middleware/agent-link-headers.js")
|
|
556
|
+
});
|
|
557
|
+
}
|
|
508
558
|
};
|
|
509
559
|
const registerContentSearchServerHandlers = (apiBaseURL, search, resolveRuntimeModule) => {
|
|
510
560
|
const searchBaseURL = search.apiBaseURL || `${apiBaseURL.replace(/\/$/, "")}/search`;
|
|
@@ -523,12 +573,58 @@ const registerContentSearchServerHandlers = (apiBaseURL, search, resolveRuntimeM
|
|
|
523
573
|
}
|
|
524
574
|
};
|
|
525
575
|
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
576
|
+
const registerContentComponentsTemplate = (addTemplateImpl) => {
|
|
577
|
+
addTemplateImpl({
|
|
578
|
+
filename: "content-components.mjs",
|
|
579
|
+
getContents({ app, nuxt }) {
|
|
580
|
+
const componentsMap = app.components.filter((component) => {
|
|
581
|
+
if (component.island) {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
if (component.filePath.endsWith(".css")) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
if (component.pascalName === "ClientOnly" || component.filePath.includes("nuxt/dist/") || component.filePath.includes("NuxtWelcome")) {
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
return true;
|
|
591
|
+
}).reduce((map, component) => {
|
|
592
|
+
const importPath = isAbsolute(component.filePath) ? "./" + relative(nuxt.options.buildDir, component.filePath).replace(/\b\.(?!vue)\w+$/g, "") : component.filePath.replace(/\b\.(?!vue)\w+$/g, "");
|
|
593
|
+
map[component.pascalName] = map[component.pascalName] || [
|
|
594
|
+
component.pascalName,
|
|
595
|
+
importPath,
|
|
596
|
+
component.global,
|
|
597
|
+
component.export || "default"
|
|
598
|
+
];
|
|
599
|
+
return map;
|
|
600
|
+
}, {});
|
|
601
|
+
const componentsList = Object.values(componentsMap);
|
|
602
|
+
const globalComponents = componentsList.filter((component) => component[2]).map((component) => component[0]);
|
|
603
|
+
const localComponents = componentsList.filter((component) => !component[2]);
|
|
604
|
+
return [
|
|
605
|
+
"const pickExport = (mod, exportName, componentName, path) => {",
|
|
606
|
+
" const resolved = exportName === 'default' ? mod?.default || mod : mod?.[exportName]",
|
|
607
|
+
" if (!resolved) {",
|
|
608
|
+
' throw new Error(`[nuxt-content] Missing export "${exportName}" for component "${componentName}" in "${path}".`)',
|
|
609
|
+
" }",
|
|
610
|
+
" return resolved",
|
|
611
|
+
"}",
|
|
612
|
+
"export const localComponentLoaders = {",
|
|
613
|
+
...localComponents.map(([pascalName, path, , exp]) => {
|
|
614
|
+
const pathLiteral = JSON.stringify(path);
|
|
615
|
+
const exportLiteral = JSON.stringify(exp);
|
|
616
|
+
const nameLiteral = JSON.stringify(pascalName);
|
|
617
|
+
return ` ${pascalName}: () => import(${pathLiteral}).then(mod => pickExport(mod, ${exportLiteral}, ${nameLiteral}, ${pathLiteral})),`;
|
|
618
|
+
}),
|
|
619
|
+
"}",
|
|
620
|
+
`export const globalComponents = ${JSON.stringify(globalComponents)}`,
|
|
621
|
+
`export const localComponents = ${JSON.stringify(localComponents.map((component) => component[0]))}`
|
|
622
|
+
].join("\n");
|
|
623
|
+
}
|
|
624
|
+
});
|
|
531
625
|
};
|
|
626
|
+
|
|
627
|
+
const SITEMAP_INDEX = "sitemap_index.xml";
|
|
532
628
|
const countTag = (xml, tag) => (xml.match(new RegExp(`<${tag}>`, "g")) || []).length;
|
|
533
629
|
const extractLocValues = (xml) => {
|
|
534
630
|
return Array.from(xml.matchAll(/<loc>([^<]+)<\/loc>/g), (match) => match[1]);
|
|
@@ -595,10 +691,9 @@ const discoverSitemapsFromDisk = async (outputPublicDir) => {
|
|
|
595
691
|
}
|
|
596
692
|
const rootSitemapPath = join$1(outputPublicDir, "sitemap.xml");
|
|
597
693
|
const rootSitemapXml = await readFile(rootSitemapPath, "utf8");
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
);
|
|
694
|
+
if (!(countTag(rootSitemapXml, "url") > 0 || rootSitemapXml.includes("<urlset"))) {
|
|
695
|
+
throw new Error(`Content sitemap assertion failed: no child sitemap files were discovered in ${indexPath} or ${sitemapDir}, and ${rootSitemapPath} is not a urlset sitemap.`);
|
|
696
|
+
}
|
|
602
697
|
return [{
|
|
603
698
|
name: "sitemap",
|
|
604
699
|
path: rootSitemapPath,
|
|
@@ -633,7 +728,9 @@ async function assertGeneratedSitemaps({
|
|
|
633
728
|
logger
|
|
634
729
|
}) {
|
|
635
730
|
const discoveredSitemaps = targets || (outputPublicDir ? await discoverSitemapsFromDisk(outputPublicDir) : []);
|
|
636
|
-
|
|
731
|
+
if (discoveredSitemaps.length === 0) {
|
|
732
|
+
throw new Error("Content sitemap assertion failed: no sitemap targets were available for validation.");
|
|
733
|
+
}
|
|
637
734
|
const targetMap = new Map(discoveredSitemaps.map((target) => [target.name, target]));
|
|
638
735
|
const failures = [];
|
|
639
736
|
for (const sitemapName of Object.keys(options.sitemaps)) {
|
|
@@ -675,7 +772,7 @@ async function assertGeneratedSitemaps({
|
|
|
675
772
|
failures.push([
|
|
676
773
|
`- Placeholder sitemap URLs found: ${placeholderSiteUrls.join(", ")}`,
|
|
677
774
|
"Expected production URLs in generated sitemap loc values.",
|
|
678
|
-
"Set site.url or runtimeConfig.public.siteUrl to the deployed origin for production release checks."
|
|
775
|
+
"Set site.url or runtimeConfig.public.content.siteUrl to the deployed origin for production release checks."
|
|
679
776
|
].join(" "));
|
|
680
777
|
}
|
|
681
778
|
}
|
|
@@ -707,283 +804,14 @@ const createSitemapAssertionTargetsFromPrerenderedSitemaps = (sitemaps) => {
|
|
|
707
804
|
}
|
|
708
805
|
return true;
|
|
709
806
|
});
|
|
710
|
-
|
|
807
|
+
if (targets.length === 0) {
|
|
808
|
+
throw new Error("Content sitemap assertion failed: no sitemap urlsets were available from sitemap:prerender:done.");
|
|
809
|
+
}
|
|
711
810
|
return targets;
|
|
712
811
|
};
|
|
713
812
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
if (typeof entry === "string") {
|
|
717
|
-
return entry === name;
|
|
718
|
-
}
|
|
719
|
-
if (Array.isArray(entry) && typeof entry[0] === "string") {
|
|
720
|
-
return entry[0] === name;
|
|
721
|
-
}
|
|
722
|
-
return false;
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
function hasNuxtI18nModule(modules = []) {
|
|
726
|
-
return hasNuxtModule(modules, "@nuxtjs/i18n");
|
|
727
|
-
}
|
|
728
|
-
function hasNuxtSitemapModule(modules = []) {
|
|
729
|
-
return hasNuxtModule(modules, "@nuxtjs/sitemap");
|
|
730
|
-
}
|
|
731
|
-
function configureNuxtSitemapSource(nuxt, apiBaseURL, sitemapPath = "/sitemap") {
|
|
732
|
-
if (!hasNuxtSitemapModule(nuxt.options.modules)) {
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
const source = {
|
|
736
|
-
context: {
|
|
737
|
-
name: GINKO_SITEMAP_SOURCE_NAME
|
|
738
|
-
},
|
|
739
|
-
fetch: resolveContentSitemapSource(apiBaseURL, sitemapPath)
|
|
740
|
-
};
|
|
741
|
-
const sitemap = nuxt.options.sitemap ??= {};
|
|
742
|
-
const sources = Array.isArray(sitemap.sources) ? sitemap.sources : [];
|
|
743
|
-
sitemap.sources = [
|
|
744
|
-
...sources.filter((item) => {
|
|
745
|
-
if (typeof item === "string") return item !== source.fetch;
|
|
746
|
-
return item?.fetch !== source.fetch && item?.context?.name !== GINKO_SITEMAP_SOURCE_NAME;
|
|
747
|
-
}),
|
|
748
|
-
source
|
|
749
|
-
];
|
|
750
|
-
}
|
|
751
|
-
function resolveNuxtSitemapPrerenderRoutes(nuxt) {
|
|
752
|
-
if (!hasNuxtSitemapModule(nuxt.options.modules)) {
|
|
753
|
-
return [];
|
|
754
|
-
}
|
|
755
|
-
const nuxtSitemap = nuxt.options.sitemap;
|
|
756
|
-
if (nuxtSitemap?.sitemaps === false) {
|
|
757
|
-
return ["/sitemap.xml"];
|
|
758
|
-
}
|
|
759
|
-
const nuxtI18n = nuxt.options.i18n || {};
|
|
760
|
-
if (!hasNuxtI18nModule(nuxt.options.modules) || !Array.isArray(nuxtI18n.locales) || nuxtI18n.locales.length === 0) {
|
|
761
|
-
return ["/sitemap.xml"];
|
|
762
|
-
}
|
|
763
|
-
const childRoutes = nuxtI18n.locales.map((locale) => typeof locale === "string" ? locale : locale.language || locale.code).filter(Boolean).map((locale) => `/__sitemap__/${locale}.xml`);
|
|
764
|
-
return Array.from(/* @__PURE__ */ new Set(["/sitemap.xml", "/sitemap_index.xml", ...childRoutes]));
|
|
765
|
-
}
|
|
766
|
-
function resolveModuleI18nOptions(options, nuxt) {
|
|
767
|
-
if (options.i18n === false) {
|
|
768
|
-
return {
|
|
769
|
-
locales: [],
|
|
770
|
-
defaultLocale: void 0,
|
|
771
|
-
fallback: {},
|
|
772
|
-
translatedSlugs: false,
|
|
773
|
-
strictTranslatedSlugs: false
|
|
774
|
-
};
|
|
775
|
-
}
|
|
776
|
-
const moduleI18n = options.i18n === true ? {} : options.i18n || {};
|
|
777
|
-
const nuxtI18n = nuxt.options.i18n || {};
|
|
778
|
-
const nuxtLocales = Array.isArray(nuxtI18n.locales) ? nuxtI18n.locales.map((locale) => typeof locale === "string" ? locale : locale.code).filter(Boolean) : [];
|
|
779
|
-
const locales = Array.from(new Set([
|
|
780
|
-
moduleI18n.defaultLocale,
|
|
781
|
-
nuxtI18n.defaultLocale,
|
|
782
|
-
...moduleI18n.locales || [],
|
|
783
|
-
...nuxtLocales
|
|
784
|
-
].filter(Boolean)));
|
|
785
|
-
const defaultLocale = moduleI18n.defaultLocale || nuxtI18n.defaultLocale || locales[0];
|
|
786
|
-
return {
|
|
787
|
-
locales,
|
|
788
|
-
defaultLocale,
|
|
789
|
-
fallback: defu({}, moduleI18n.fallback),
|
|
790
|
-
translatedSlugs: moduleI18n.translatedSlugs ?? false,
|
|
791
|
-
strictTranslatedSlugs: moduleI18n.strictTranslatedSlugs ?? false
|
|
792
|
-
};
|
|
793
|
-
}
|
|
794
|
-
function normalizeSitemapOptions(options) {
|
|
795
|
-
if (options.sitemap === false) {
|
|
796
|
-
return false;
|
|
797
|
-
}
|
|
798
|
-
const sitemap = options.sitemap === true ? {} : options.sitemap;
|
|
799
|
-
return {
|
|
800
|
-
path: sitemap.path || "/sitemap",
|
|
801
|
-
include: sitemap.include,
|
|
802
|
-
exclude: sitemap.exclude || [],
|
|
803
|
-
includeDrafts: sitemap.includeDrafts,
|
|
804
|
-
assert: normalizeContentSitemapAssertOptions(sitemap.assert)
|
|
805
|
-
};
|
|
806
|
-
}
|
|
807
|
-
function normalizeSearchOptions(options) {
|
|
808
|
-
if (options.search === false) {
|
|
809
|
-
return false;
|
|
810
|
-
}
|
|
811
|
-
return {
|
|
812
|
-
engine: options.search?.engine || "minisearch",
|
|
813
|
-
ignoredTags: options.search?.ignoredTags || ["script", "style", "pre"],
|
|
814
|
-
filterQuery: options.search?.filterQuery || { _draft: false, _partial: false },
|
|
815
|
-
collections: options.search?.collections,
|
|
816
|
-
extraFields: options.search?.extraFields || [],
|
|
817
|
-
apiBaseURL: options.search?.apiBaseURL,
|
|
818
|
-
minisearch: normalizeMiniSearchOptions(options.search?.minisearch)
|
|
819
|
-
};
|
|
820
|
-
}
|
|
821
|
-
const defaultMiniSearchOptions = {
|
|
822
|
-
fields: ["title", "content", "headings"],
|
|
823
|
-
storeFields: ["path", "title", "excerpt", "anchor", "locale", "collection"],
|
|
824
|
-
boost: {
|
|
825
|
-
title: 4,
|
|
826
|
-
headings: 2,
|
|
827
|
-
content: 1
|
|
828
|
-
},
|
|
829
|
-
fuzzy: 0.2,
|
|
830
|
-
prefix: true
|
|
831
|
-
};
|
|
832
|
-
const requiredMiniSearchStoreFields = ["path", "title", "excerpt"];
|
|
833
|
-
function normalizeMiniSearchOptions(options = {}) {
|
|
834
|
-
const fields = options?.fields?.filter((field) => typeof field === "string" && field.length > 0);
|
|
835
|
-
const storeFields = options?.storeFields?.filter((field) => typeof field === "string" && field.length > 0);
|
|
836
|
-
const boost = Object.fromEntries(
|
|
837
|
-
Object.entries(options?.boost || {}).filter((entry) => typeof entry[0] === "string" && entry[0].length > 0 && typeof entry[1] === "number" && Number.isFinite(entry[1]))
|
|
838
|
-
);
|
|
839
|
-
const resolvedFields = fields?.length ? fields : [...defaultMiniSearchOptions.fields];
|
|
840
|
-
const resolvedStoreFields = storeFields?.length ? storeFields : defaultMiniSearchOptions.storeFields;
|
|
841
|
-
return {
|
|
842
|
-
fields: resolvedFields,
|
|
843
|
-
storeFields: Array.from(/* @__PURE__ */ new Set([...requiredMiniSearchStoreFields, ...resolvedStoreFields])),
|
|
844
|
-
boost: Object.keys(boost).length ? boost : { ...defaultMiniSearchOptions.boost },
|
|
845
|
-
fuzzy: typeof options?.fuzzy === "boolean" || typeof options?.fuzzy === "number" ? options.fuzzy : defaultMiniSearchOptions.fuzzy,
|
|
846
|
-
prefix: typeof options?.prefix === "boolean" ? options.prefix : defaultMiniSearchOptions.prefix
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
function createSearchRuntimeConfig(search, apiBaseURL) {
|
|
850
|
-
const resolvedApiBaseURL = search.apiBaseURL || `${apiBaseURL.replace(/\/$/, "")}/search`;
|
|
851
|
-
return {
|
|
852
|
-
apiBaseURL: resolvedApiBaseURL,
|
|
853
|
-
indexURL: `${resolvedApiBaseURL.replace(/\/$/, "")}/index.json`,
|
|
854
|
-
engine: search.engine || "minisearch",
|
|
855
|
-
minisearch: normalizeMiniSearchOptions(search.minisearch)
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
const resolveNuxtSiteUrl = (nuxt) => {
|
|
860
|
-
const publicRuntime = nuxt.options.runtimeConfig.public;
|
|
861
|
-
const configuredSiteUrl = publicRuntime.siteUrl;
|
|
862
|
-
if (typeof configuredSiteUrl === "string" && configuredSiteUrl.length > 0) {
|
|
863
|
-
return configuredSiteUrl;
|
|
864
|
-
}
|
|
865
|
-
const nuxtSite = nuxt.options.site;
|
|
866
|
-
return typeof nuxtSite?.url === "string" && nuxtSite.url.length > 0 ? nuxtSite.url : void 0;
|
|
867
|
-
};
|
|
868
|
-
const applyContentRuntimeConfig = (nuxt, options, contentContext, runtimeCollections, buildIntegrity, cacheIntegrity) => {
|
|
869
|
-
const searchRuntime = contentContext.search === false ? false : {
|
|
870
|
-
apiBaseURL: contentContext.search.apiBaseURL || `${options.api.baseURL.replace(/\/$/, "")}/search`,
|
|
871
|
-
indexURL: `${(contentContext.search.apiBaseURL || `${options.api.baseURL.replace(/\/$/, "")}/search`).replace(/\/$/, "")}/index.json`,
|
|
872
|
-
engine: contentContext.search.engine || "minisearch",
|
|
873
|
-
minisearch: normalizeMiniSearchOptions(contentContext.search.minisearch)
|
|
874
|
-
};
|
|
875
|
-
const contentRuntime = defu(nuxt.options.runtimeConfig.public.content, {
|
|
876
|
-
locales: contentContext.locales,
|
|
877
|
-
provider: contentContext.provider || "filesystem",
|
|
878
|
-
providers: contentContext.providers || {},
|
|
879
|
-
defaultLocale: contentContext.defaultLocale || void 0,
|
|
880
|
-
localeFallback: contentContext.localeFallback || {},
|
|
881
|
-
translatedSlugs: contentContext.translatedSlugs ?? false,
|
|
882
|
-
strictTranslatedSlugs: contentContext.strictTranslatedSlugs ?? false,
|
|
883
|
-
collections: runtimeCollections,
|
|
884
|
-
integrity: buildIntegrity,
|
|
885
|
-
experimental: {
|
|
886
|
-
stripQueryParameters: options.experimental.stripQueryParameters
|
|
887
|
-
},
|
|
888
|
-
respectPathCase: options.respectPathCase ?? false,
|
|
889
|
-
api: {
|
|
890
|
-
baseURL: options.api.baseURL
|
|
891
|
-
},
|
|
892
|
-
markdown: {
|
|
893
|
-
plugins: contentContext.markdown.plugins,
|
|
894
|
-
tags: contentContext.markdown.tags,
|
|
895
|
-
anchorLinks: contentContext.markdown.anchorLinks,
|
|
896
|
-
image: contentContext.markdown.image || "auto"
|
|
897
|
-
},
|
|
898
|
-
sitemap: contentContext.sitemap ? {
|
|
899
|
-
path: contentContext.sitemap.path || "/sitemap",
|
|
900
|
-
...contentContext.sitemap.include?.length ? { include: contentContext.sitemap.include } : {},
|
|
901
|
-
...contentContext.sitemap.exclude?.length ? { exclude: contentContext.sitemap.exclude } : {},
|
|
902
|
-
...typeof contentContext.sitemap.includeDrafts === "boolean" ? { includeDrafts: contentContext.sitemap.includeDrafts } : {}
|
|
903
|
-
} : false,
|
|
904
|
-
search: searchRuntime,
|
|
905
|
-
navigation: contentContext.navigation,
|
|
906
|
-
wsUrl: "",
|
|
907
|
-
contentHead: options.contentHead ?? true
|
|
908
|
-
});
|
|
909
|
-
const siteUrl = resolveNuxtSiteUrl(nuxt);
|
|
910
|
-
if (siteUrl) {
|
|
911
|
-
nuxt.options.runtimeConfig.public.siteUrl = siteUrl;
|
|
912
|
-
}
|
|
913
|
-
nuxt.options.runtimeConfig.public.content = contentRuntime;
|
|
914
|
-
nuxt.options.runtimeConfig.content = defu(nuxt.options.runtimeConfig.content, {
|
|
915
|
-
cacheVersion: CACHE_VERSION,
|
|
916
|
-
cacheIntegrity,
|
|
917
|
-
revalidate: options.revalidate && options.revalidate !== false && options.revalidate.token ? {
|
|
918
|
-
token: options.revalidate.token,
|
|
919
|
-
allowUnsigned: options.revalidate.allowUnsigned === true
|
|
920
|
-
} : false,
|
|
921
|
-
...contentContext,
|
|
922
|
-
collections: runtimeCollections
|
|
923
|
-
});
|
|
924
|
-
};
|
|
925
|
-
|
|
926
|
-
const registerContentComponentsTemplate = (addTemplateImpl) => {
|
|
927
|
-
addTemplateImpl({
|
|
928
|
-
filename: "content-components.mjs",
|
|
929
|
-
getContents({ app, nuxt }) {
|
|
930
|
-
const componentsMap = app.components.filter((component) => {
|
|
931
|
-
if (component.island) {
|
|
932
|
-
return false;
|
|
933
|
-
}
|
|
934
|
-
if (component.filePath.endsWith(".css")) {
|
|
935
|
-
return false;
|
|
936
|
-
}
|
|
937
|
-
if (component.pascalName === "ClientOnly" || component.filePath.includes("nuxt/dist/") || component.filePath.includes("NuxtWelcome")) {
|
|
938
|
-
return false;
|
|
939
|
-
}
|
|
940
|
-
return true;
|
|
941
|
-
}).reduce((map, component) => {
|
|
942
|
-
const importPath = isAbsolute(component.filePath) ? "./" + relative(nuxt.options.buildDir, component.filePath).replace(/\b\.(?!vue)\w+$/g, "") : component.filePath.replace(/\b\.(?!vue)\w+$/g, "");
|
|
943
|
-
map[component.pascalName] = map[component.pascalName] || [
|
|
944
|
-
component.pascalName,
|
|
945
|
-
importPath,
|
|
946
|
-
component.global,
|
|
947
|
-
component.export || "default"
|
|
948
|
-
];
|
|
949
|
-
return map;
|
|
950
|
-
}, {});
|
|
951
|
-
const componentsList = Object.values(componentsMap);
|
|
952
|
-
const globalComponents = componentsList.filter((component) => component[2]).map((component) => component[0]);
|
|
953
|
-
const localComponents = componentsList.filter((component) => !component[2]);
|
|
954
|
-
return [
|
|
955
|
-
"const pickExport = (mod, exportName, componentName, path) => {",
|
|
956
|
-
" const resolved = exportName === 'default' ? mod?.default || mod : mod?.[exportName]",
|
|
957
|
-
" if (!resolved) {",
|
|
958
|
-
' throw new Error(`[nuxt-content] Missing export "${exportName}" for component "${componentName}" in "${path}".`)',
|
|
959
|
-
" }",
|
|
960
|
-
" return resolved",
|
|
961
|
-
"}",
|
|
962
|
-
"export const localComponentLoaders = {",
|
|
963
|
-
...localComponents.map(([pascalName, path, , exp]) => {
|
|
964
|
-
const pathLiteral = JSON.stringify(path);
|
|
965
|
-
const exportLiteral = JSON.stringify(exp);
|
|
966
|
-
const nameLiteral = JSON.stringify(pascalName);
|
|
967
|
-
return ` ${pascalName}: () => import(${pathLiteral}).then(mod => pickExport(mod, ${exportLiteral}, ${nameLiteral}, ${pathLiteral})),`;
|
|
968
|
-
}),
|
|
969
|
-
"}",
|
|
970
|
-
`export const globalComponents = ${JSON.stringify(globalComponents)}`,
|
|
971
|
-
`export const localComponents = ${JSON.stringify(localComponents.map((component) => component[0]))}`
|
|
972
|
-
].join("\n");
|
|
973
|
-
}
|
|
974
|
-
});
|
|
975
|
-
};
|
|
976
|
-
|
|
977
|
-
const appendHook = (hooks, name, handler) => {
|
|
978
|
-
const existing = hooks[name];
|
|
979
|
-
if (!existing) {
|
|
980
|
-
hooks[name] = handler;
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
|
-
hooks[name] = Array.isArray(existing) ? [...existing, handler] : [existing, handler];
|
|
984
|
-
};
|
|
985
|
-
const resolveSitemapCollections = (collections, sitemap) => {
|
|
986
|
-
if (!sitemap || sitemap === false) {
|
|
813
|
+
const resolveSitemapCollections = (collections, sitemap) => {
|
|
814
|
+
if (!sitemap) {
|
|
987
815
|
return [];
|
|
988
816
|
}
|
|
989
817
|
const include = sitemap.include?.length ? sitemap.include : Object.keys(collections);
|
|
@@ -997,7 +825,7 @@ const toTranslatedSlugSourcePattern = (source) => {
|
|
|
997
825
|
return match ? `${match[1]}.*${match[2] || ""}` : segment;
|
|
998
826
|
}).join("/");
|
|
999
827
|
};
|
|
1000
|
-
const
|
|
828
|
+
const parseDerivedCollectionFiles = async (rootDir, collections, collectionNames, contentContext) => {
|
|
1001
829
|
const contentDir = resolve$1(rootDir, "content");
|
|
1002
830
|
const patterns = Array.from(new Set(
|
|
1003
831
|
collectionNames.flatMap((name) => {
|
|
@@ -1028,7 +856,7 @@ const parseCollectionFiles = async (rootDir, collections, collectionNames, conte
|
|
|
1028
856
|
for (const id of ids) {
|
|
1029
857
|
const file = resolve$1(contentDir, id);
|
|
1030
858
|
const content = await readFile(file, "utf8");
|
|
1031
|
-
const normalizedId = `content:${relative$1(contentDir, file).
|
|
859
|
+
const normalizedId = `content:${relative$1(contentDir, file).replace(/\\/g, "/")}`;
|
|
1032
860
|
const parsed = await transformContent(normalizedId, content, {
|
|
1033
861
|
markdown: contentContext.markdown,
|
|
1034
862
|
yaml: contentContext.yaml,
|
|
@@ -1042,29 +870,36 @@ const parseCollectionFiles = async (rootDir, collections, collectionNames, conte
|
|
|
1042
870
|
collectionResolver: (filePath) => resolveCollection(filePath, collections, contentContext.locales || [])
|
|
1043
871
|
}
|
|
1044
872
|
});
|
|
1045
|
-
const collection = parsed._collection ? collections[parsed._collection] : void 0;
|
|
1046
|
-
documents.push(...expandDataLocaleVariants(parsed, collection?.i18n));
|
|
873
|
+
const collection = typeof parsed._collection === "string" ? collections[parsed._collection] : void 0;
|
|
874
|
+
documents.push(...expandDataLocaleVariants(parsed, collection?.i18n === true ? void 0 : collection?.i18n));
|
|
1047
875
|
}
|
|
1048
876
|
return documents;
|
|
1049
877
|
};
|
|
1050
|
-
const
|
|
878
|
+
const collectDerivedDocuments = async (rootDir, contentContext) => {
|
|
1051
879
|
const collections = contentContext.collections || {};
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
const includeCollections = resolveSitemapCollections(collections, contentContext.sitemap);
|
|
1056
|
-
if (!includeCollections.length) {
|
|
1057
|
-
return [];
|
|
880
|
+
const includedCollections = resolveSitemapCollections(collections, contentContext.sitemap);
|
|
881
|
+
if (!includedCollections.length) {
|
|
882
|
+
return { collections, includedCollections, graph: buildContentGraph([], { locales: contentContext.locales, defaultLocale: contentContext.defaultLocale }) };
|
|
1058
883
|
}
|
|
1059
|
-
const documents = await
|
|
884
|
+
const documents = await parseDerivedCollectionFiles(rootDir, collections, includedCollections, contentContext);
|
|
1060
885
|
const graph = buildContentGraph(documents, {
|
|
1061
886
|
locales: contentContext.locales,
|
|
1062
887
|
defaultLocale: contentContext.defaultLocale
|
|
1063
888
|
});
|
|
889
|
+
return { collections, includedCollections, graph };
|
|
890
|
+
};
|
|
891
|
+
const collectDerivedPrerenderRoutes = async (rootDir, contentContext) => {
|
|
892
|
+
if (!contentContext.sitemap) {
|
|
893
|
+
return [];
|
|
894
|
+
}
|
|
895
|
+
const { includedCollections, graph } = await collectDerivedDocuments(rootDir, contentContext);
|
|
896
|
+
if (!includedCollections.length) {
|
|
897
|
+
return [];
|
|
898
|
+
}
|
|
1064
899
|
const routes = /* @__PURE__ */ new Set();
|
|
1065
|
-
for (const collection of
|
|
900
|
+
for (const collection of includedCollections) {
|
|
1066
901
|
const { defaultLocale } = resolveCollectionI18n(collection, contentContext);
|
|
1067
|
-
const includeDrafts =
|
|
902
|
+
const includeDrafts = Boolean(contentContext.sitemap.includeDrafts);
|
|
1068
903
|
const seenCanonicalKeys = /* @__PURE__ */ new Set();
|
|
1069
904
|
for (const contentId of graph.byCollection[collection] || []) {
|
|
1070
905
|
const document = graph.byId[contentId];
|
|
@@ -1091,18 +926,12 @@ const collectPrerenderRoutes = async (rootDir, contentContext) => {
|
|
|
1091
926
|
return Array.from(routes).sort();
|
|
1092
927
|
};
|
|
1093
928
|
const collectSitemapCollectionRouteCounts = async (rootDir, contentContext) => {
|
|
1094
|
-
const
|
|
1095
|
-
const includedCollections = resolveSitemapCollections(collections, contentContext.sitemap);
|
|
929
|
+
const { includedCollections, graph } = await collectDerivedDocuments(rootDir, contentContext);
|
|
1096
930
|
if (!includedCollections.length) {
|
|
1097
931
|
return {};
|
|
1098
932
|
}
|
|
1099
|
-
const documents = await parseCollectionFiles(rootDir, collections, includedCollections, contentContext);
|
|
1100
|
-
const graph = buildContentGraph(documents, {
|
|
1101
|
-
locales: contentContext.locales,
|
|
1102
|
-
defaultLocale: contentContext.defaultLocale
|
|
1103
|
-
});
|
|
1104
933
|
const counts = Object.fromEntries(includedCollections.map((collection) => [collection, 0]));
|
|
1105
|
-
const includeDrafts = contentContext.sitemap
|
|
934
|
+
const includeDrafts = contentContext.sitemap ? Boolean(contentContext.sitemap.includeDrafts) : false;
|
|
1106
935
|
for (const collection of includedCollections) {
|
|
1107
936
|
const seenCanonicalKeys = /* @__PURE__ */ new Set();
|
|
1108
937
|
for (const contentId of graph.byCollection[collection] || []) {
|
|
@@ -1126,12 +955,32 @@ const collectSitemapCollectionRouteCounts = async (rootDir, contentContext) => {
|
|
|
1126
955
|
}
|
|
1127
956
|
return counts;
|
|
1128
957
|
};
|
|
958
|
+
|
|
959
|
+
const appendHook = (hooks, name, handler) => {
|
|
960
|
+
const existing = hooks[name];
|
|
961
|
+
if (!existing) {
|
|
962
|
+
hooks[name] = handler;
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
hooks[name] = Array.isArray(existing) ? [...existing, handler] : [existing, handler];
|
|
966
|
+
};
|
|
1129
967
|
const registerContentNitroIntegrationHooks = (nitroConfig, options, contentContext) => {
|
|
1130
|
-
const
|
|
968
|
+
const getHookContentContext = () => {
|
|
969
|
+
if (!options.resolveContentContext) {
|
|
970
|
+
return contentContext;
|
|
971
|
+
}
|
|
972
|
+
try {
|
|
973
|
+
return options.resolveContentContext();
|
|
974
|
+
} catch {
|
|
975
|
+
return contentContext;
|
|
976
|
+
}
|
|
977
|
+
};
|
|
1131
978
|
nitroConfig.hooks ||= {};
|
|
1132
|
-
if (contentContext.sitemap
|
|
979
|
+
if (contentContext.sitemap && contentContext.sitemap.assert?.enabled) {
|
|
1133
980
|
appendHook(nitroConfig.hooks, "compiled", async (nitro) => {
|
|
1134
|
-
const
|
|
981
|
+
const hookContentContext = getHookContentContext();
|
|
982
|
+
const hookUsesFilesystemProvider = !hookContentContext.provider || hookContentContext.provider === "filesystem";
|
|
983
|
+
const assertOptions = hookContentContext.sitemap ? hookContentContext.sitemap.assert : void 0;
|
|
1135
984
|
if (!assertOptions || !shouldRunSitemapAssertionOnCompiled(assertOptions, nitro)) {
|
|
1136
985
|
return;
|
|
1137
986
|
}
|
|
@@ -1139,11 +988,11 @@ const registerContentNitroIntegrationHooks = (nitroConfig, options, contentConte
|
|
|
1139
988
|
await assertGeneratedSitemaps({
|
|
1140
989
|
outputPublicDir: nitro.options.output.publicDir,
|
|
1141
990
|
options: assertOptions,
|
|
1142
|
-
collectionRouteCounts:
|
|
991
|
+
collectionRouteCounts: hookUsesFilesystemProvider ? await collectSitemapCollectionRouteCounts(options.rootDir, hookContentContext) : {},
|
|
1143
992
|
logger: nitro.logger
|
|
1144
993
|
});
|
|
1145
994
|
} catch (error) {
|
|
1146
|
-
if (error
|
|
995
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
1147
996
|
return;
|
|
1148
997
|
}
|
|
1149
998
|
throw error;
|
|
@@ -1151,8 +1000,10 @@ const registerContentNitroIntegrationHooks = (nitroConfig, options, contentConte
|
|
|
1151
1000
|
});
|
|
1152
1001
|
}
|
|
1153
1002
|
appendHook(nitroConfig.hooks, "prerender:routes", async (routes) => {
|
|
1154
|
-
|
|
1155
|
-
|
|
1003
|
+
const hookContentContext = getHookContentContext();
|
|
1004
|
+
const hookUsesFilesystemProvider = !hookContentContext.provider || hookContentContext.provider === "filesystem";
|
|
1005
|
+
if (hookUsesFilesystemProvider) {
|
|
1006
|
+
for (const route of await collectDerivedPrerenderRoutes(options.rootDir, hookContentContext)) {
|
|
1156
1007
|
routes.add(route);
|
|
1157
1008
|
}
|
|
1158
1009
|
}
|
|
@@ -1163,12 +1014,157 @@ const registerContentNitroIntegrationHooks = (nitroConfig, options, contentConte
|
|
|
1163
1014
|
});
|
|
1164
1015
|
};
|
|
1165
1016
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1017
|
+
function hasNuxtModule(modules = [], name) {
|
|
1018
|
+
return modules.some((entry) => {
|
|
1019
|
+
if (typeof entry === "string") {
|
|
1020
|
+
return entry === name;
|
|
1021
|
+
}
|
|
1022
|
+
if (Array.isArray(entry) && typeof entry[0] === "string") {
|
|
1023
|
+
return entry[0] === name;
|
|
1024
|
+
}
|
|
1025
|
+
return false;
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
function hasNuxtI18nModule(modules = []) {
|
|
1029
|
+
return hasNuxtModule(modules, "@nuxtjs/i18n");
|
|
1030
|
+
}
|
|
1031
|
+
function hasNuxtSitemapModule(modules = []) {
|
|
1032
|
+
return hasNuxtModule(modules, "@nuxtjs/sitemap");
|
|
1033
|
+
}
|
|
1034
|
+
function configureNuxtSitemapSource(nuxt, apiBaseURL, sitemapPath = "/sitemap") {
|
|
1035
|
+
if (!hasNuxtSitemapModule(nuxt.options.modules)) {
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
const source = {
|
|
1039
|
+
context: {
|
|
1040
|
+
name: GINKO_SITEMAP_SOURCE_NAME
|
|
1041
|
+
},
|
|
1042
|
+
fetch: resolveContentSitemapSource(apiBaseURL, sitemapPath)
|
|
1043
|
+
};
|
|
1044
|
+
const sitemap = nuxt.options.sitemap ??= {};
|
|
1045
|
+
const sources = Array.isArray(sitemap.sources) ? sitemap.sources : [];
|
|
1046
|
+
sitemap.sources = [
|
|
1047
|
+
...sources.filter((item) => {
|
|
1048
|
+
if (typeof item === "string") return item !== source.fetch;
|
|
1049
|
+
return item?.fetch !== source.fetch && item?.context?.name !== GINKO_SITEMAP_SOURCE_NAME;
|
|
1050
|
+
}),
|
|
1051
|
+
source
|
|
1052
|
+
];
|
|
1053
|
+
}
|
|
1054
|
+
function resolveNuxtSitemapPrerenderRoutes(nuxt) {
|
|
1055
|
+
if (!hasNuxtSitemapModule(nuxt.options.modules)) {
|
|
1056
|
+
return [];
|
|
1057
|
+
}
|
|
1058
|
+
const nuxtSitemap = nuxt.options.sitemap;
|
|
1059
|
+
if (nuxtSitemap?.sitemaps === false) {
|
|
1060
|
+
return ["/sitemap.xml"];
|
|
1061
|
+
}
|
|
1062
|
+
const nuxtI18n = nuxt.options.i18n || {};
|
|
1063
|
+
if (!hasNuxtI18nModule(nuxt.options.modules) || !Array.isArray(nuxtI18n.locales) || nuxtI18n.locales.length === 0) {
|
|
1064
|
+
return ["/sitemap.xml"];
|
|
1065
|
+
}
|
|
1066
|
+
const childRoutes = nuxtI18n.locales.map((locale) => typeof locale === "string" ? locale : locale.language || locale.code).filter(Boolean).map((locale) => `/__sitemap__/${locale}.xml`);
|
|
1067
|
+
return Array.from(/* @__PURE__ */ new Set(["/sitemap.xml", "/sitemap_index.xml", ...childRoutes]));
|
|
1068
|
+
}
|
|
1069
|
+
function resolveModuleI18nOptions(options, nuxt) {
|
|
1070
|
+
if (options.i18n === false) {
|
|
1071
|
+
return {
|
|
1072
|
+
locales: [],
|
|
1073
|
+
defaultLocale: void 0,
|
|
1074
|
+
fallback: {},
|
|
1075
|
+
translatedSlugs: false,
|
|
1076
|
+
strictTranslatedSlugs: false
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
const moduleI18n = options.i18n === true ? {} : options.i18n || {};
|
|
1080
|
+
const nuxtI18n = nuxt.options.i18n || {};
|
|
1081
|
+
const nuxtLocales = Array.isArray(nuxtI18n.locales) ? nuxtI18n.locales.map((locale) => typeof locale === "string" ? locale : locale.code).filter(Boolean) : [];
|
|
1082
|
+
const locales = Array.from(new Set([
|
|
1083
|
+
moduleI18n.defaultLocale,
|
|
1084
|
+
nuxtI18n.defaultLocale,
|
|
1085
|
+
...moduleI18n.locales || [],
|
|
1086
|
+
...nuxtLocales
|
|
1087
|
+
].filter(Boolean)));
|
|
1088
|
+
const defaultLocale = moduleI18n.defaultLocale || nuxtI18n.defaultLocale || locales[0];
|
|
1089
|
+
return {
|
|
1090
|
+
locales,
|
|
1091
|
+
defaultLocale,
|
|
1092
|
+
fallback: defu({}, moduleI18n.fallback),
|
|
1093
|
+
translatedSlugs: moduleI18n.translatedSlugs ?? false,
|
|
1094
|
+
strictTranslatedSlugs: moduleI18n.strictTranslatedSlugs ?? false
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
function normalizeSitemapOptions(options) {
|
|
1098
|
+
if (options.sitemap === false) {
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
const sitemap = options.sitemap === true ? {} : options.sitemap;
|
|
1102
|
+
return {
|
|
1103
|
+
path: sitemap.path || "/sitemap",
|
|
1104
|
+
include: sitemap.include,
|
|
1105
|
+
exclude: sitemap.exclude || [],
|
|
1106
|
+
includeDrafts: sitemap.includeDrafts,
|
|
1107
|
+
assert: normalizeContentSitemapAssertOptions(sitemap.assert)
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
function normalizeSearchOptions(options) {
|
|
1111
|
+
if (options.search === false) {
|
|
1112
|
+
return false;
|
|
1113
|
+
}
|
|
1114
|
+
return {
|
|
1115
|
+
engine: options.search?.engine || "minisearch",
|
|
1116
|
+
ignoredTags: options.search?.ignoredTags || ["script", "style", "pre"],
|
|
1117
|
+
filterQuery: options.search?.filterQuery || { _draft: false, _partial: false },
|
|
1118
|
+
collections: options.search?.collections,
|
|
1119
|
+
extraFields: options.search?.extraFields || [],
|
|
1120
|
+
apiBaseURL: options.search?.apiBaseURL,
|
|
1121
|
+
minisearch: normalizeMiniSearchOptions(options.search?.minisearch)
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
const defaultMiniSearchOptions = {
|
|
1125
|
+
fields: ["title", "content", "headings"],
|
|
1126
|
+
storeFields: ["path", "title", "excerpt", "anchor", "locale", "collection"],
|
|
1127
|
+
boost: {
|
|
1128
|
+
title: 4,
|
|
1129
|
+
headings: 2,
|
|
1130
|
+
content: 1
|
|
1131
|
+
},
|
|
1132
|
+
fuzzy: 0.2,
|
|
1133
|
+
prefix: true
|
|
1134
|
+
};
|
|
1135
|
+
const requiredMiniSearchStoreFields = ["path", "title", "excerpt"];
|
|
1136
|
+
function normalizeMiniSearchOptions(options = {}) {
|
|
1137
|
+
const fields = options?.fields?.filter((field) => typeof field === "string" && field.length > 0);
|
|
1138
|
+
const storeFields = options?.storeFields?.filter((field) => typeof field === "string" && field.length > 0);
|
|
1139
|
+
const boost = Object.fromEntries(
|
|
1140
|
+
Object.entries(options?.boost || {}).filter((entry) => typeof entry[0] === "string" && entry[0].length > 0 && typeof entry[1] === "number" && Number.isFinite(entry[1]))
|
|
1141
|
+
);
|
|
1142
|
+
const resolvedFields = fields?.length ? fields : [...defaultMiniSearchOptions.fields];
|
|
1143
|
+
const resolvedStoreFields = storeFields?.length ? storeFields : defaultMiniSearchOptions.storeFields;
|
|
1144
|
+
return {
|
|
1145
|
+
fields: resolvedFields,
|
|
1146
|
+
storeFields: Array.from(/* @__PURE__ */ new Set([...requiredMiniSearchStoreFields, ...resolvedStoreFields])),
|
|
1147
|
+
boost: Object.keys(boost).length ? boost : { ...defaultMiniSearchOptions.boost },
|
|
1148
|
+
fuzzy: typeof options?.fuzzy === "boolean" || typeof options?.fuzzy === "number" ? options.fuzzy : defaultMiniSearchOptions.fuzzy,
|
|
1149
|
+
prefix: typeof options?.prefix === "boolean" ? options.prefix : defaultMiniSearchOptions.prefix
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
function createSearchRuntimeConfig(search, apiBaseURL) {
|
|
1153
|
+
const resolvedApiBaseURL = search.apiBaseURL || `${apiBaseURL.replace(/\/$/, "")}/search`;
|
|
1154
|
+
return {
|
|
1155
|
+
apiBaseURL: resolvedApiBaseURL,
|
|
1156
|
+
indexURL: `${resolvedApiBaseURL.replace(/\/$/, "")}/index.json`,
|
|
1157
|
+
engine: search.engine || "minisearch",
|
|
1158
|
+
minisearch: normalizeMiniSearchOptions(search.minisearch)
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
const getContentPageMeta = (page) => {
|
|
1163
|
+
const content = page.meta?.content;
|
|
1164
|
+
return content && typeof content === "object" ? content : void 0;
|
|
1165
|
+
};
|
|
1166
|
+
const isRouteConfig = (value) => typeof value === "string" || value !== null && typeof value === "object" && Object.values(value).every((entry) => typeof entry === "string");
|
|
1167
|
+
const describePage = (page) => page.file || page.path || "<unknown page>";
|
|
1172
1168
|
const expectedLocalesFor = (collection, locales, defaultLocale) => {
|
|
1173
1169
|
const collectionI18n = collection.i18n && typeof collection.i18n === "object" ? collection.i18n : void 0;
|
|
1174
1170
|
return collectionI18n?.locales?.length ? collectionI18n.locales : locales.length ? locales : defaultLocale ? [defaultLocale] : [];
|
|
@@ -1218,6 +1214,556 @@ function validatePage(page, contentMeta, collections, options) {
|
|
|
1218
1214
|
}
|
|
1219
1215
|
}
|
|
1220
1216
|
|
|
1217
|
+
const hasAgentSurface = (config) => Boolean(
|
|
1218
|
+
config.agent || Object.values(config.collections || {}).some((collection) => Boolean(collection.agent?.markdown))
|
|
1219
|
+
);
|
|
1220
|
+
const agentSectionIds = (sections) => new Set((sections || []).map((section) => section.id).filter(Boolean));
|
|
1221
|
+
const validateAgentConfig = (config, options, context) => {
|
|
1222
|
+
if (!hasAgentSurface(config)) return;
|
|
1223
|
+
const agentRoutes = normalizeAgentRouteOptions(options);
|
|
1224
|
+
if (!context.dev && agentRoutes.routes && agentRoutes.prerender && !config.agent?.site?.url) {
|
|
1225
|
+
throw new Error(
|
|
1226
|
+
"@lupinum/ginko-content agent prerender requires agent.site.url for non-dev builds. Set agent.site.url in content.config.ts or disable content.agent.prerender."
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
const sections = agentSectionIds(config.agent?.sections);
|
|
1230
|
+
const seenSections = /* @__PURE__ */ new Set();
|
|
1231
|
+
for (const section of config.agent?.sections || []) {
|
|
1232
|
+
if (!section.id) {
|
|
1233
|
+
throw new Error("@lupinum/ginko-content agent section ids must be non-empty strings.");
|
|
1234
|
+
}
|
|
1235
|
+
if (seenSections.has(section.id)) {
|
|
1236
|
+
throw new Error(`Duplicate Ginko agent section id "${section.id}". Agent section ids must be unique.`);
|
|
1237
|
+
}
|
|
1238
|
+
seenSections.add(section.id);
|
|
1239
|
+
}
|
|
1240
|
+
const assertSection = (id, owner) => {
|
|
1241
|
+
if (!id || id === "content") return;
|
|
1242
|
+
if (!sections.has(id)) {
|
|
1243
|
+
throw new Error(
|
|
1244
|
+
`${owner} references unknown Ginko agent section "${id}". Declare it in agent.sections or use the default "content" section.`
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
1248
|
+
for (const [name, collection] of Object.entries(config.collections || {})) {
|
|
1249
|
+
if (collection.agent?.markdown || collection.agent?.section) {
|
|
1250
|
+
assertSection(collection.agent.section, `Collection "${name}"`);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
for (const page of config.agent?.pages || []) {
|
|
1254
|
+
assertSection(page.section, `Agent app page "${page.id}"`);
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
const normalizeStaticRoutePath = (path) => {
|
|
1259
|
+
if (!path || path === "/") return "/";
|
|
1260
|
+
return `/${path.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}`;
|
|
1261
|
+
};
|
|
1262
|
+
const collectRawMarkdownLinksFromLlms = (markdown, siteUrl) => {
|
|
1263
|
+
const links = /* @__PURE__ */ new Set();
|
|
1264
|
+
const pattern = /\[[^\]]*\]\(([^)]+)\)/g;
|
|
1265
|
+
for (const match of markdown.matchAll(pattern)) {
|
|
1266
|
+
const href = match[1];
|
|
1267
|
+
if (!href) continue;
|
|
1268
|
+
try {
|
|
1269
|
+
const url = /^[a-z][a-z0-9+.-]*:/i.test(href) ? new URL(href) : new URL(href, siteUrl || "http://localhost:3000");
|
|
1270
|
+
if (url.pathname.startsWith("/raw/") && url.pathname.endsWith(".md")) links.add(url.pathname);
|
|
1271
|
+
} catch {
|
|
1272
|
+
if (href.startsWith("/raw/") && href.endsWith(".md")) links.add(href);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return Array.from(links);
|
|
1276
|
+
};
|
|
1277
|
+
const rawMarkdownRouteForPageRoute = (route) => {
|
|
1278
|
+
const normalized = normalizeStaticRoutePath(route);
|
|
1279
|
+
return normalized === "/" ? "/raw/index.md" : `/raw${normalized}.md`;
|
|
1280
|
+
};
|
|
1281
|
+
const collectRawMarkdownRoutesFromGeneratedFrontmatter = (markdown) => {
|
|
1282
|
+
const links = /* @__PURE__ */ new Set();
|
|
1283
|
+
const addRoutePath = (route) => {
|
|
1284
|
+
links.add(rawMarkdownRouteForPageRoute(route));
|
|
1285
|
+
};
|
|
1286
|
+
const addFrontmatterRoute = (frontmatter) => {
|
|
1287
|
+
const route = /^route:\s*"([^"]+)"/m.exec(frontmatter || "")?.[1];
|
|
1288
|
+
if (!route) return;
|
|
1289
|
+
addRoutePath(route);
|
|
1290
|
+
};
|
|
1291
|
+
const addSourceRoute = (source) => {
|
|
1292
|
+
if (!source) return;
|
|
1293
|
+
try {
|
|
1294
|
+
addRoutePath(new URL(source, "http://localhost:3000").pathname);
|
|
1295
|
+
} catch {
|
|
1296
|
+
addRoutePath(source);
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
const sourcePattern = /^Source:\s+(\S+)/gm;
|
|
1300
|
+
for (const match of markdown.matchAll(sourcePattern)) {
|
|
1301
|
+
addSourceRoute(match[1]);
|
|
1302
|
+
}
|
|
1303
|
+
const pageFrontmatterPattern = /^Source:\s+[^\n]+\n\n---\n([\s\S]*?)\n---/gm;
|
|
1304
|
+
for (const match of markdown.matchAll(pageFrontmatterPattern)) {
|
|
1305
|
+
addFrontmatterRoute(match[1]);
|
|
1306
|
+
}
|
|
1307
|
+
const firstFrontmatter = /^---\n([\s\S]*?)\n---/.exec(markdown)?.[1];
|
|
1308
|
+
addFrontmatterRoute(firstFrontmatter);
|
|
1309
|
+
return Array.from(links);
|
|
1310
|
+
};
|
|
1311
|
+
const publicOutputPath = (publicDir, route) => join(publicDir, normalizeStaticRoutePath(route).replace(/^\//, ""));
|
|
1312
|
+
|
|
1313
|
+
const hookNuxtBoundary$2 = (nuxt, name, callback) => {
|
|
1314
|
+
const hook = nuxt.hook;
|
|
1315
|
+
hook(name, callback);
|
|
1316
|
+
};
|
|
1317
|
+
const registerStaticOutputGeneration = ({
|
|
1318
|
+
nuxt,
|
|
1319
|
+
options,
|
|
1320
|
+
appContentConfig,
|
|
1321
|
+
contentContext,
|
|
1322
|
+
resolvedI18n,
|
|
1323
|
+
resolveRuntimeModule,
|
|
1324
|
+
getSearchRuntime
|
|
1325
|
+
}) => {
|
|
1326
|
+
if (nuxt.options.dev) return;
|
|
1327
|
+
hookNuxtBoundary$2(nuxt, "nitro:build:before", (nitro) => {
|
|
1328
|
+
nitro.hooks.hook("prerender:init", (prerenderer) => {
|
|
1329
|
+
prerenderer.hooks.hook("compiled", async () => {
|
|
1330
|
+
const searchRuntime = getSearchRuntime();
|
|
1331
|
+
const publicDir = nitro.options.output.publicDir || nuxt.options.nitro?.output?.publicDir || resolve$1(nuxt.options.rootDir, ".output/public");
|
|
1332
|
+
const serverFilename = typeof prerenderer.options.rollupConfig?.output?.entryFileNames === "string" ? prerenderer.options.rollupConfig.output.entryFileNames : "index.mjs";
|
|
1333
|
+
const serverEntrypoint = resolve$1(prerenderer.options.output.serverDir, serverFilename);
|
|
1334
|
+
const { localFetch } = await import(pathToFileURL(serverEntrypoint).href);
|
|
1335
|
+
if (searchRuntime !== false && searchRuntime.engine !== "cms" && (!contentContext.provider || contentContext.provider === "filesystem")) {
|
|
1336
|
+
const response = await localFetch(searchRuntime.indexURL);
|
|
1337
|
+
if (!response.ok) {
|
|
1338
|
+
throw new Error(`Failed to generate search index: [${response.status}] ${response.statusText}`);
|
|
1339
|
+
}
|
|
1340
|
+
const json = await response.text();
|
|
1341
|
+
const indexPath = publicOutputPath(publicDir, searchRuntime.indexURL);
|
|
1342
|
+
mkdirSync(dirname(indexPath), { recursive: true });
|
|
1343
|
+
writeFileSync(indexPath, json, "utf8");
|
|
1344
|
+
if (searchRuntime.engine === "pagefind") {
|
|
1345
|
+
const records = JSON.parse(json);
|
|
1346
|
+
const { writePagefindIndex } = await import(resolveRuntimeModule("./server/pagefind.js"));
|
|
1347
|
+
await writePagefindIndex(records, resolve$1(publicDir, "pagefind"));
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
const agentRoutes = normalizeAgentRouteOptions(options);
|
|
1351
|
+
if (agentRoutes.routes && agentRoutes.prerender && appContentConfig.agent) {
|
|
1352
|
+
const defaultLocale = appContentConfig.agent.site?.defaultLocale || resolvedI18n.defaultLocale;
|
|
1353
|
+
const locales = appContentConfig.agent.site?.locales?.length ? appContentConfig.agent.site.locales : resolvedI18n.locales;
|
|
1354
|
+
const llmsRoutes = [
|
|
1355
|
+
"/llms.txt",
|
|
1356
|
+
"/llms-full.txt",
|
|
1357
|
+
...locales.filter((locale) => locale && locale !== defaultLocale).flatMap((locale) => [`/${locale}/llms.txt`, `/${locale}/llms-full.txt`])
|
|
1358
|
+
];
|
|
1359
|
+
const markdownRoutes = /* @__PURE__ */ new Set();
|
|
1360
|
+
for (const route of llmsRoutes) {
|
|
1361
|
+
const response = await localFetch(route);
|
|
1362
|
+
if (!response.ok) {
|
|
1363
|
+
throw new Error(`Failed to generate agent markdown route ${route}: [${response.status}] ${response.statusText}`);
|
|
1364
|
+
}
|
|
1365
|
+
const body = await response.text();
|
|
1366
|
+
const outputPath = publicOutputPath(publicDir, route);
|
|
1367
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
1368
|
+
writeFileSync(outputPath, body, "utf8");
|
|
1369
|
+
if (/\/llms\.txt$/i.test(route)) {
|
|
1370
|
+
collectRawMarkdownLinksFromLlms(body, appContentConfig.agent.site?.url).forEach((link) => markdownRoutes.add(link));
|
|
1371
|
+
} else if (/\/llms-full\.txt$/i.test(route)) {
|
|
1372
|
+
collectRawMarkdownRoutesFromGeneratedFrontmatter(body).forEach((link) => markdownRoutes.add(link));
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
for (const route of markdownRoutes) {
|
|
1376
|
+
const response = await localFetch(route);
|
|
1377
|
+
if (!response.ok) {
|
|
1378
|
+
throw new Error(`Failed to generate agent markdown route ${route}: [${response.status}] ${response.statusText}`);
|
|
1379
|
+
}
|
|
1380
|
+
const body = await response.text();
|
|
1381
|
+
const outputPath = publicOutputPath(publicDir, route);
|
|
1382
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
1383
|
+
writeFileSync(outputPath, body, "utf8");
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
});
|
|
1388
|
+
});
|
|
1389
|
+
};
|
|
1390
|
+
|
|
1391
|
+
const hookNuxtBoundary$1 = (nuxt, name, callback) => {
|
|
1392
|
+
const hook = nuxt.hook;
|
|
1393
|
+
hook(name, callback);
|
|
1394
|
+
};
|
|
1395
|
+
const registerContentNitroConfig = ({
|
|
1396
|
+
nuxt,
|
|
1397
|
+
options,
|
|
1398
|
+
appContentConfig,
|
|
1399
|
+
contentContext,
|
|
1400
|
+
runtimeInlineDependencies,
|
|
1401
|
+
buildIntegrity,
|
|
1402
|
+
resolvedI18n,
|
|
1403
|
+
resolveRuntimeModule,
|
|
1404
|
+
resolveModuleFile,
|
|
1405
|
+
getResolvedContentContext,
|
|
1406
|
+
getSearchRuntime
|
|
1407
|
+
}) => {
|
|
1408
|
+
hookNuxtBoundary$1(nuxt, "nitro:config", (nitroConfig) => {
|
|
1409
|
+
const searchRuntime = getSearchRuntime();
|
|
1410
|
+
nitroConfig.prerender = nitroConfig.prerender || {};
|
|
1411
|
+
nitroConfig.prerender.routes = nitroConfig.prerender.routes || [];
|
|
1412
|
+
const usesFilesystemProvider = !contentContext.provider || contentContext.provider === "filesystem";
|
|
1413
|
+
if (!nuxt.options.dev && usesFilesystemProvider) {
|
|
1414
|
+
nitroConfig.prerender.routes.unshift(`${options.api.baseURL}/cache.${buildIntegrity}.json`);
|
|
1415
|
+
}
|
|
1416
|
+
const sources = useContentMounts(nuxt, contentContext.sources);
|
|
1417
|
+
nitroConfig.devStorage = Object.assign(nitroConfig.devStorage || {}, sources);
|
|
1418
|
+
nitroConfig.devStorage["cache:content"] = {
|
|
1419
|
+
driver: "fs",
|
|
1420
|
+
base: resolve$1(nuxt.options.buildDir, "content-cache")
|
|
1421
|
+
};
|
|
1422
|
+
for (const source of Object.values(sources)) {
|
|
1423
|
+
if (source.driver === "fs" && typeof source.base === "string" && source.base.includes(nuxt.options.srcDir)) {
|
|
1424
|
+
const wildcard = join(source.base, "**/*").replace(withTrailingSlash(nuxt.options.srcDir), "");
|
|
1425
|
+
nuxt.options.ignore.push(wildcard, `!${wildcard}.vue`);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
nitroConfig.bundledStorage = nitroConfig.bundledStorage || [];
|
|
1429
|
+
nitroConfig.bundledStorage.push("cache:content");
|
|
1430
|
+
nitroConfig.externals = defu(typeof nitroConfig.externals === "object" ? nitroConfig.externals : {}, {
|
|
1431
|
+
inline: [
|
|
1432
|
+
resolveModuleFile("./runtime"),
|
|
1433
|
+
...runtimeInlineDependencies
|
|
1434
|
+
]
|
|
1435
|
+
});
|
|
1436
|
+
if (searchRuntime !== false && searchRuntime.engine !== "cms" && usesFilesystemProvider) {
|
|
1437
|
+
nitroConfig.routeRules = nitroConfig.routeRules || {};
|
|
1438
|
+
nitroConfig.routeRules[searchRuntime.indexURL] = {
|
|
1439
|
+
prerender: true,
|
|
1440
|
+
headers: { "Content-Type": "application/json; charset=utf-8" }
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
if (contentContext.sitemap !== false) {
|
|
1444
|
+
nitroConfig.plugins ||= [];
|
|
1445
|
+
const sitemapPlugin = resolveRuntimeModule("server/plugins/sitemap.js");
|
|
1446
|
+
if (!nitroConfig.plugins.includes(sitemapPlugin)) {
|
|
1447
|
+
nitroConfig.plugins.push(sitemapPlugin);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
if (contentContext.cache) {
|
|
1451
|
+
nitroConfig.plugins ||= [];
|
|
1452
|
+
const cachePlugin = resolveRuntimeModule("server/plugins/cache.js");
|
|
1453
|
+
if (!nitroConfig.plugins.includes(cachePlugin)) {
|
|
1454
|
+
nitroConfig.plugins.push(cachePlugin);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
registerContentNitroIntegrationHooks(nitroConfig, {
|
|
1458
|
+
rootDir: nuxt.options.rootDir,
|
|
1459
|
+
sitemapPrerenderRoutes: () => contentContext.sitemap === false ? [] : resolveNuxtSitemapPrerenderRoutes(nuxt),
|
|
1460
|
+
resolveContentContext: getResolvedContentContext
|
|
1461
|
+
}, {
|
|
1462
|
+
collections: contentContext.collections,
|
|
1463
|
+
locales: contentContext.locales,
|
|
1464
|
+
defaultLocale: contentContext.defaultLocale,
|
|
1465
|
+
translatedSlugs: contentContext.translatedSlugs,
|
|
1466
|
+
respectPathCase: contentContext.respectPathCase,
|
|
1467
|
+
markdown: processMarkdownOptions(contentContext.markdown),
|
|
1468
|
+
yaml: contentContext.yaml,
|
|
1469
|
+
csv: contentContext.csv,
|
|
1470
|
+
sitemap: contentContext.sitemap,
|
|
1471
|
+
provider: contentContext.provider
|
|
1472
|
+
});
|
|
1473
|
+
const agentRoutes = normalizeAgentRouteOptions(options);
|
|
1474
|
+
if (agentRoutes.routes && agentRoutes.prerender && appContentConfig.agent) {
|
|
1475
|
+
nitroConfig.prerender.routes.push("/llms.txt", "/llms-full.txt");
|
|
1476
|
+
for (const locale of appContentConfig.agent.site?.locales || resolvedI18n.locales || []) {
|
|
1477
|
+
if (locale && locale !== (appContentConfig.agent.site?.defaultLocale || resolvedI18n.defaultLocale)) {
|
|
1478
|
+
nitroConfig.prerender.routes.push(`/${locale}/llms.txt`, `/${locale}/llms-full.txt`);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
for (const page of appContentConfig.agent.pages || []) {
|
|
1482
|
+
const routes = typeof page.route === "string" ? [page.route] : Object.values(page.route);
|
|
1483
|
+
for (const route of routes) {
|
|
1484
|
+
const normalized = route === "/" ? "/" : `/${route.replace(/^\/+|\/+$/g, "")}`;
|
|
1485
|
+
nitroConfig.prerender.routes.push(
|
|
1486
|
+
normalized === "/" ? "/raw/index.md" : `/raw${normalized}.md`
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
});
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
const BUILTIN_PLUGIN_PEER_DEPS = {
|
|
1495
|
+
highlight: "shiki",
|
|
1496
|
+
math: "katex",
|
|
1497
|
+
mermaid: "beautiful-mermaid"
|
|
1498
|
+
};
|
|
1499
|
+
function assertConfiguredProviderAvailable(contentContext) {
|
|
1500
|
+
const provider = contentContext.provider || "filesystem";
|
|
1501
|
+
if (provider === "filesystem") return;
|
|
1502
|
+
if (contentContext.providers?.[provider]) return;
|
|
1503
|
+
if (provider === "cms") {
|
|
1504
|
+
throw new Error('content.config.ts sets provider "cms", but no CMS provider module registered it. Add @lupinum/ginko-cms to nuxt.config.ts modules or remove provider: "cms".');
|
|
1505
|
+
}
|
|
1506
|
+
throw new Error(`content.config.ts sets provider "${provider}", but no provider module registered it. Register a module for "${provider}" or add it to content providers.`);
|
|
1507
|
+
}
|
|
1508
|
+
function validateCollectionNames(collections) {
|
|
1509
|
+
normalizeContentConfigCollectionNames(collections);
|
|
1510
|
+
}
|
|
1511
|
+
function validateRemovedMarkdownOptions(options) {
|
|
1512
|
+
if (options.highlight !== void 0) {
|
|
1513
|
+
throw new Error("`content.highlight` was removed. Enable syntax highlighting with `content.markdown.plugins`, for example `[['highlight', { ...options }]]`.");
|
|
1514
|
+
}
|
|
1515
|
+
const markdown = options.markdown || {};
|
|
1516
|
+
const removedOptions = ["mdc", "remarkPlugins", "rehypePlugins", "toc"];
|
|
1517
|
+
const removed = removedOptions.filter((key) => typeof markdown[key] !== "undefined");
|
|
1518
|
+
if (removed.length) {
|
|
1519
|
+
throw new Error(`Removed markdown options: ${removed.map((option) => `content.markdown.${String(option)}`).join(", ")}. Use ordered \`content.markdown.plugins\` entries instead.`);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
async function validateBuiltinMarkdownPlugins(plugins, resolvePath) {
|
|
1523
|
+
for (const plugin of plugins) {
|
|
1524
|
+
const peerDependency = BUILTIN_PLUGIN_PEER_DEPS[plugin.name];
|
|
1525
|
+
if (!peerDependency) {
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
try {
|
|
1529
|
+
await resolvePath(peerDependency);
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
const next = new Error(`Markdown plugin "${plugin.name}" requires "${peerDependency}" to be installed.`);
|
|
1532
|
+
next.cause = error;
|
|
1533
|
+
throw next;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
const contentModuleDefaults = {
|
|
1539
|
+
api: {
|
|
1540
|
+
baseURL: "/api/_content"
|
|
1541
|
+
},
|
|
1542
|
+
i18n: true,
|
|
1543
|
+
sitemap: true,
|
|
1544
|
+
search: {
|
|
1545
|
+
engine: "minisearch",
|
|
1546
|
+
ignoredTags: ["script", "style", "pre"],
|
|
1547
|
+
filterQuery: { _draft: false, _partial: false },
|
|
1548
|
+
extraFields: [],
|
|
1549
|
+
minisearch: {
|
|
1550
|
+
fields: [...defaultMiniSearchOptions.fields],
|
|
1551
|
+
storeFields: [...defaultMiniSearchOptions.storeFields],
|
|
1552
|
+
boost: { ...defaultMiniSearchOptions.boost },
|
|
1553
|
+
fuzzy: defaultMiniSearchOptions.fuzzy,
|
|
1554
|
+
prefix: defaultMiniSearchOptions.prefix
|
|
1555
|
+
}
|
|
1556
|
+
},
|
|
1557
|
+
watch: true,
|
|
1558
|
+
sources: {},
|
|
1559
|
+
ignores: [],
|
|
1560
|
+
collections: {},
|
|
1561
|
+
markdown: {
|
|
1562
|
+
plugins: [],
|
|
1563
|
+
tags: {
|
|
1564
|
+
code: "ProseCode",
|
|
1565
|
+
img: "ProseImg",
|
|
1566
|
+
pre: "ProsePre"
|
|
1567
|
+
},
|
|
1568
|
+
anchorLinks: {
|
|
1569
|
+
depth: 4,
|
|
1570
|
+
exclude: [1]
|
|
1571
|
+
},
|
|
1572
|
+
image: "auto"
|
|
1573
|
+
},
|
|
1574
|
+
yaml: {},
|
|
1575
|
+
csv: {
|
|
1576
|
+
delimiter: ",",
|
|
1577
|
+
json: true
|
|
1578
|
+
},
|
|
1579
|
+
navigation: {
|
|
1580
|
+
fields: []
|
|
1581
|
+
},
|
|
1582
|
+
agent: {
|
|
1583
|
+
routes: true,
|
|
1584
|
+
linkHeaders: true,
|
|
1585
|
+
markdownNegotiation: true,
|
|
1586
|
+
prerender: true
|
|
1587
|
+
},
|
|
1588
|
+
contentHead: true,
|
|
1589
|
+
respectPathCase: false,
|
|
1590
|
+
experimental: {
|
|
1591
|
+
stripQueryParameters: false
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
const resolveNuxtSiteUrl = (nuxt) => {
|
|
1596
|
+
const publicRuntime = nuxt.options.runtimeConfig.public;
|
|
1597
|
+
const publicContentRuntime = publicRuntime.content;
|
|
1598
|
+
const configuredSiteUrl = publicContentRuntime?.siteUrl || publicRuntime.siteUrl;
|
|
1599
|
+
if (typeof configuredSiteUrl === "string" && configuredSiteUrl.length > 0) {
|
|
1600
|
+
return configuredSiteUrl;
|
|
1601
|
+
}
|
|
1602
|
+
const nuxtSite = nuxt.options.site;
|
|
1603
|
+
return typeof nuxtSite?.url === "string" && nuxtSite.url.length > 0 ? nuxtSite.url : void 0;
|
|
1604
|
+
};
|
|
1605
|
+
const sanitizePublicMarkdownPluginValue = (value) => {
|
|
1606
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
1607
|
+
return void 0;
|
|
1608
|
+
}
|
|
1609
|
+
if (Array.isArray(value)) {
|
|
1610
|
+
return value.map((item) => sanitizePublicMarkdownPluginValue(item)).filter((item) => item !== void 0);
|
|
1611
|
+
}
|
|
1612
|
+
if (typeof value !== "object" || value === null) {
|
|
1613
|
+
return value;
|
|
1614
|
+
}
|
|
1615
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1616
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
1617
|
+
return value;
|
|
1618
|
+
}
|
|
1619
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "transformers").map(([key, item]) => [key, sanitizePublicMarkdownPluginValue(item)]).filter(([, item]) => item !== void 0));
|
|
1620
|
+
};
|
|
1621
|
+
const sanitizePublicMarkdownPlugins = (plugins) => plugins.map((plugin) => ({
|
|
1622
|
+
name: plugin.name,
|
|
1623
|
+
options: sanitizePublicMarkdownPluginValue(plugin.options || {})
|
|
1624
|
+
}));
|
|
1625
|
+
const sanitizePrivateMarkdownPluginValue = (value) => {
|
|
1626
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
1627
|
+
return void 0;
|
|
1628
|
+
}
|
|
1629
|
+
if (Array.isArray(value)) {
|
|
1630
|
+
return value.map((item) => sanitizePrivateMarkdownPluginValue(item)).filter((item) => item !== void 0);
|
|
1631
|
+
}
|
|
1632
|
+
if (typeof value !== "object" || value === null) {
|
|
1633
|
+
return value;
|
|
1634
|
+
}
|
|
1635
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1636
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
1637
|
+
return value;
|
|
1638
|
+
}
|
|
1639
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, sanitizePrivateMarkdownPluginValue(item)]).filter(([, item]) => item !== void 0));
|
|
1640
|
+
};
|
|
1641
|
+
const sanitizePrivateMarkdownPlugins = (plugins) => plugins.map((plugin) => ({
|
|
1642
|
+
name: plugin.name,
|
|
1643
|
+
options: sanitizePrivateMarkdownPluginValue(plugin.options || {})
|
|
1644
|
+
}));
|
|
1645
|
+
const applyContentRuntimeConfig = (nuxt, options, contentContext, runtimeCollections, buildIntegrity, cacheIntegrity) => {
|
|
1646
|
+
const revalidate = options.revalidate === false ? void 0 : options.revalidate;
|
|
1647
|
+
const searchRuntime = contentContext.search === false ? false : {
|
|
1648
|
+
apiBaseURL: contentContext.search.apiBaseURL || `${options.api.baseURL.replace(/\/$/, "")}/search`,
|
|
1649
|
+
indexURL: `${(contentContext.search.apiBaseURL || `${options.api.baseURL.replace(/\/$/, "")}/search`).replace(/\/$/, "")}/index.json`,
|
|
1650
|
+
engine: contentContext.search.engine || "minisearch",
|
|
1651
|
+
minisearch: normalizeMiniSearchOptions(contentContext.search.minisearch)
|
|
1652
|
+
};
|
|
1653
|
+
const siteUrl = resolveNuxtSiteUrl(nuxt);
|
|
1654
|
+
const contentRuntime = defu(nuxt.options.runtimeConfig.public.content, {
|
|
1655
|
+
...siteUrl ? { siteUrl } : {},
|
|
1656
|
+
locales: contentContext.locales,
|
|
1657
|
+
provider: contentContext.provider || "filesystem",
|
|
1658
|
+
providers: contentContext.providers || {},
|
|
1659
|
+
defaultLocale: contentContext.defaultLocale || void 0,
|
|
1660
|
+
localeFallback: contentContext.localeFallback || {},
|
|
1661
|
+
translatedSlugs: contentContext.translatedSlugs ?? false,
|
|
1662
|
+
strictTranslatedSlugs: contentContext.strictTranslatedSlugs ?? false,
|
|
1663
|
+
collections: runtimeCollections,
|
|
1664
|
+
integrity: buildIntegrity,
|
|
1665
|
+
experimental: {
|
|
1666
|
+
stripQueryParameters: options.experimental.stripQueryParameters
|
|
1667
|
+
},
|
|
1668
|
+
respectPathCase: options.respectPathCase ?? false,
|
|
1669
|
+
api: {
|
|
1670
|
+
baseURL: options.api.baseURL
|
|
1671
|
+
},
|
|
1672
|
+
markdown: {
|
|
1673
|
+
plugins: sanitizePublicMarkdownPlugins(contentContext.markdown.plugins),
|
|
1674
|
+
tags: contentContext.markdown.tags,
|
|
1675
|
+
anchorLinks: contentContext.markdown.anchorLinks,
|
|
1676
|
+
image: contentContext.markdown.image || "auto"
|
|
1677
|
+
},
|
|
1678
|
+
sitemap: contentContext.sitemap ? {
|
|
1679
|
+
path: contentContext.sitemap.path || "/sitemap",
|
|
1680
|
+
...contentContext.sitemap.include?.length ? { include: contentContext.sitemap.include } : {},
|
|
1681
|
+
...contentContext.sitemap.exclude?.length ? { exclude: contentContext.sitemap.exclude } : {},
|
|
1682
|
+
...typeof contentContext.sitemap.includeDrafts === "boolean" ? { includeDrafts: contentContext.sitemap.includeDrafts } : {}
|
|
1683
|
+
} : false,
|
|
1684
|
+
search: searchRuntime,
|
|
1685
|
+
navigation: contentContext.navigation,
|
|
1686
|
+
contentHead: options.contentHead ?? true
|
|
1687
|
+
});
|
|
1688
|
+
const privateContentRuntime = {
|
|
1689
|
+
...contentContext,
|
|
1690
|
+
markdown: {
|
|
1691
|
+
...contentContext.markdown,
|
|
1692
|
+
plugins: sanitizePrivateMarkdownPlugins(contentContext.markdown.plugins)
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
nuxt.options.runtimeConfig.public.content = contentRuntime;
|
|
1696
|
+
nuxt.options.runtimeConfig.content = defu(nuxt.options.runtimeConfig.content, {
|
|
1697
|
+
cacheVersion: CACHE_VERSION,
|
|
1698
|
+
cacheIntegrity,
|
|
1699
|
+
revalidate: revalidate?.token ? {
|
|
1700
|
+
token: revalidate.token,
|
|
1701
|
+
allowUnsigned: revalidate.allowUnsigned === true
|
|
1702
|
+
} : false,
|
|
1703
|
+
...privateContentRuntime,
|
|
1704
|
+
collections: runtimeCollections
|
|
1705
|
+
});
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
const registerContentContextFinalization = ({
|
|
1709
|
+
nuxt,
|
|
1710
|
+
options,
|
|
1711
|
+
contentContext,
|
|
1712
|
+
buildIntegrity,
|
|
1713
|
+
resolvePath,
|
|
1714
|
+
resolveRuntimeModule,
|
|
1715
|
+
onResolved
|
|
1716
|
+
}) => {
|
|
1717
|
+
nuxt.hook("modules:done", async () => {
|
|
1718
|
+
await nuxt.callHook("content:providers", contentContext.providers ||= {});
|
|
1719
|
+
assertConfiguredProviderAvailable(contentContext);
|
|
1720
|
+
await nuxt.callHook("content:context", contentContext);
|
|
1721
|
+
if (contentContext.search !== false) {
|
|
1722
|
+
registerContentSearchServerHandlers(options.api.baseURL, contentContext.search, resolveRuntimeModule);
|
|
1723
|
+
}
|
|
1724
|
+
contentContext.defaultLocale = contentContext.defaultLocale || contentContext.locales[0];
|
|
1725
|
+
const resolvedContentContext = {
|
|
1726
|
+
...contentContext,
|
|
1727
|
+
markdown: processMarkdownOptions(contentContext.markdown)
|
|
1728
|
+
};
|
|
1729
|
+
onResolved(resolvedContentContext);
|
|
1730
|
+
await validateBuiltinMarkdownPlugins(resolvedContentContext.markdown.plugins, resolvePath);
|
|
1731
|
+
const runtimeCollections = Object.fromEntries(Object.entries(options.collections || {}).map(([name, collection]) => {
|
|
1732
|
+
const references = collectTopLevelReferenceFieldsByTarget(collection.schema);
|
|
1733
|
+
return [
|
|
1734
|
+
name,
|
|
1735
|
+
{
|
|
1736
|
+
...collection.source ? { source: collection.source } : {},
|
|
1737
|
+
...collection.exclude ? { exclude: collection.exclude } : {},
|
|
1738
|
+
...collection.type ? { type: collection.type } : {},
|
|
1739
|
+
strict: collection.strict ?? true,
|
|
1740
|
+
...collection.route ? { route: collection.route } : {},
|
|
1741
|
+
...typeof collection.sitemap === "boolean" ? { sitemap: collection.sitemap } : {},
|
|
1742
|
+
...collection.i18n && collection.i18n !== true ? { i18n: collection.i18n } : {},
|
|
1743
|
+
...Object.keys(references).length ? { references } : {}
|
|
1744
|
+
}
|
|
1745
|
+
];
|
|
1746
|
+
}));
|
|
1747
|
+
const cacheIntegrity = hash({
|
|
1748
|
+
locales: resolvedContentContext.locales,
|
|
1749
|
+
defaultLocale: resolvedContentContext.defaultLocale,
|
|
1750
|
+
localeFallback: resolvedContentContext.localeFallback,
|
|
1751
|
+
translatedSlugs: resolvedContentContext.translatedSlugs,
|
|
1752
|
+
strictTranslatedSlugs: resolvedContentContext.strictTranslatedSlugs,
|
|
1753
|
+
respectPathCase: resolvedContentContext.respectPathCase,
|
|
1754
|
+
collections: runtimeCollections,
|
|
1755
|
+
markdown: resolvedContentContext.markdown,
|
|
1756
|
+
yaml: resolvedContentContext.yaml,
|
|
1757
|
+
csv: resolvedContentContext.csv
|
|
1758
|
+
});
|
|
1759
|
+
applyContentRuntimeConfig(nuxt, options, resolvedContentContext, runtimeCollections, buildIntegrity, cacheIntegrity);
|
|
1760
|
+
});
|
|
1761
|
+
};
|
|
1762
|
+
|
|
1763
|
+
const hookNuxtBoundary = (nuxt, name2, callback) => {
|
|
1764
|
+
const hook = nuxt.hook;
|
|
1765
|
+
hook(name2, callback);
|
|
1766
|
+
};
|
|
1221
1767
|
const module$1 = defineNuxtModule({
|
|
1222
1768
|
meta: {
|
|
1223
1769
|
name,
|
|
@@ -1236,75 +1782,14 @@ const module$1 = defineNuxtModule({
|
|
|
1236
1782
|
}
|
|
1237
1783
|
}
|
|
1238
1784
|
},
|
|
1239
|
-
defaults:
|
|
1240
|
-
api: {
|
|
1241
|
-
baseURL: "/api/_content"
|
|
1242
|
-
},
|
|
1243
|
-
i18n: true,
|
|
1244
|
-
sitemap: true,
|
|
1245
|
-
search: {
|
|
1246
|
-
engine: "minisearch",
|
|
1247
|
-
ignoredTags: ["script", "style", "pre"],
|
|
1248
|
-
filterQuery: { _draft: false, _partial: false },
|
|
1249
|
-
extraFields: [],
|
|
1250
|
-
minisearch: {
|
|
1251
|
-
fields: ["title", "content", "headings"],
|
|
1252
|
-
storeFields: ["path", "title", "excerpt", "anchor", "locale"],
|
|
1253
|
-
boost: {
|
|
1254
|
-
title: 4,
|
|
1255
|
-
headings: 2,
|
|
1256
|
-
content: 1
|
|
1257
|
-
},
|
|
1258
|
-
fuzzy: 0.2,
|
|
1259
|
-
prefix: true
|
|
1260
|
-
}
|
|
1261
|
-
},
|
|
1262
|
-
watch: {
|
|
1263
|
-
ws: {
|
|
1264
|
-
port: {
|
|
1265
|
-
port: 4e3,
|
|
1266
|
-
portRange: [4e3, 4040]
|
|
1267
|
-
},
|
|
1268
|
-
hostname: "localhost",
|
|
1269
|
-
showURL: false
|
|
1270
|
-
}
|
|
1271
|
-
},
|
|
1272
|
-
sources: {},
|
|
1273
|
-
ignores: [],
|
|
1274
|
-
collections: {},
|
|
1275
|
-
markdown: {
|
|
1276
|
-
plugins: [],
|
|
1277
|
-
tags: {
|
|
1278
|
-
code: "ProseCode",
|
|
1279
|
-
img: "ProseImg",
|
|
1280
|
-
pre: "ProsePre"
|
|
1281
|
-
},
|
|
1282
|
-
anchorLinks: {
|
|
1283
|
-
depth: 4,
|
|
1284
|
-
exclude: [1]
|
|
1285
|
-
},
|
|
1286
|
-
image: "auto"
|
|
1287
|
-
},
|
|
1288
|
-
yaml: {},
|
|
1289
|
-
csv: {
|
|
1290
|
-
delimiter: ",",
|
|
1291
|
-
json: true
|
|
1292
|
-
},
|
|
1293
|
-
navigation: {
|
|
1294
|
-
fields: []
|
|
1295
|
-
},
|
|
1296
|
-
contentHead: true,
|
|
1297
|
-
respectPathCase: false,
|
|
1298
|
-
experimental: {
|
|
1299
|
-
stripQueryParameters: false
|
|
1300
|
-
}
|
|
1301
|
-
},
|
|
1785
|
+
defaults: contentModuleDefaults,
|
|
1302
1786
|
async setup(options, nuxt) {
|
|
1303
1787
|
const { resolve, resolvePath } = createResolver(import.meta.url);
|
|
1304
1788
|
const logger = useLogger(name);
|
|
1305
1789
|
const resolveRuntimeModule = (path) => resolve("./runtime", path);
|
|
1306
1790
|
const runtimeInlineDependencies = ["comark", "@comark/vue"];
|
|
1307
1791
|
validateRemovedMarkdownOptions(options);
|
|
1792
|
+
nuxt.options.experimental.payloadExtraction ??= false;
|
|
1308
1793
|
nuxt.options.build.transpile ||= [];
|
|
1309
1794
|
for (const dependency of runtimeInlineDependencies) {
|
|
1310
1795
|
if (!nuxt.options.build.transpile.includes(dependency)) {
|
|
@@ -1317,6 +1802,10 @@ const module$1 = defineNuxtModule({
|
|
|
1317
1802
|
});
|
|
1318
1803
|
const contentConfigPath = resolveContentConfigPath(nuxt);
|
|
1319
1804
|
const appContentConfig = await loadContentConfig(nuxt);
|
|
1805
|
+
const externalGinkoContentConfig = nuxt.options.ginkoContent;
|
|
1806
|
+
if (externalGinkoContentConfig?.agent && options.agent !== false) {
|
|
1807
|
+
options.agent = defu(options.agent || {}, externalGinkoContentConfig.agent);
|
|
1808
|
+
}
|
|
1320
1809
|
if (!contentConfigPath || !appContentConfig.collections || !Object.keys(appContentConfig.collections).length) {
|
|
1321
1810
|
throw new Error("@lupinum/ginko-content requires a content.config.ts with at least one collection. Define collections with defineContentConfig({ collections: { ... } }).");
|
|
1322
1811
|
}
|
|
@@ -1324,6 +1813,10 @@ const module$1 = defineNuxtModule({
|
|
|
1324
1813
|
const resolvedSitemap = normalizeSitemapOptions(options);
|
|
1325
1814
|
const resolvedSearch = normalizeSearchOptions(options);
|
|
1326
1815
|
validateCollectionNames(appContentConfig.collections);
|
|
1816
|
+
if (!hasAgentSurface(appContentConfig)) {
|
|
1817
|
+
options.agent = false;
|
|
1818
|
+
}
|
|
1819
|
+
validateAgentConfig(appContentConfig, options, { dev: nuxt.options.dev });
|
|
1327
1820
|
options.collections = Object.fromEntries(Object.entries(appContentConfig.collections).map(([name2, collection]) => [
|
|
1328
1821
|
name2,
|
|
1329
1822
|
{
|
|
@@ -1353,25 +1846,32 @@ const module$1 = defineNuxtModule({
|
|
|
1353
1846
|
sitemap: resolvedSitemap,
|
|
1354
1847
|
search: resolvedSearch
|
|
1355
1848
|
};
|
|
1849
|
+
let resolvedContentContext;
|
|
1850
|
+
const getResolvedContentContext = () => {
|
|
1851
|
+
if (!resolvedContentContext) {
|
|
1852
|
+
throw new Error("Content runtime config was read before content context resolution completed.");
|
|
1853
|
+
}
|
|
1854
|
+
return resolvedContentContext;
|
|
1855
|
+
};
|
|
1356
1856
|
if (resolvedSitemap !== false) {
|
|
1357
1857
|
configureNuxtSitemapSource(nuxt, options.api.baseURL, resolvedSitemap.path);
|
|
1358
1858
|
}
|
|
1359
1859
|
nuxt.hook("pages:extend", (pages) => {
|
|
1360
|
-
validateContentPageRouteMetadata(pages, options.collections, {
|
|
1860
|
+
validateContentPageRouteMetadata(pages, options.collections || {}, {
|
|
1361
1861
|
locales: resolvedI18n.locales,
|
|
1362
1862
|
defaultLocale: resolvedI18n.defaultLocale
|
|
1363
1863
|
});
|
|
1364
1864
|
});
|
|
1365
1865
|
if (resolvedSitemap && resolvedSitemap.assert.enabled) {
|
|
1366
|
-
nuxt
|
|
1367
|
-
const assertOptions =
|
|
1866
|
+
hookNuxtBoundary(nuxt, "sitemap:prerender:done", async ({ sitemaps }) => {
|
|
1867
|
+
const assertOptions = resolvedSitemap ? resolvedSitemap.assert : void 0;
|
|
1368
1868
|
if (!assertOptions || !shouldRunSitemapAssertionOnPrerenderedSitemaps(assertOptions)) {
|
|
1369
1869
|
return;
|
|
1370
1870
|
}
|
|
1371
1871
|
await assertGeneratedSitemaps({
|
|
1372
1872
|
options: assertOptions,
|
|
1373
1873
|
targets: createSitemapAssertionTargetsFromPrerenderedSitemaps(sitemaps),
|
|
1374
|
-
collectionRouteCounts: await collectSitemapCollectionRouteCounts(nuxt.options.rootDir,
|
|
1874
|
+
collectionRouteCounts: await collectSitemapCollectionRouteCounts(nuxt.options.rootDir, getResolvedContentContext()),
|
|
1375
1875
|
logger
|
|
1376
1876
|
});
|
|
1377
1877
|
});
|
|
@@ -1389,146 +1889,40 @@ const module$1 = defineNuxtModule({
|
|
|
1389
1889
|
Object.keys(appContentConfig.collections),
|
|
1390
1890
|
Object.entries(appContentConfig.collections).filter(([, collection]) => Boolean(collection.i18n)).map(([name2]) => name2)
|
|
1391
1891
|
);
|
|
1392
|
-
await registerUserContentComponents(nuxt
|
|
1892
|
+
await registerUserContentComponents(nuxt);
|
|
1393
1893
|
const getSearchRuntime = () => contentContext.search === false ? false : createSearchRuntimeConfig(contentContext.search, options.api.baseURL);
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
base: resolve(nuxt.options.buildDir, "content-cache")
|
|
1407
|
-
};
|
|
1408
|
-
for (const source of Object.values(sources)) {
|
|
1409
|
-
if (source.driver === "fs" && source.base.includes(nuxt.options.srcDir)) {
|
|
1410
|
-
const wildcard = join(source.base, "**/*").replace(withTrailingSlash(nuxt.options.srcDir), "");
|
|
1411
|
-
nuxt.options.ignore.push(
|
|
1412
|
-
// Remove `srcDir` from the path
|
|
1413
|
-
wildcard,
|
|
1414
|
-
`!${wildcard}.vue`
|
|
1415
|
-
);
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
nitroConfig.bundledStorage = nitroConfig.bundledStorage || [];
|
|
1419
|
-
nitroConfig.bundledStorage.push("cache:content");
|
|
1420
|
-
nitroConfig.externals = defu(typeof nitroConfig.externals === "object" ? nitroConfig.externals : {}, {
|
|
1421
|
-
inline: [
|
|
1422
|
-
resolve("./runtime"),
|
|
1423
|
-
...runtimeInlineDependencies
|
|
1424
|
-
]
|
|
1425
|
-
});
|
|
1426
|
-
if (searchRuntime !== false && searchRuntime.engine !== "cms" && usesFilesystemProvider) {
|
|
1427
|
-
nitroConfig.routeRules = nitroConfig.routeRules || {};
|
|
1428
|
-
nitroConfig.routeRules[searchRuntime.indexURL] = {
|
|
1429
|
-
prerender: true,
|
|
1430
|
-
headers: { "Content-Type": "application/json; charset=utf-8" }
|
|
1431
|
-
};
|
|
1432
|
-
}
|
|
1433
|
-
if (contentContext.sitemap !== false) {
|
|
1434
|
-
nitroConfig.plugins ||= [];
|
|
1435
|
-
const sitemapPlugin = resolveRuntimeModule("server/plugins/sitemap.js");
|
|
1436
|
-
if (!nitroConfig.plugins.includes(sitemapPlugin)) {
|
|
1437
|
-
nitroConfig.plugins.push(sitemapPlugin);
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
if (contentContext.cache && contentContext.cache !== false) {
|
|
1441
|
-
nitroConfig.plugins ||= [];
|
|
1442
|
-
const cachePlugin = resolveRuntimeModule("server/plugins/cache.js");
|
|
1443
|
-
if (!nitroConfig.plugins.includes(cachePlugin)) {
|
|
1444
|
-
nitroConfig.plugins.push(cachePlugin);
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
registerContentNitroIntegrationHooks(nitroConfig, {
|
|
1448
|
-
rootDir: nuxt.options.rootDir,
|
|
1449
|
-
sitemapPrerenderRoutes: () => contentContext.sitemap === false ? [] : resolveNuxtSitemapPrerenderRoutes(nuxt)
|
|
1450
|
-
}, {
|
|
1451
|
-
collections: contentContext.collections,
|
|
1452
|
-
locales: contentContext.locales,
|
|
1453
|
-
defaultLocale: contentContext.defaultLocale,
|
|
1454
|
-
translatedSlugs: contentContext.translatedSlugs,
|
|
1455
|
-
strictTranslatedSlugs: contentContext.strictTranslatedSlugs,
|
|
1456
|
-
respectPathCase: contentContext.respectPathCase,
|
|
1457
|
-
markdown: contentContext.markdown,
|
|
1458
|
-
yaml: contentContext.yaml,
|
|
1459
|
-
csv: contentContext.csv,
|
|
1460
|
-
sitemap: contentContext.sitemap,
|
|
1461
|
-
provider: contentContext.provider
|
|
1462
|
-
});
|
|
1894
|
+
registerContentNitroConfig({
|
|
1895
|
+
nuxt,
|
|
1896
|
+
options,
|
|
1897
|
+
appContentConfig,
|
|
1898
|
+
contentContext,
|
|
1899
|
+
runtimeInlineDependencies,
|
|
1900
|
+
buildIntegrity,
|
|
1901
|
+
resolvedI18n,
|
|
1902
|
+
resolveRuntimeModule,
|
|
1903
|
+
resolveModuleFile: resolve,
|
|
1904
|
+
getResolvedContentContext,
|
|
1905
|
+
getSearchRuntime
|
|
1463
1906
|
});
|
|
1464
|
-
|
|
1465
|
-
nuxt
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
mkdirSync(dirname(indexPath), { recursive: true });
|
|
1483
|
-
writeFileSync(indexPath, json, "utf8");
|
|
1484
|
-
if (searchRuntime.engine === "pagefind") {
|
|
1485
|
-
const records = JSON.parse(json);
|
|
1486
|
-
const { writePagefindIndex } = await import(resolveRuntimeModule("./server/pagefind.js"));
|
|
1487
|
-
await writePagefindIndex(records, resolve$1(publicDir, "pagefind"));
|
|
1488
|
-
}
|
|
1489
|
-
});
|
|
1490
|
-
});
|
|
1491
|
-
});
|
|
1492
|
-
}
|
|
1493
|
-
nuxt.hook("modules:done", async () => {
|
|
1494
|
-
await nuxt.callHook("content:providers", contentContext.providers ||= {});
|
|
1495
|
-
assertConfiguredProviderAvailable(contentContext);
|
|
1496
|
-
await nuxt.callHook("content:context", contentContext);
|
|
1497
|
-
if (contentContext.search !== false) {
|
|
1498
|
-
registerContentSearchServerHandlers(options.api.baseURL, contentContext.search, resolveRuntimeModule);
|
|
1907
|
+
registerStaticOutputGeneration({
|
|
1908
|
+
nuxt,
|
|
1909
|
+
options,
|
|
1910
|
+
appContentConfig,
|
|
1911
|
+
contentContext,
|
|
1912
|
+
resolvedI18n,
|
|
1913
|
+
resolveRuntimeModule,
|
|
1914
|
+
getSearchRuntime
|
|
1915
|
+
});
|
|
1916
|
+
registerContentContextFinalization({
|
|
1917
|
+
nuxt,
|
|
1918
|
+
options,
|
|
1919
|
+
contentContext,
|
|
1920
|
+
buildIntegrity,
|
|
1921
|
+
resolvePath,
|
|
1922
|
+
resolveRuntimeModule,
|
|
1923
|
+
onResolved: (context) => {
|
|
1924
|
+
resolvedContentContext = context;
|
|
1499
1925
|
}
|
|
1500
|
-
contentContext.defaultLocale = contentContext.defaultLocale || contentContext.locales[0];
|
|
1501
|
-
contentContext.markdown = processMarkdownOptions(contentContext.markdown);
|
|
1502
|
-
await validateBuiltinMarkdownPlugins(contentContext.markdown.plugins, resolvePath);
|
|
1503
|
-
const runtimeCollections = Object.fromEntries(Object.entries(options.collections || {}).map(([name2, collection]) => {
|
|
1504
|
-
const references = collectTopLevelReferenceFieldsByTarget(collection.schema);
|
|
1505
|
-
return [
|
|
1506
|
-
name2,
|
|
1507
|
-
{
|
|
1508
|
-
...collection.source ? { source: collection.source } : {},
|
|
1509
|
-
...collection.exclude ? { exclude: collection.exclude } : {},
|
|
1510
|
-
...collection.type ? { type: collection.type } : {},
|
|
1511
|
-
strict: collection.strict ?? true,
|
|
1512
|
-
...collection.route ? { route: collection.route } : {},
|
|
1513
|
-
...typeof collection.sitemap === "boolean" ? { sitemap: collection.sitemap } : {},
|
|
1514
|
-
...collection.i18n && collection.i18n !== true ? { i18n: collection.i18n } : {},
|
|
1515
|
-
...Object.keys(references).length ? { references } : {}
|
|
1516
|
-
}
|
|
1517
|
-
];
|
|
1518
|
-
}));
|
|
1519
|
-
const cacheIntegrity = hash({
|
|
1520
|
-
locales: contentContext.locales,
|
|
1521
|
-
defaultLocale: contentContext.defaultLocale,
|
|
1522
|
-
localeFallback: contentContext.localeFallback,
|
|
1523
|
-
translatedSlugs: contentContext.translatedSlugs,
|
|
1524
|
-
strictTranslatedSlugs: contentContext.strictTranslatedSlugs,
|
|
1525
|
-
respectPathCase: contentContext.respectPathCase,
|
|
1526
|
-
collections: runtimeCollections,
|
|
1527
|
-
markdown: contentContext.markdown,
|
|
1528
|
-
yaml: contentContext.yaml,
|
|
1529
|
-
csv: contentContext.csv
|
|
1530
|
-
});
|
|
1531
|
-
applyContentRuntimeConfig(nuxt, options, contentContext, runtimeCollections, buildIntegrity, cacheIntegrity);
|
|
1532
1926
|
});
|
|
1533
1927
|
if (nuxt.options.dev) {
|
|
1534
1928
|
registerDevRuntimePlugin(resolveRuntimeModule);
|
|
@@ -1536,46 +1930,5 @@ const module$1 = defineNuxtModule({
|
|
|
1536
1930
|
}
|
|
1537
1931
|
}
|
|
1538
1932
|
});
|
|
1539
|
-
function assertConfiguredProviderAvailable(contentContext) {
|
|
1540
|
-
const provider = contentContext.provider || "filesystem";
|
|
1541
|
-
if (provider === "filesystem") return;
|
|
1542
|
-
if (contentContext.providers?.[provider]) return;
|
|
1543
|
-
if (provider === "cms") {
|
|
1544
|
-
throw new Error('content.config.ts sets provider "cms", but no CMS provider module registered it. Add @lupinum/ginko-cms to nuxt.config.ts modules or remove provider: "cms".');
|
|
1545
|
-
}
|
|
1546
|
-
throw new Error(`content.config.ts sets provider "${provider}", but no provider module registered it. Register a module for "${provider}" or add it to content providers.`);
|
|
1547
|
-
}
|
|
1548
|
-
function validateCollectionNames(collections) {
|
|
1549
|
-
normalizeContentConfigCollectionNames(collections);
|
|
1550
|
-
}
|
|
1551
|
-
function validateRemovedMarkdownOptions(options) {
|
|
1552
|
-
if (options.highlight !== void 0) {
|
|
1553
|
-
throw new Error("`content.highlight` was removed. Enable syntax highlighting with `content.markdown.plugins`, for example `[['highlight', { ...options }]]`.");
|
|
1554
|
-
}
|
|
1555
|
-
const markdown = options.markdown || {};
|
|
1556
|
-
const removedOptions = ["mdc", "remarkPlugins", "rehypePlugins", "toc"];
|
|
1557
|
-
const removed = removedOptions.filter((key) => typeof markdown[key] !== "undefined");
|
|
1558
|
-
if (removed.length) {
|
|
1559
|
-
throw new Error(`Removed markdown options: ${removed.map((option) => `content.markdown.${String(option)}`).join(", ")}. Use ordered \`content.markdown.plugins\` entries instead.`);
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
async function validateBuiltinMarkdownPlugins(plugins, resolvePath) {
|
|
1563
|
-
for (const plugin of plugins) {
|
|
1564
|
-
const peerDependency = BUILTIN_PLUGIN_PEER_DEPS[plugin.name];
|
|
1565
|
-
if (!peerDependency) {
|
|
1566
|
-
continue;
|
|
1567
|
-
}
|
|
1568
|
-
try {
|
|
1569
|
-
await resolvePath(peerDependency);
|
|
1570
|
-
} catch (error) {
|
|
1571
|
-
throw new Error(`Markdown plugin "${plugin.name}" requires "${peerDependency}" to be installed.`, { cause: error });
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
const BUILTIN_PLUGIN_PEER_DEPS = {
|
|
1576
|
-
highlight: "shiki",
|
|
1577
|
-
math: "katex",
|
|
1578
|
-
mermaid: "beautiful-mermaid"
|
|
1579
|
-
};
|
|
1580
1933
|
|
|
1581
1934
|
export { module$1 as default };
|