@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,104 @@
|
|
|
1
|
+
import { joinURL } from "ufo";
|
|
2
|
+
import { apply, ensureArray, sortList, withoutKeys, withKeys, omit } from "./utils.js";
|
|
3
|
+
import { createMatch } from "./index.js";
|
|
4
|
+
export function createPipelineFetcher(getContentsList) {
|
|
5
|
+
const match = createMatch();
|
|
6
|
+
const surround = (data, { query, before, after }) => {
|
|
7
|
+
const matchQuery = typeof query === "string" ? { _path: query } : query;
|
|
8
|
+
const index = data.findIndex((item) => match(item, matchQuery));
|
|
9
|
+
before = before ?? 1;
|
|
10
|
+
after = after ?? 1;
|
|
11
|
+
const slice = new Array(before + after).fill(null, 0);
|
|
12
|
+
return index === -1 ? slice : slice.map((_, i) => data[index - before + i + Number(i >= before)] || null);
|
|
13
|
+
};
|
|
14
|
+
const matchingPipelines = [
|
|
15
|
+
// Conditions
|
|
16
|
+
(state, params) => {
|
|
17
|
+
const filtered = state.result.filter((item) => ensureArray(params.where).every((matchQuery) => match(item, matchQuery)));
|
|
18
|
+
return {
|
|
19
|
+
...state,
|
|
20
|
+
result: filtered,
|
|
21
|
+
total: filtered.length
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
// Sort data
|
|
25
|
+
(state, params) => ensureArray(params.sort).forEach((options) => sortList(state.result, options)),
|
|
26
|
+
function fetchSurround(state, params, db) {
|
|
27
|
+
if (params.surround) {
|
|
28
|
+
let _surround = surround(state.result?.length === 1 ? db : state.result, params.surround);
|
|
29
|
+
_surround = apply(withoutKeys(params.without))(_surround);
|
|
30
|
+
_surround = apply(withKeys(params.only))(_surround);
|
|
31
|
+
state.surround = _surround;
|
|
32
|
+
}
|
|
33
|
+
return state;
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
const transformingPiples = [
|
|
37
|
+
// Skip first items
|
|
38
|
+
(state, params) => {
|
|
39
|
+
if (params.skip) {
|
|
40
|
+
return {
|
|
41
|
+
...state,
|
|
42
|
+
result: state.result.slice(params.skip),
|
|
43
|
+
skip: params.skip
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
// Pick first items
|
|
48
|
+
(state, params) => {
|
|
49
|
+
if (params.limit) {
|
|
50
|
+
return {
|
|
51
|
+
...state,
|
|
52
|
+
result: state.result.slice(0, params.limit),
|
|
53
|
+
limit: params.limit
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
function fetchDirConfig(state, params, db) {
|
|
58
|
+
if (params.dirConfig) {
|
|
59
|
+
const path = state.result[0]?._path || params.where?.find((w) => w._path)?._path;
|
|
60
|
+
if (typeof path === "string") {
|
|
61
|
+
const dirConfig = db.find((item) => item._path === joinURL(path, "_dir"));
|
|
62
|
+
if (dirConfig) {
|
|
63
|
+
state.dirConfig = { _path: dirConfig._path, ...withoutKeys(["_"])(dirConfig) };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return state;
|
|
68
|
+
},
|
|
69
|
+
// Remove unwanted fields
|
|
70
|
+
(state, params) => ({
|
|
71
|
+
...state,
|
|
72
|
+
result: apply(withoutKeys(params.without))(state.result)
|
|
73
|
+
}),
|
|
74
|
+
// Select only wanted fields
|
|
75
|
+
(state, params) => ({
|
|
76
|
+
...state,
|
|
77
|
+
result: apply(withKeys(params.only))(state.result)
|
|
78
|
+
})
|
|
79
|
+
];
|
|
80
|
+
return async (query) => {
|
|
81
|
+
const db = await getContentsList();
|
|
82
|
+
const params = query.params();
|
|
83
|
+
const result1 = {
|
|
84
|
+
result: db,
|
|
85
|
+
limit: 0,
|
|
86
|
+
skip: 0,
|
|
87
|
+
total: db.length
|
|
88
|
+
};
|
|
89
|
+
const matchedData = matchingPipelines.reduce(($data, pipe) => pipe($data, params, db) || $data, result1);
|
|
90
|
+
if (params.count) {
|
|
91
|
+
return {
|
|
92
|
+
result: matchedData.result.length
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const result = transformingPiples.reduce(($data, pipe) => pipe($data, params, db) || $data, matchedData);
|
|
96
|
+
if (params.first) {
|
|
97
|
+
return {
|
|
98
|
+
...omit(["skip", "limit", "total"])(result),
|
|
99
|
+
result: result.result[0]
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SortOptions } from '@nuxt/content';
|
|
2
|
+
/**
|
|
3
|
+
* Retrive nested value from object by path
|
|
4
|
+
*/
|
|
5
|
+
export declare const get: (obj: any, path: string) => any;
|
|
6
|
+
/**
|
|
7
|
+
* Returns a new object with the specified keys
|
|
8
|
+
**/
|
|
9
|
+
export declare const pick: (keys?: string[]) => (obj: any) => any;
|
|
10
|
+
/**
|
|
11
|
+
* Returns a new object with all the keys of the original object execept the ones specified.
|
|
12
|
+
**/
|
|
13
|
+
export declare const omit: (keys?: string[]) => (obj: any) => any;
|
|
14
|
+
/**
|
|
15
|
+
* Apply a function to each element of an array
|
|
16
|
+
*/
|
|
17
|
+
export declare const apply: (fn: (d: any) => any) => (data: any) => any;
|
|
18
|
+
export declare const detectProperties: (keys: string[]) => {
|
|
19
|
+
prefixes: string[];
|
|
20
|
+
properties: string[];
|
|
21
|
+
};
|
|
22
|
+
export declare const withoutKeys: (keys?: string[]) => (obj: any) => any;
|
|
23
|
+
export declare const withKeys: (keys?: string[]) => (obj: any) => any;
|
|
24
|
+
/**
|
|
25
|
+
* Sort list of items by givin options
|
|
26
|
+
*/
|
|
27
|
+
export declare const sortList: (data: any[], params: SortOptions) => any[];
|
|
28
|
+
/**
|
|
29
|
+
* Raise TypeError if value is not an array
|
|
30
|
+
*/
|
|
31
|
+
export declare const assertArray: (value: any, message?: string) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Ensure result is an array
|
|
34
|
+
*/
|
|
35
|
+
export declare const ensureArray: <T>(value: T) => T extends Array<any> ? T : T[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export const get = (obj, path) => path.split(".").reduce((acc, part) => acc && acc[part], obj);
|
|
2
|
+
const _pick = (obj, condition) => Object.keys(obj).filter(condition).reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {});
|
|
3
|
+
export const pick = (keys) => (obj) => keys && keys.length ? _pick(obj, (key) => keys.includes(key)) : obj;
|
|
4
|
+
export const omit = (keys) => (obj) => keys && keys.length ? _pick(obj, (key) => !keys.includes(key)) : obj;
|
|
5
|
+
export const apply = (fn) => (data) => Array.isArray(data) ? data.map((item) => fn(item)) : fn(data);
|
|
6
|
+
export const detectProperties = (keys) => {
|
|
7
|
+
const prefixes = [];
|
|
8
|
+
const properties = [];
|
|
9
|
+
for (const key of keys) {
|
|
10
|
+
if (["$", "_"].includes(key)) {
|
|
11
|
+
prefixes.push(key);
|
|
12
|
+
} else {
|
|
13
|
+
properties.push(key);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { prefixes, properties };
|
|
17
|
+
};
|
|
18
|
+
export const withoutKeys = (keys = []) => (obj) => {
|
|
19
|
+
if (keys.length === 0 || !obj) {
|
|
20
|
+
return obj;
|
|
21
|
+
}
|
|
22
|
+
const { prefixes, properties } = detectProperties(keys);
|
|
23
|
+
return _pick(obj, (key) => !properties.includes(key) && !prefixes.includes(key[0]));
|
|
24
|
+
};
|
|
25
|
+
export const withKeys = (keys = []) => (obj) => {
|
|
26
|
+
if (keys.length === 0 || !obj) {
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
const { prefixes, properties } = detectProperties(keys);
|
|
30
|
+
return _pick(obj, (key) => properties.includes(key) || prefixes.includes(key[0]));
|
|
31
|
+
};
|
|
32
|
+
export const sortList = (data, params) => {
|
|
33
|
+
const comperable = new Intl.Collator(params.$locale, {
|
|
34
|
+
numeric: params.$numeric,
|
|
35
|
+
caseFirst: params.$caseFirst,
|
|
36
|
+
sensitivity: params.$sensitivity
|
|
37
|
+
});
|
|
38
|
+
const keys = Object.keys(params).filter((key) => !key.startsWith("$"));
|
|
39
|
+
for (const key of keys) {
|
|
40
|
+
data = data.sort((a, b) => {
|
|
41
|
+
const values = [get(a, key), get(b, key)].map((value) => {
|
|
42
|
+
if (value === null) {
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
if (value instanceof Date) {
|
|
46
|
+
return value.toISOString();
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
});
|
|
50
|
+
if (params[key] === -1) {
|
|
51
|
+
values.reverse();
|
|
52
|
+
}
|
|
53
|
+
return comperable.compare(values[0], values[1]);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return data;
|
|
57
|
+
};
|
|
58
|
+
export const assertArray = (value, message = "Expected an array") => {
|
|
59
|
+
if (!Array.isArray(value)) {
|
|
60
|
+
throw new TypeError(message);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
export const ensureArray = (value) => {
|
|
64
|
+
return Array.isArray(value) ? value : [void 0, null].includes(value) ? [] : [value];
|
|
65
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { QueryBuilder, ParsedContent, ContentQueryBuilder, ContentQueryBuilderParams, ContentQueryFetcher } from '@nuxt/content';
|
|
2
|
+
interface QueryOptions {
|
|
3
|
+
initialParams?: ContentQueryBuilderParams;
|
|
4
|
+
legacy?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function createQuery<T = ParsedContent>(fetcher: ContentQueryFetcher<T>, opts: QueryOptions & {
|
|
7
|
+
legacy: true;
|
|
8
|
+
}): QueryBuilder<T>;
|
|
9
|
+
export declare function createQuery<T = ParsedContent>(fetcher: ContentQueryFetcher<T>, opts: QueryOptions & {
|
|
10
|
+
legacy: false;
|
|
11
|
+
}): ContentQueryBuilder<T>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ensureArray } from "./match/utils.js";
|
|
2
|
+
const arrayParams = ["sort", "where", "only", "without"];
|
|
3
|
+
export function createQuery(fetcher, opts = {}) {
|
|
4
|
+
const queryParams = {};
|
|
5
|
+
for (const key of Object.keys(opts.initialParams || {})) {
|
|
6
|
+
queryParams[key] = arrayParams.includes(key) ? ensureArray(opts.initialParams[key]) : opts.initialParams[key];
|
|
7
|
+
}
|
|
8
|
+
const $set = (key, fn = (v) => v) => {
|
|
9
|
+
return (...values) => {
|
|
10
|
+
queryParams[key] = fn(...values);
|
|
11
|
+
return query;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
const resolveResult = (result) => {
|
|
15
|
+
if (opts.legacy) {
|
|
16
|
+
if (result?.surround) {
|
|
17
|
+
return result.surround;
|
|
18
|
+
}
|
|
19
|
+
if (!result) {
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
if (result?.dirConfig) {
|
|
23
|
+
result.result = {
|
|
24
|
+
_path: result.dirConfig?._path,
|
|
25
|
+
...result.result,
|
|
26
|
+
_dir: result.dirConfig
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return result?._path || Array.isArray(result) || !Object.prototype.hasOwnProperty.call(result, "result") ? result : result?.result;
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
const query = {
|
|
34
|
+
params: () => ({
|
|
35
|
+
...queryParams,
|
|
36
|
+
...queryParams.where ? { where: [...ensureArray(queryParams.where)] } : {},
|
|
37
|
+
...queryParams.sort ? { sort: [...ensureArray(queryParams.sort)] } : {}
|
|
38
|
+
}),
|
|
39
|
+
only: $set("only", ensureArray),
|
|
40
|
+
without: $set("without", ensureArray),
|
|
41
|
+
where: $set("where", (q) => [...ensureArray(queryParams.where), ...ensureArray(q)]),
|
|
42
|
+
sort: $set("sort", (sort) => [...ensureArray(queryParams.sort), ...ensureArray(sort)]),
|
|
43
|
+
limit: $set("limit", (v) => parseInt(String(v), 10)),
|
|
44
|
+
skip: $set("skip", (v) => parseInt(String(v), 10)),
|
|
45
|
+
// find
|
|
46
|
+
find: () => fetcher(query).then(resolveResult),
|
|
47
|
+
findOne: () => fetcher($set("first")(true)).then(resolveResult),
|
|
48
|
+
count: () => fetcher($set("count")(true)).then(resolveResult),
|
|
49
|
+
// locale
|
|
50
|
+
locale: (_locale) => query.where({ _locale }),
|
|
51
|
+
withSurround: $set("surround", (surroundQuery, options) => ({ query: surroundQuery, ...options })),
|
|
52
|
+
withDirConfig: () => $set("dirConfig")(true)
|
|
53
|
+
};
|
|
54
|
+
if (opts.legacy) {
|
|
55
|
+
query.findSurround = (surroundQuery, options) => {
|
|
56
|
+
return query.withSurround(surroundQuery, options).find().then(resolveResult);
|
|
57
|
+
};
|
|
58
|
+
return query;
|
|
59
|
+
}
|
|
60
|
+
return query;
|
|
61
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineEventHandler } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const { getContentIndex } = await import("../content-index.js");
|
|
5
|
+
const { cacheStorage, serverQueryContent } = await import("../storage.js");
|
|
6
|
+
const { content } = useRuntimeConfig();
|
|
7
|
+
const now = Date.now();
|
|
8
|
+
const contents = await serverQueryContent(event).find();
|
|
9
|
+
await getContentIndex(event);
|
|
10
|
+
const navigation = await $fetch(`${content.api.baseURL}/navigation`);
|
|
11
|
+
await cacheStorage().setItem("content-navigation.json", navigation);
|
|
12
|
+
return {
|
|
13
|
+
generatedAt: now,
|
|
14
|
+
generateTime: Date.now() - now,
|
|
15
|
+
contents: content.experimental.cacheContents ? contents : [],
|
|
16
|
+
navigation
|
|
17
|
+
};
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as default } from './navigation';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./navigation.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as default } from './navigation';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./navigation.js";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defineEventHandler } from "h3";
|
|
2
|
+
import { isPreview } from "../preview.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const { getContentQuery } = await import("../../utils/query.js");
|
|
5
|
+
const { cacheStorage, serverQueryContent } = await import("../storage.js");
|
|
6
|
+
const { createNav } = await import("../navigation.js");
|
|
7
|
+
const query = getContentQuery(event);
|
|
8
|
+
if (!isPreview(event) && Object.keys(query).length === 0) {
|
|
9
|
+
const cache = await cacheStorage().getItem("content-navigation.json");
|
|
10
|
+
if (cache) {
|
|
11
|
+
return cache;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const contents = await serverQueryContent(event, query).where({
|
|
15
|
+
/**
|
|
16
|
+
* Partial contents are not included in the navigation
|
|
17
|
+
* A partial content is a content that has `_` prefix in its path
|
|
18
|
+
*/
|
|
19
|
+
_partial: false,
|
|
20
|
+
/**
|
|
21
|
+
* Exclude any pages which have opted out of navigation via frontmatter.
|
|
22
|
+
*/
|
|
23
|
+
navigation: {
|
|
24
|
+
$ne: false
|
|
25
|
+
}
|
|
26
|
+
}).find();
|
|
27
|
+
const _locale = (query?.where || []).find((w) => w._locale)?._locale;
|
|
28
|
+
const dirConfigs = await serverQueryContent(event, _locale ? { where: [{ _locale }] } : void 0).where({ _path: /\/_dir$/i, _partial: true }).find();
|
|
29
|
+
const configs = (dirConfigs?.result || dirConfigs).reduce((configs2, conf) => {
|
|
30
|
+
if (conf.title?.toLowerCase() === "dir") {
|
|
31
|
+
conf.title = void 0;
|
|
32
|
+
}
|
|
33
|
+
const key = conf._path.split("/").slice(0, -1).join("/") || "/";
|
|
34
|
+
configs2[key] = {
|
|
35
|
+
...conf,
|
|
36
|
+
// Extract meta from body. (non MD files)
|
|
37
|
+
...conf.body
|
|
38
|
+
};
|
|
39
|
+
return configs2;
|
|
40
|
+
}, {});
|
|
41
|
+
return createNav(contents?.result || contents, configs);
|
|
42
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as default } from './query';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./query.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as default } from './query';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./query.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createError, defineEventHandler } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const { getContentQuery } = await import("../../utils/query.js");
|
|
5
|
+
const { serverQueryContent } = await import("../storage.js");
|
|
6
|
+
const query = getContentQuery(event);
|
|
7
|
+
const { advanceQuery } = useRuntimeConfig().public.content.experimental;
|
|
8
|
+
if (query.first) {
|
|
9
|
+
let contentQuery = serverQueryContent(event, query);
|
|
10
|
+
if (!advanceQuery) {
|
|
11
|
+
contentQuery = contentQuery.withDirConfig();
|
|
12
|
+
}
|
|
13
|
+
const content = await contentQuery.findOne();
|
|
14
|
+
const _result = advanceQuery ? content?.result : content;
|
|
15
|
+
const missing = !_result && !content?.dirConfig?.navigation?.redirect && !content?._dir?.navigation?.redirect;
|
|
16
|
+
if (missing) {
|
|
17
|
+
throw createError({
|
|
18
|
+
statusMessage: "Document not found!",
|
|
19
|
+
statusCode: 404,
|
|
20
|
+
data: {
|
|
21
|
+
description: "Could not find document for the given query.",
|
|
22
|
+
query
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return content;
|
|
27
|
+
}
|
|
28
|
+
if (query.count) {
|
|
29
|
+
return serverQueryContent(event, query).count();
|
|
30
|
+
}
|
|
31
|
+
return serverQueryContent(event, query).find();
|
|
32
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineEventHandler } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const { serverSearchContent, splitPageIntoSections } = await import("../search.js");
|
|
5
|
+
const MiniSearch = await import("minisearch").then((m) => m.default);
|
|
6
|
+
const runtimeConfig = useRuntimeConfig();
|
|
7
|
+
const { ignoredTags = [], filterQuery, indexed, options } = runtimeConfig.public.content.search;
|
|
8
|
+
const files = await serverSearchContent(event, filterQuery);
|
|
9
|
+
const sections = files.map((page) => splitPageIntoSections(page, { ignoredTags })).flat();
|
|
10
|
+
if (indexed) {
|
|
11
|
+
const miniSearch = new MiniSearch(options);
|
|
12
|
+
miniSearch.addAll(sections);
|
|
13
|
+
return JSON.stringify(miniSearch);
|
|
14
|
+
}
|
|
15
|
+
return sections;
|
|
16
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { ParsedContent, ContentQueryBuilder } from '@nuxt/content';
|
|
3
|
+
export declare function getContentIndex(event: H3Event): Promise<Record<string, string[]>>;
|
|
4
|
+
export declare function getIndexedContentsList<T = ParsedContent>(event: H3Event, query: ContentQueryBuilder<T>): Promise<T[]>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { isPreview } from "./preview.js";
|
|
2
|
+
import { cacheStorage, chunksFromArray, getContent, getContentsList } from "./storage.js";
|
|
3
|
+
import { useRuntimeConfig } from "#imports";
|
|
4
|
+
export async function getContentIndex(event) {
|
|
5
|
+
const defaultLocale = useRuntimeConfig().content.defaultLocale;
|
|
6
|
+
let contentIndex = await cacheStorage().getItem("content-index.json");
|
|
7
|
+
if (!contentIndex) {
|
|
8
|
+
const data = await getContentsList(event);
|
|
9
|
+
contentIndex = data.reduce((acc, item) => {
|
|
10
|
+
acc[item._path] = acc[item._path] || [];
|
|
11
|
+
if (item._locale === defaultLocale) {
|
|
12
|
+
acc[item._path].unshift(item._id);
|
|
13
|
+
} else {
|
|
14
|
+
acc[item._path].push(item._id);
|
|
15
|
+
}
|
|
16
|
+
return acc;
|
|
17
|
+
}, {});
|
|
18
|
+
await cacheStorage().setItem("content-index.json", contentIndex);
|
|
19
|
+
}
|
|
20
|
+
return contentIndex;
|
|
21
|
+
}
|
|
22
|
+
export async function getIndexedContentsList(event, query) {
|
|
23
|
+
const params = query.params();
|
|
24
|
+
const path = params?.where?.find((wh) => wh._path)?._path;
|
|
25
|
+
if (!isPreview(event) && !params.surround && !params.dirConfig && (typeof path === "string" || path instanceof RegExp)) {
|
|
26
|
+
const index = await getContentIndex(event);
|
|
27
|
+
const keys = Object.keys(index).filter((key) => path.test ? path.test(key) : key === String(path)).flatMap((key) => index[key]);
|
|
28
|
+
const keyChunks = [...chunksFromArray(keys, 10)];
|
|
29
|
+
const contents = [];
|
|
30
|
+
for await (const chunk of keyChunks) {
|
|
31
|
+
const result = await Promise.all(chunk.map((key) => getContent(event, key)));
|
|
32
|
+
contents.push(...result);
|
|
33
|
+
}
|
|
34
|
+
return contents;
|
|
35
|
+
}
|
|
36
|
+
return getContentsList(event);
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { serverQueryContent, parseContent } from './storage';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { serverQueryContent, parseContent } from "./storage.js";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { generateTitle } from "../transformers/path-meta.js";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
export function createNav(contents, configs) {
|
|
4
|
+
const { navigation } = useRuntimeConfig().public.content;
|
|
5
|
+
if (navigation === false) {
|
|
6
|
+
return [];
|
|
7
|
+
}
|
|
8
|
+
const pickNavigationFields = (content) => ({
|
|
9
|
+
...pick(["title", ...navigation.fields])(content),
|
|
10
|
+
...isObject(content?.navigation) ? content.navigation : {}
|
|
11
|
+
});
|
|
12
|
+
const nav = contents.sort((a, b) => a._path.localeCompare(b._path)).reduce((nav2, content) => {
|
|
13
|
+
const parts = content._path.substring(1).split("/");
|
|
14
|
+
const idParts = content._id.split(":").slice(1);
|
|
15
|
+
const isIndex = !!idParts[idParts.length - 1]?.match(/([1-9][0-9]*\.)?index.md/g);
|
|
16
|
+
const getNavItem = (content2) => ({
|
|
17
|
+
title: content2.title,
|
|
18
|
+
_path: content2._path,
|
|
19
|
+
_file: content2._file,
|
|
20
|
+
children: [],
|
|
21
|
+
...pickNavigationFields(content2),
|
|
22
|
+
...content2._draft ? { _draft: true } : {}
|
|
23
|
+
});
|
|
24
|
+
const navItem = getNavItem(content);
|
|
25
|
+
if (isIndex) {
|
|
26
|
+
const dirConfig = configs[navItem._path];
|
|
27
|
+
if (typeof dirConfig?.navigation !== "undefined" && !dirConfig?.navigation) {
|
|
28
|
+
return nav2;
|
|
29
|
+
}
|
|
30
|
+
if (content._path !== "/") {
|
|
31
|
+
const indexItem = getNavItem(content);
|
|
32
|
+
navItem.children.push(indexItem);
|
|
33
|
+
}
|
|
34
|
+
if (dirConfig) {
|
|
35
|
+
Object.assign(
|
|
36
|
+
navItem,
|
|
37
|
+
pickNavigationFields(dirConfig)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (parts.length === 1) {
|
|
42
|
+
nav2.push(navItem);
|
|
43
|
+
return nav2;
|
|
44
|
+
}
|
|
45
|
+
const siblings = parts.slice(0, -1).reduce((nodes, part, i) => {
|
|
46
|
+
const currentPathPart = "/" + parts.slice(0, i + 1).join("/");
|
|
47
|
+
const conf = configs[currentPathPart];
|
|
48
|
+
if (typeof conf?.navigation !== "undefined" && !conf.navigation) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
let parent = nodes.find((n) => n._path === currentPathPart);
|
|
52
|
+
if (!parent) {
|
|
53
|
+
parent = {
|
|
54
|
+
title: generateTitle(part),
|
|
55
|
+
_path: currentPathPart,
|
|
56
|
+
_file: content._file,
|
|
57
|
+
children: [],
|
|
58
|
+
...conf && pickNavigationFields(conf)
|
|
59
|
+
};
|
|
60
|
+
nodes.push(parent);
|
|
61
|
+
}
|
|
62
|
+
return parent.children;
|
|
63
|
+
}, nav2);
|
|
64
|
+
siblings.push(navItem);
|
|
65
|
+
return nav2;
|
|
66
|
+
}, []);
|
|
67
|
+
return sortAndClear(nav);
|
|
68
|
+
}
|
|
69
|
+
const collator = new Intl.Collator(void 0, { numeric: true, sensitivity: "base" });
|
|
70
|
+
function sortAndClear(nav) {
|
|
71
|
+
nav.forEach((item) => {
|
|
72
|
+
item._file = item._file.split(".").slice(0, -1).join(".");
|
|
73
|
+
});
|
|
74
|
+
const sorted = nav.sort((a, b) => collator.compare(a._file, b._file));
|
|
75
|
+
for (const item of sorted) {
|
|
76
|
+
if (item.children?.length) {
|
|
77
|
+
sortAndClear(item.children);
|
|
78
|
+
} else {
|
|
79
|
+
delete item.children;
|
|
80
|
+
}
|
|
81
|
+
delete item._file;
|
|
82
|
+
}
|
|
83
|
+
return nav;
|
|
84
|
+
}
|
|
85
|
+
function pick(keys) {
|
|
86
|
+
return (obj) => {
|
|
87
|
+
obj = obj || {};
|
|
88
|
+
if (keys && keys.length) {
|
|
89
|
+
return keys.filter((key) => typeof obj[key] !== "undefined").reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {});
|
|
90
|
+
}
|
|
91
|
+
return obj;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function isObject(obj) {
|
|
95
|
+
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
96
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useStorage, defineNitroPlugin } from "#imports";
|
|
2
|
+
export default defineNitroPlugin(async (nitro) => {
|
|
3
|
+
const { cleanCachedContents } = await import("../storage.js");
|
|
4
|
+
const storage = useStorage();
|
|
5
|
+
const unwatch = await storage.watch(async (event, key) => {
|
|
6
|
+
if (key.startsWith("content:source")) {
|
|
7
|
+
cleanCachedContents();
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
nitro.hooks.hook("close", async () => {
|
|
11
|
+
if (typeof unwatch === "function") {
|
|
12
|
+
await unwatch();
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getQuery, getCookie } from "h3";
|
|
2
|
+
export const isPreview = (event) => {
|
|
3
|
+
const previewToken = getQuery(event).previewToken || getCookie(event, "previewToken");
|
|
4
|
+
return !!previewToken;
|
|
5
|
+
};
|
|
6
|
+
export const getPreview = (event) => {
|
|
7
|
+
const key = getQuery(event).previewToken || getCookie(event, "previewToken");
|
|
8
|
+
return { key };
|
|
9
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { ParsedContent, QueryBuilderWhere } from '@nuxt/content';
|
|
3
|
+
export declare function serverSearchContent(event: H3Event, filterQuery?: QueryBuilderWhere): Promise<ParsedContent[]>;
|
|
4
|
+
type Section = {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
titles: string[];
|
|
8
|
+
level: number;
|
|
9
|
+
content: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function splitPageIntoSections(page: ParsedContent, { ignoredTags }: {
|
|
12
|
+
ignoredTags: string[];
|
|
13
|
+
}): Section[];
|
|
14
|
+
export {};
|