@ztl-uwu/nuxt-content 2.13.5
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/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/module.d.mts +1176 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +696 -0
- package/dist/runtime/app.vue +3 -0
- package/dist/runtime/app.vue.d.ts +2 -0
- package/dist/runtime/components/ContentDoc.vue +108 -0
- package/dist/runtime/components/ContentDoc.vue.d.ts +118 -0
- package/dist/runtime/components/ContentList.vue +59 -0
- package/dist/runtime/components/ContentList.vue.d.ts +59 -0
- package/dist/runtime/components/ContentNavigation.vue +61 -0
- package/dist/runtime/components/ContentNavigation.vue.d.ts +35 -0
- package/dist/runtime/components/ContentQuery.vue +212 -0
- package/dist/runtime/components/ContentQuery.vue.d.ts +0 -0
- package/dist/runtime/components/ContentRenderer.vue +78 -0
- package/dist/runtime/components/ContentRenderer.vue.d.ts +56 -0
- package/dist/runtime/components/ContentRendererMarkdown.vue +69 -0
- package/dist/runtime/components/ContentRendererMarkdown.vue.d.ts +73 -0
- package/dist/runtime/components/ContentSlot.vue +25 -0
- package/dist/runtime/components/ContentSlot.vue.d.ts +37 -0
- package/dist/runtime/components/DocumentDrivenEmpty.vue +18 -0
- package/dist/runtime/components/DocumentDrivenEmpty.vue.d.ts +17 -0
- package/dist/runtime/components/DocumentDrivenNotFound.vue +9 -0
- package/dist/runtime/components/DocumentDrivenNotFound.vue.d.ts +5 -0
- package/dist/runtime/components/Markdown.vue +29 -0
- package/dist/runtime/components/Markdown.vue.d.ts +31 -0
- package/dist/runtime/components/Prose/ProseCode.vue +32 -0
- package/dist/runtime/components/Prose/ProseCode.vue.d.ts +110 -0
- package/dist/runtime/components/Prose/ProseCodeInline.vue +3 -0
- package/dist/runtime/components/Prose/ProseCodeInline.vue.d.ts +14 -0
- package/dist/runtime/components/Prose/ProsePre.vue +42 -0
- package/dist/runtime/components/Prose/ProsePre.vue.d.ts +146 -0
- package/dist/runtime/composables/client-db.d.ts +14 -0
- package/dist/runtime/composables/client-db.js +105 -0
- package/dist/runtime/composables/content.d.ts +19 -0
- package/dist/runtime/composables/content.js +41 -0
- package/dist/runtime/composables/head.d.ts +4 -0
- package/dist/runtime/composables/head.js +94 -0
- package/dist/runtime/composables/helpers.d.ts +7 -0
- package/dist/runtime/composables/helpers.js +66 -0
- package/dist/runtime/composables/navigation.d.ts +2 -0
- package/dist/runtime/composables/navigation.js +34 -0
- package/dist/runtime/composables/preview.d.ts +5 -0
- package/dist/runtime/composables/preview.js +41 -0
- package/dist/runtime/composables/query.d.ts +10 -0
- package/dist/runtime/composables/query.js +64 -0
- package/dist/runtime/composables/search.d.ts +130 -0
- package/dist/runtime/composables/search.js +59 -0
- package/dist/runtime/composables/useUnwrap.d.ts +5 -0
- package/dist/runtime/composables/useUnwrap.js +5 -0
- package/dist/runtime/composables/utils.d.ts +6 -0
- package/dist/runtime/composables/utils.js +36 -0
- package/dist/runtime/composables/web-socket.d.ts +3 -0
- package/dist/runtime/composables/web-socket.js +65 -0
- package/dist/runtime/legacy/composables/client-db.d.ts +12 -0
- package/dist/runtime/legacy/composables/client-db.js +105 -0
- package/dist/runtime/legacy/composables/navigation.d.ts +2 -0
- package/dist/runtime/legacy/composables/navigation.js +34 -0
- package/dist/runtime/legacy/composables/query.d.ts +10 -0
- package/dist/runtime/legacy/composables/query.js +61 -0
- package/dist/runtime/legacy/plugins/documentDriven.d.ts +2 -0
- package/dist/runtime/legacy/plugins/documentDriven.js +231 -0
- package/dist/runtime/legacy/server.d.ts +3 -0
- package/dist/runtime/legacy/server.js +3 -0
- package/dist/runtime/legacy/types.d.ts +5 -0
- package/dist/runtime/pages/document-driven.vue +27 -0
- package/dist/runtime/pages/document-driven.vue.d.ts +2 -0
- package/dist/runtime/plugins/documentDriven.d.ts +2 -0
- package/dist/runtime/plugins/documentDriven.js +222 -0
- package/dist/runtime/plugins/ws.d.ts +2 -0
- package/dist/runtime/plugins/ws.js +7 -0
- package/dist/runtime/query/match/index.d.ts +6 -0
- package/dist/runtime/query/match/index.js +123 -0
- package/dist/runtime/query/match/pipeline-legacy.d.ts +2 -0
- package/dist/runtime/query/match/pipeline-legacy.js +22 -0
- package/dist/runtime/query/match/pipeline.d.ts +2 -0
- package/dist/runtime/query/match/pipeline.js +104 -0
- package/dist/runtime/query/match/utils.d.ts +35 -0
- package/dist/runtime/query/match/utils.js +65 -0
- package/dist/runtime/query/query.d.ts +12 -0
- package/dist/runtime/query/query.js +61 -0
- package/dist/runtime/server/api/cache.d.ts +7 -0
- package/dist/runtime/server/api/cache.js +18 -0
- package/dist/runtime/server/api/navigation-qid-params.d.ts +1 -0
- package/dist/runtime/server/api/navigation-qid-params.js +1 -0
- package/dist/runtime/server/api/navigation-qid.d.ts +1 -0
- package/dist/runtime/server/api/navigation-qid.js +1 -0
- package/dist/runtime/server/api/navigation.d.ts +2 -0
- package/dist/runtime/server/api/navigation.js +42 -0
- package/dist/runtime/server/api/query-qid-params.d.ts +1 -0
- package/dist/runtime/server/api/query-qid-params.js +1 -0
- package/dist/runtime/server/api/query-qid.d.ts +1 -0
- package/dist/runtime/server/api/query-qid.js +1 -0
- package/dist/runtime/server/api/query.d.ts +2 -0
- package/dist/runtime/server/api/query.js +32 -0
- package/dist/runtime/server/api/search.d.ts +8 -0
- package/dist/runtime/server/api/search.js +16 -0
- package/dist/runtime/server/content-index.d.ts +4 -0
- package/dist/runtime/server/content-index.js +37 -0
- package/dist/runtime/server/index.d.ts +1 -0
- package/dist/runtime/server/index.js +1 -0
- package/dist/runtime/server/navigation.d.ts +5 -0
- package/dist/runtime/server/navigation.js +96 -0
- package/dist/runtime/server/plugins/refresh-cache.d.ts +2 -0
- package/dist/runtime/server/plugins/refresh-cache.js +15 -0
- package/dist/runtime/server/preview.d.ts +5 -0
- package/dist/runtime/server/preview.js +9 -0
- package/dist/runtime/server/search.d.ts +14 -0
- package/dist/runtime/server/search.js +70 -0
- package/dist/runtime/server/storage.d.ts +35 -0
- package/dist/runtime/server/storage.js +238 -0
- package/dist/runtime/transformers/component-resolver.d.ts +2 -0
- package/dist/runtime/transformers/component-resolver.js +44 -0
- package/dist/runtime/transformers/csv/create-tokenizer.d.ts +39 -0
- package/dist/runtime/transformers/csv/create-tokenizer.js +307 -0
- package/dist/runtime/transformers/csv/from-csv.d.ts +13 -0
- package/dist/runtime/transformers/csv/from-csv.js +203 -0
- package/dist/runtime/transformers/csv/index.d.ts +2 -0
- package/dist/runtime/transformers/csv/index.js +50 -0
- package/dist/runtime/transformers/csv/parser.d.ts +24 -0
- package/dist/runtime/transformers/csv/parser.js +154 -0
- package/dist/runtime/transformers/index.d.ts +7 -0
- package/dist/runtime/transformers/index.js +50 -0
- package/dist/runtime/transformers/json.d.ts +2 -0
- package/dist/runtime/transformers/json.js +29 -0
- package/dist/runtime/transformers/markdown.d.ts +2 -0
- package/dist/runtime/transformers/markdown.js +88 -0
- package/dist/runtime/transformers/path-meta.d.ts +27 -0
- package/dist/runtime/transformers/path-meta.js +59 -0
- package/dist/runtime/transformers/utils.d.ts +3 -0
- package/dist/runtime/transformers/utils.js +12 -0
- package/dist/runtime/transformers/yaml.d.ts +2 -0
- package/dist/runtime/transformers/yaml.js +21 -0
- package/dist/runtime/utils/config.d.ts +4 -0
- package/dist/runtime/utils/config.js +7 -0
- package/dist/runtime/utils/html-tags.d.ts +2 -0
- package/dist/runtime/utils/html-tags.js +119 -0
- package/dist/runtime/utils/json.d.ts +10 -0
- package/dist/runtime/utils/json.js +20 -0
- package/dist/runtime/utils/query.d.ts +5 -0
- package/dist/runtime/utils/query.js +77 -0
- package/dist/runtime/virtual/transformers.d.ts +2 -0
- package/dist/types.d.mts +9 -0
- package/dist/web-types.json +572 -0
- package/package.json +111 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { withoutTrailingSlash, hasProtocol } from "ufo";
|
|
2
|
+
import { pascalCase } from "scule";
|
|
3
|
+
import { callWithNuxt } from "#app/nuxt";
|
|
4
|
+
import { useContentState } from "../../composables/content.js";
|
|
5
|
+
import { useContentHelpers } from "../../composables/helpers.js";
|
|
6
|
+
import { fetchContentNavigation } from "../composables/navigation.js";
|
|
7
|
+
import { queryContent } from "../composables/query.js";
|
|
8
|
+
import { defineNuxtPlugin } from "nuxt/app";
|
|
9
|
+
import { useRuntimeConfig, addRouteMiddleware, navigateTo, useRoute, prefetchComponents, useRouter } from "#imports";
|
|
10
|
+
import { componentNames } from "#components";
|
|
11
|
+
import layouts from "#build/layouts";
|
|
12
|
+
export default defineNuxtPlugin((nuxt) => {
|
|
13
|
+
const moduleOptions = useRuntimeConfig()?.public?.content.documentDriven;
|
|
14
|
+
const isClientDBEnabled = useRuntimeConfig()?.public?.content.experimental.clientDB;
|
|
15
|
+
const { navigation, pages, globals, surrounds } = useContentState();
|
|
16
|
+
const findLayout = (to, page, navigation2, globals2) => {
|
|
17
|
+
if (page && page?.layout) {
|
|
18
|
+
return page.layout;
|
|
19
|
+
}
|
|
20
|
+
if (to.matched[0] && to.matched[0].meta?.layout) {
|
|
21
|
+
return to.matched[0].meta.layout;
|
|
22
|
+
}
|
|
23
|
+
if (navigation2 && page) {
|
|
24
|
+
const { navKeyFromPath } = useContentHelpers();
|
|
25
|
+
const layoutFromNav = navKeyFromPath(page._path, "layout", navigation2);
|
|
26
|
+
if (layoutFromNav) {
|
|
27
|
+
return layoutFromNav;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (moduleOptions.layoutFallbacks && globals2) {
|
|
31
|
+
let layoutFallback;
|
|
32
|
+
for (const fallback of moduleOptions.layoutFallbacks) {
|
|
33
|
+
if (globals2[fallback] && globals2[fallback].layout) {
|
|
34
|
+
layoutFallback = globals2[fallback].layout;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (layoutFallback) {
|
|
39
|
+
return layoutFallback;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return "default";
|
|
43
|
+
};
|
|
44
|
+
const refresh = async (to, dedup = false) => {
|
|
45
|
+
nuxt.callHook("content:document-driven:start", { route: to, dedup });
|
|
46
|
+
const routeConfig = to.meta.documentDriven || {};
|
|
47
|
+
if (to.meta.documentDriven === false) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const _path = withoutTrailingSlash(to.path);
|
|
51
|
+
const promises = [];
|
|
52
|
+
if (moduleOptions.navigation && routeConfig.navigation !== false) {
|
|
53
|
+
const navigationQuery = () => {
|
|
54
|
+
const { navigation: navigation2 } = useContentState();
|
|
55
|
+
if (navigation2.value && !dedup) {
|
|
56
|
+
return navigation2.value;
|
|
57
|
+
}
|
|
58
|
+
return fetchContentNavigation().then((_navigation) => {
|
|
59
|
+
navigation2.value = _navigation;
|
|
60
|
+
return _navigation;
|
|
61
|
+
}).catch(() => null);
|
|
62
|
+
};
|
|
63
|
+
promises.push(navigationQuery);
|
|
64
|
+
} else {
|
|
65
|
+
promises.push(() => Promise.resolve(null));
|
|
66
|
+
}
|
|
67
|
+
if (moduleOptions.globals) {
|
|
68
|
+
const globalsQuery = () => {
|
|
69
|
+
const { globals: globals2 } = useContentState();
|
|
70
|
+
if (typeof moduleOptions.globals === "object" && Array.isArray(moduleOptions.globals)) {
|
|
71
|
+
console.log("Globals must be a list of keys with QueryBuilderParams as a value.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
return Promise.all(
|
|
75
|
+
Object.entries(moduleOptions.globals).map(
|
|
76
|
+
([key, query]) => {
|
|
77
|
+
if (!dedup && globals2.value[key]) {
|
|
78
|
+
return globals2.value[key];
|
|
79
|
+
}
|
|
80
|
+
let type = "findOne";
|
|
81
|
+
if (query?.type) {
|
|
82
|
+
type = query.type;
|
|
83
|
+
}
|
|
84
|
+
return queryContent(query)[type]().catch(() => null);
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
).then(
|
|
88
|
+
(values) => {
|
|
89
|
+
return values.reduce(
|
|
90
|
+
(acc, value, index) => {
|
|
91
|
+
const key = Object.keys(moduleOptions.globals)[index];
|
|
92
|
+
if (key) {
|
|
93
|
+
acc[key] = value;
|
|
94
|
+
}
|
|
95
|
+
return acc;
|
|
96
|
+
},
|
|
97
|
+
{}
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
promises.push(globalsQuery);
|
|
103
|
+
} else {
|
|
104
|
+
promises.push(() => Promise.resolve(null));
|
|
105
|
+
}
|
|
106
|
+
if (moduleOptions.page && routeConfig.page !== false) {
|
|
107
|
+
let where = { _path };
|
|
108
|
+
if (typeof routeConfig.page === "string") {
|
|
109
|
+
where = { _path: routeConfig.page };
|
|
110
|
+
}
|
|
111
|
+
if (typeof routeConfig.page === "object") {
|
|
112
|
+
where = routeConfig.page;
|
|
113
|
+
}
|
|
114
|
+
const pageQuery = () => {
|
|
115
|
+
const { pages: pages2 } = useContentState();
|
|
116
|
+
if (!dedup && pages2.value[_path] && pages2.value[_path]._path === _path) {
|
|
117
|
+
return pages2.value[_path];
|
|
118
|
+
}
|
|
119
|
+
return queryContent().where(where).findOne().catch(() => null);
|
|
120
|
+
};
|
|
121
|
+
promises.push(pageQuery);
|
|
122
|
+
} else {
|
|
123
|
+
promises.push(() => Promise.resolve(null));
|
|
124
|
+
}
|
|
125
|
+
if (moduleOptions.surround && routeConfig.surround !== false) {
|
|
126
|
+
let surround = _path;
|
|
127
|
+
if (["string", "object"].includes(typeof routeConfig.page)) {
|
|
128
|
+
surround = routeConfig.page;
|
|
129
|
+
}
|
|
130
|
+
if (["string", "object"].includes(typeof routeConfig.surround)) {
|
|
131
|
+
surround = routeConfig.surround;
|
|
132
|
+
}
|
|
133
|
+
const surroundQuery = () => {
|
|
134
|
+
const { surrounds: surrounds2 } = useContentState();
|
|
135
|
+
if (!dedup && surrounds2.value[_path]) {
|
|
136
|
+
return surrounds2.value[_path];
|
|
137
|
+
}
|
|
138
|
+
return queryContent().where({
|
|
139
|
+
_partial: { $not: true },
|
|
140
|
+
navigation: { $not: false }
|
|
141
|
+
}).without(["body"]).findSurround(surround).catch(() => null);
|
|
142
|
+
};
|
|
143
|
+
promises.push(surroundQuery);
|
|
144
|
+
} else {
|
|
145
|
+
promises.push(() => Promise.resolve(null));
|
|
146
|
+
}
|
|
147
|
+
return await Promise.all(promises.map((promise) => promise())).then(async ([
|
|
148
|
+
_navigation,
|
|
149
|
+
_globals,
|
|
150
|
+
_page,
|
|
151
|
+
_surround
|
|
152
|
+
]) => {
|
|
153
|
+
if (_navigation) {
|
|
154
|
+
navigation.value = _navigation;
|
|
155
|
+
}
|
|
156
|
+
if (_globals) {
|
|
157
|
+
globals.value = _globals;
|
|
158
|
+
}
|
|
159
|
+
if (_surround) {
|
|
160
|
+
surrounds.value[_path] = _surround;
|
|
161
|
+
}
|
|
162
|
+
const redirectTo = _page?.redirect || _page?._dir?.navigation?.redirect;
|
|
163
|
+
if (redirectTo) {
|
|
164
|
+
pages.value[_path] = _page;
|
|
165
|
+
return redirectTo;
|
|
166
|
+
}
|
|
167
|
+
if (_page) {
|
|
168
|
+
const layoutName = findLayout(to, _page, _navigation, _globals);
|
|
169
|
+
const layout = layouts[layoutName];
|
|
170
|
+
if (layout && typeof layout === "function") {
|
|
171
|
+
await layout();
|
|
172
|
+
}
|
|
173
|
+
to.meta.layout = layoutName;
|
|
174
|
+
_page.layout = layoutName;
|
|
175
|
+
}
|
|
176
|
+
pages.value[_path] = _page;
|
|
177
|
+
await nuxt.callHook("content:document-driven:finish", { route: to, dedup, page: _page, navigation: _navigation, globals: _globals, surround: _surround });
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
if (import.meta.client) {
|
|
181
|
+
const router = useRouter();
|
|
182
|
+
nuxt.hook("link:prefetch", (link) => {
|
|
183
|
+
if (!(link in pages.value) && !hasProtocol(link)) {
|
|
184
|
+
const route = router.resolve(link);
|
|
185
|
+
if (route.matched.length > 0) {
|
|
186
|
+
refresh(route);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
nuxt.hooks.hook("content:document-driven:finish", ({ page }) => {
|
|
191
|
+
if (page?.body?.children) {
|
|
192
|
+
prefetchBodyComponents(page.body.children);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
addRouteMiddleware(async (to, from) => {
|
|
197
|
+
if (import.meta.client && !isClientDBEnabled && to.path === from.path) {
|
|
198
|
+
if (!to.meta.layout) {
|
|
199
|
+
const _path = withoutTrailingSlash(to.path);
|
|
200
|
+
if (pages.value[_path]) {
|
|
201
|
+
to.meta.layout = pages.value[_path].layout;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const redirect = await refresh(to, false);
|
|
207
|
+
if (redirect) {
|
|
208
|
+
if (hasProtocol(redirect)) {
|
|
209
|
+
return callWithNuxt(nuxt, navigateTo, [redirect, { external: true }]);
|
|
210
|
+
} else {
|
|
211
|
+
return redirect;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
nuxt.hook("app:data:refresh", async () => import.meta.client && await refresh(useRoute(), true));
|
|
216
|
+
});
|
|
217
|
+
function prefetchBodyComponents(nodes) {
|
|
218
|
+
for (const node of nodes) {
|
|
219
|
+
if (node.children) {
|
|
220
|
+
prefetchBodyComponents(node.children);
|
|
221
|
+
}
|
|
222
|
+
if (node.type === "element" && node.tag) {
|
|
223
|
+
const el = pascalCase(node.tag);
|
|
224
|
+
for (const name of ["Prose" + el, el]) {
|
|
225
|
+
if (componentNames.includes(name)) {
|
|
226
|
+
prefetchComponents(name);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ParsedContent, QueryBuilder, QueryBuilderParams } from "@nuxt/content"
|
|
2
|
+
import type { H3Event } from 'h3'
|
|
3
|
+
|
|
4
|
+
export function serverQueryContent<T = ParsedContent>(event: H3Event, params?: QueryBuilderParams): QueryBuilder<T>;
|
|
5
|
+
export function serverQueryContent<T = ParsedContent>(event: H3Event, query?: string, ...pathParts: string[]): QueryBuilder<T>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useRuntimeConfig, useContent, useContentHead, useRequestEvent } from "#imports";
|
|
3
|
+
const { contentHead } = useRuntimeConfig().public.content;
|
|
4
|
+
const { page, layout } = useContent();
|
|
5
|
+
if (!page.value && import.meta.server) {
|
|
6
|
+
const event = useRequestEvent();
|
|
7
|
+
if (event) {
|
|
8
|
+
event.node.res.statusCode = 404;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
if (contentHead) {
|
|
12
|
+
useContentHead(page);
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<div class="document-driven-page">
|
|
18
|
+
<NuxtLayout :name="layout || 'default'">
|
|
19
|
+
<ContentRenderer v-if="page" :key="page._id" :value="page">
|
|
20
|
+
<template #empty="{ value }">
|
|
21
|
+
<DocumentDrivenEmpty :value="value" />
|
|
22
|
+
</template>
|
|
23
|
+
</ContentRenderer>
|
|
24
|
+
<DocumentDrivenNotFound v-else />
|
|
25
|
+
</NuxtLayout>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { withoutTrailingSlash, hasProtocol } from "ufo";
|
|
2
|
+
import { pascalCase } from "scule";
|
|
3
|
+
import { callWithNuxt } from "#app/nuxt";
|
|
4
|
+
import { useContentState } from "../composables/content.js";
|
|
5
|
+
import { useContentHelpers } from "../composables/helpers.js";
|
|
6
|
+
import { fetchContentNavigation } from "../composables/navigation.js";
|
|
7
|
+
import { queryContent } from "../composables/query.js";
|
|
8
|
+
import { defineNuxtPlugin } from "nuxt/app";
|
|
9
|
+
import { useRuntimeConfig, addRouteMiddleware, navigateTo, useRoute, prefetchComponents, useRouter } from "#imports";
|
|
10
|
+
import { componentNames } from "#components";
|
|
11
|
+
import layouts from "#build/layouts";
|
|
12
|
+
export default defineNuxtPlugin((nuxt) => {
|
|
13
|
+
const moduleOptions = useRuntimeConfig()?.public?.content.documentDriven;
|
|
14
|
+
const isClientDBEnabled = useRuntimeConfig()?.public?.content.experimental.clientDB;
|
|
15
|
+
const { navigation, pages, globals, surrounds } = useContentState();
|
|
16
|
+
const findLayout = (to, page, navigation2, globals2) => {
|
|
17
|
+
if (page && page?.layout) {
|
|
18
|
+
return page.layout;
|
|
19
|
+
}
|
|
20
|
+
if (to.matched[0] && to.matched[0].meta?.layout) {
|
|
21
|
+
return to.matched[0].meta.layout;
|
|
22
|
+
}
|
|
23
|
+
if (navigation2 && page) {
|
|
24
|
+
const { navKeyFromPath } = useContentHelpers();
|
|
25
|
+
const layoutFromNav = navKeyFromPath(page._path, "layout", navigation2);
|
|
26
|
+
if (layoutFromNav) {
|
|
27
|
+
return layoutFromNav;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (moduleOptions.layoutFallbacks && globals2) {
|
|
31
|
+
let layoutFallback;
|
|
32
|
+
for (const fallback of moduleOptions.layoutFallbacks) {
|
|
33
|
+
if (globals2[fallback] && globals2[fallback].layout) {
|
|
34
|
+
layoutFallback = globals2[fallback].layout;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (layoutFallback) {
|
|
39
|
+
return layoutFallback;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return "default";
|
|
43
|
+
};
|
|
44
|
+
const refresh = async (to, dedup = false) => {
|
|
45
|
+
nuxt.callHook("content:document-driven:start", { route: to, dedup });
|
|
46
|
+
const routeConfig = to.meta.documentDriven || {};
|
|
47
|
+
if (to.meta.documentDriven === false) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const _path = withoutTrailingSlash(to.path);
|
|
51
|
+
const promises = [];
|
|
52
|
+
if (moduleOptions.navigation && routeConfig.navigation !== false) {
|
|
53
|
+
const navigationQuery = () => {
|
|
54
|
+
const { navigation: navigation2 } = useContentState();
|
|
55
|
+
if (navigation2.value && !dedup) {
|
|
56
|
+
return navigation2.value;
|
|
57
|
+
}
|
|
58
|
+
return fetchContentNavigation().then((_navigation) => {
|
|
59
|
+
navigation2.value = _navigation;
|
|
60
|
+
return _navigation;
|
|
61
|
+
}).catch(() => null);
|
|
62
|
+
};
|
|
63
|
+
promises.push(navigationQuery);
|
|
64
|
+
} else {
|
|
65
|
+
promises.push(() => Promise.resolve(null));
|
|
66
|
+
}
|
|
67
|
+
if (moduleOptions.globals) {
|
|
68
|
+
const globalsQuery = () => {
|
|
69
|
+
const { globals: globals2 } = useContentState();
|
|
70
|
+
if (typeof moduleOptions.globals === "object" && Array.isArray(moduleOptions.globals)) {
|
|
71
|
+
console.log("Globals must be a list of keys with QueryBuilderParams as a value.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
return Promise.all(
|
|
75
|
+
Object.entries(moduleOptions.globals).map(
|
|
76
|
+
([key, query]) => {
|
|
77
|
+
if (!dedup && globals2.value[key]) {
|
|
78
|
+
return globals2.value[key];
|
|
79
|
+
}
|
|
80
|
+
let type = "findOne";
|
|
81
|
+
if (query?.type) {
|
|
82
|
+
type = query.type;
|
|
83
|
+
}
|
|
84
|
+
return queryContent(query)[type]().catch(() => null);
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
).then(
|
|
88
|
+
(values) => {
|
|
89
|
+
return values.reduce(
|
|
90
|
+
(acc, value, index) => {
|
|
91
|
+
const key = Object.keys(moduleOptions.globals)[index];
|
|
92
|
+
if (key) {
|
|
93
|
+
acc[key] = value;
|
|
94
|
+
}
|
|
95
|
+
return acc;
|
|
96
|
+
},
|
|
97
|
+
{}
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
promises.push(globalsQuery);
|
|
103
|
+
} else {
|
|
104
|
+
promises.push(() => Promise.resolve(null));
|
|
105
|
+
}
|
|
106
|
+
if (moduleOptions.page && routeConfig.page !== false) {
|
|
107
|
+
let where = { _path };
|
|
108
|
+
if (typeof routeConfig.page === "string") {
|
|
109
|
+
where = { _path: routeConfig.page };
|
|
110
|
+
}
|
|
111
|
+
if (typeof routeConfig.page === "object") {
|
|
112
|
+
where = routeConfig.page;
|
|
113
|
+
}
|
|
114
|
+
const pageQuery = () => {
|
|
115
|
+
const { pages: pages2 } = useContentState();
|
|
116
|
+
if (!dedup && pages2.value[_path] && pages2.value[_path]._path === _path) {
|
|
117
|
+
return {
|
|
118
|
+
result: pages2.value[_path],
|
|
119
|
+
surround: surrounds.value[_path]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const query = queryContent().where(where).withDirConfig();
|
|
123
|
+
if (moduleOptions.surround && routeConfig.surround !== false) {
|
|
124
|
+
let surround = _path;
|
|
125
|
+
if (["string", "object"].includes(typeof routeConfig.page)) {
|
|
126
|
+
surround = routeConfig.page;
|
|
127
|
+
}
|
|
128
|
+
if (["string", "object"].includes(typeof routeConfig.surround)) {
|
|
129
|
+
surround = routeConfig.surround;
|
|
130
|
+
}
|
|
131
|
+
query.withSurround(surround);
|
|
132
|
+
}
|
|
133
|
+
return query.findOne().catch(() => null);
|
|
134
|
+
};
|
|
135
|
+
promises.push(pageQuery);
|
|
136
|
+
} else {
|
|
137
|
+
promises.push(() => Promise.resolve(null));
|
|
138
|
+
}
|
|
139
|
+
return await Promise.all(promises.map((promise) => promise())).then(async ([
|
|
140
|
+
_navigation,
|
|
141
|
+
_globals,
|
|
142
|
+
_page
|
|
143
|
+
]) => {
|
|
144
|
+
if (_navigation) {
|
|
145
|
+
navigation.value = _navigation;
|
|
146
|
+
}
|
|
147
|
+
if (_globals) {
|
|
148
|
+
globals.value = _globals;
|
|
149
|
+
}
|
|
150
|
+
if (_page?.surround) {
|
|
151
|
+
surrounds.value[_path] = _page.surround;
|
|
152
|
+
}
|
|
153
|
+
const redirectTo = _page?.result?.redirect || _page?.dirConfig?.navigation?.redirect;
|
|
154
|
+
if (redirectTo) {
|
|
155
|
+
pages.value[_path] = _page.result;
|
|
156
|
+
return redirectTo;
|
|
157
|
+
}
|
|
158
|
+
if (_page?.result) {
|
|
159
|
+
const layoutName = findLayout(to, _page.result, _navigation, _globals);
|
|
160
|
+
const layout = layouts[layoutName];
|
|
161
|
+
if (layout && typeof layout === "function") {
|
|
162
|
+
await layout();
|
|
163
|
+
}
|
|
164
|
+
to.meta.layout = layoutName;
|
|
165
|
+
_page.result.layout = layoutName;
|
|
166
|
+
}
|
|
167
|
+
pages.value[_path] = _page?.result;
|
|
168
|
+
await nuxt.callHook("content:document-driven:finish", { route: to, dedup, page: _page?.result, navigation: _navigation, globals: _globals, surround: _page?.surround });
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
if (import.meta.client) {
|
|
172
|
+
const router = useRouter();
|
|
173
|
+
nuxt.hook("link:prefetch", (link) => {
|
|
174
|
+
if (!(link in pages.value) && !hasProtocol(link)) {
|
|
175
|
+
const route = router.resolve(link);
|
|
176
|
+
if (route.matched.length > 0) {
|
|
177
|
+
refresh(route);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
nuxt.hooks.hook("content:document-driven:finish", ({ page }) => {
|
|
182
|
+
if (page?.body?.children) {
|
|
183
|
+
prefetchBodyComponents(page.body.children);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
addRouteMiddleware(async (to, from) => {
|
|
188
|
+
if (import.meta.client && !isClientDBEnabled && to.path === from.path) {
|
|
189
|
+
if (!to.meta.layout) {
|
|
190
|
+
const _path = withoutTrailingSlash(to.path);
|
|
191
|
+
if (pages.value[_path]) {
|
|
192
|
+
to.meta.layout = pages.value[_path].layout;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const redirect = await refresh(to, false);
|
|
198
|
+
if (redirect) {
|
|
199
|
+
if (hasProtocol(redirect)) {
|
|
200
|
+
return callWithNuxt(nuxt, navigateTo, [redirect, { external: true }]);
|
|
201
|
+
} else {
|
|
202
|
+
return redirect;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
nuxt.hook("app:data:refresh", async () => import.meta.client && await refresh(useRoute(), true));
|
|
207
|
+
});
|
|
208
|
+
function prefetchBodyComponents(nodes) {
|
|
209
|
+
for (const node of nodes) {
|
|
210
|
+
if (node.children) {
|
|
211
|
+
prefetchBodyComponents(node.children);
|
|
212
|
+
}
|
|
213
|
+
if (node.type === "element" && node.tag) {
|
|
214
|
+
const el = pascalCase(node.tag);
|
|
215
|
+
for (const name of ["Prose" + el, el]) {
|
|
216
|
+
if (componentNames.includes(name)) {
|
|
217
|
+
prefetchComponents(name);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineNuxtPlugin, useRuntimeConfig } from "#imports";
|
|
2
|
+
export default defineNuxtPlugin(() => {
|
|
3
|
+
const publicConfig = useRuntimeConfig().public;
|
|
4
|
+
if (import.meta.client && publicConfig.content.wsUrl) {
|
|
5
|
+
import("../composables/web-socket.js").then(({ useContentWebSocket }) => useContentWebSocket());
|
|
6
|
+
}
|
|
7
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { assertArray, ensureArray, get } from "./utils.js";
|
|
2
|
+
export function createMatch(opts = {}) {
|
|
3
|
+
const operators = createOperators(match, opts.operators);
|
|
4
|
+
function match(item, conditions) {
|
|
5
|
+
if (typeof conditions !== "object" || conditions instanceof RegExp) {
|
|
6
|
+
return operators.$eq(item, conditions);
|
|
7
|
+
}
|
|
8
|
+
return Object.keys(conditions || {}).every((key) => {
|
|
9
|
+
const condition = conditions[key];
|
|
10
|
+
if (key.startsWith("$") && operators[key]) {
|
|
11
|
+
const fn = operators[key];
|
|
12
|
+
return typeof fn === "function" ? fn(item, condition) : false;
|
|
13
|
+
}
|
|
14
|
+
return match(get(item, key), condition);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return match;
|
|
18
|
+
}
|
|
19
|
+
function createOperators(match, operators = {}) {
|
|
20
|
+
return {
|
|
21
|
+
$match: (item, condition) => match(item, condition),
|
|
22
|
+
/**
|
|
23
|
+
* Match if item equals condition
|
|
24
|
+
**/
|
|
25
|
+
$eq: (item, condition) => condition instanceof RegExp ? condition.test(item) : item === condition,
|
|
26
|
+
/**
|
|
27
|
+
* Match if item not equals condition
|
|
28
|
+
**/
|
|
29
|
+
$ne: (item, condition) => condition instanceof RegExp ? !condition.test(item) : item !== condition,
|
|
30
|
+
/**
|
|
31
|
+
* Match is condition is false
|
|
32
|
+
**/
|
|
33
|
+
$not: (item, condition) => !match(item, condition),
|
|
34
|
+
/**
|
|
35
|
+
* Match only if all of nested conditions are true
|
|
36
|
+
**/
|
|
37
|
+
$and: (item, condition) => {
|
|
38
|
+
assertArray(condition, "$and requires an array as condition");
|
|
39
|
+
return condition.every((cond) => match(item, cond));
|
|
40
|
+
},
|
|
41
|
+
/**
|
|
42
|
+
* Match if any of nested conditions is true
|
|
43
|
+
**/
|
|
44
|
+
$or: (item, condition) => {
|
|
45
|
+
assertArray(condition, "$or requires an array as condition");
|
|
46
|
+
return condition.some((cond) => match(item, cond));
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Match if item is in condition array
|
|
50
|
+
**/
|
|
51
|
+
$in: (item, condition) => ensureArray(condition).some(
|
|
52
|
+
(cond) => Array.isArray(item) ? match(item, { $contains: cond }) : match(item, cond)
|
|
53
|
+
),
|
|
54
|
+
/**
|
|
55
|
+
* Match if item contains every condition or match every rule in condition array
|
|
56
|
+
**/
|
|
57
|
+
$contains: (item, condition) => {
|
|
58
|
+
item = Array.isArray(item) ? item : String(item);
|
|
59
|
+
return ensureArray(condition).every((i) => item.includes(i));
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* Ignore case contains
|
|
63
|
+
**/
|
|
64
|
+
$icontains: (item, condition) => {
|
|
65
|
+
if (typeof condition !== "string") {
|
|
66
|
+
throw new TypeError("$icontains requires a string, use $contains instead");
|
|
67
|
+
}
|
|
68
|
+
item = String(item).toLocaleLowerCase();
|
|
69
|
+
return ensureArray(condition).every((i) => item.includes(i.toLocaleLowerCase()));
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* Match if item contains at least one rule from condition array
|
|
73
|
+
*/
|
|
74
|
+
$containsAny: (item, condition) => {
|
|
75
|
+
assertArray(condition, "$containsAny requires an array as condition");
|
|
76
|
+
item = Array.isArray(item) ? item : String(item);
|
|
77
|
+
return condition.some((i) => item.includes(i));
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* Check key existence
|
|
81
|
+
*/
|
|
82
|
+
$exists: (item, condition) => condition ? typeof item !== "undefined" : typeof item === "undefined",
|
|
83
|
+
/**
|
|
84
|
+
* Match if type of item equals condition
|
|
85
|
+
*/
|
|
86
|
+
$type: (item, condition) => typeof item === String(condition),
|
|
87
|
+
/**
|
|
88
|
+
* Provides regular expression capabilities for pattern matching strings.
|
|
89
|
+
*/
|
|
90
|
+
$regex: (item, condition) => {
|
|
91
|
+
if (!(condition instanceof RegExp)) {
|
|
92
|
+
const matched = String(condition).match(/\/(.*)\/([dgimsuy]*)$/);
|
|
93
|
+
condition = matched?.[1] ? new RegExp(matched[1], matched[2] || "") : new RegExp(condition);
|
|
94
|
+
}
|
|
95
|
+
return condition.test(String(item || ""));
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* Check if item is less than condition
|
|
99
|
+
*/
|
|
100
|
+
$lt: (item, condition) => {
|
|
101
|
+
return item < condition;
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* Check if item is less than or equal to condition
|
|
105
|
+
*/
|
|
106
|
+
$lte: (item, condition) => {
|
|
107
|
+
return item <= condition;
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* Check if item is greater than condition
|
|
111
|
+
*/
|
|
112
|
+
$gt: (item, condition) => {
|
|
113
|
+
return item > condition;
|
|
114
|
+
},
|
|
115
|
+
/**
|
|
116
|
+
* Check if item is greater than or equal to condition
|
|
117
|
+
*/
|
|
118
|
+
$gte: (item, condition) => {
|
|
119
|
+
return item >= condition;
|
|
120
|
+
},
|
|
121
|
+
...operators || {}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createPipelineFetcher } from "./pipeline.js";
|
|
2
|
+
export function createPipelineFetcherLegacy(getContentsList) {
|
|
3
|
+
const _pipelineFetcher = createPipelineFetcher(getContentsList);
|
|
4
|
+
return async (query) => {
|
|
5
|
+
if (query.params().first) {
|
|
6
|
+
query.withDirConfig();
|
|
7
|
+
}
|
|
8
|
+
const params = query.params();
|
|
9
|
+
const result = await _pipelineFetcher(query);
|
|
10
|
+
if (params.surround) {
|
|
11
|
+
return result?.surround;
|
|
12
|
+
}
|
|
13
|
+
if (result?.dirConfig) {
|
|
14
|
+
result.result = {
|
|
15
|
+
_path: result.dirConfig?._path,
|
|
16
|
+
...result.result,
|
|
17
|
+
_dir: result.dirConfig
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return result?.result;
|
|
21
|
+
};
|
|
22
|
+
}
|