@xleddyl/nuxt-cms 0.1.43 → 0.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +12 -44
- package/dist/runtime/seed.d.ts +7 -0
- package/dist/runtime/seed.js +10 -0
- package/dist/runtime/shared/index.d.ts +3 -3
- package/dist/runtime/shared/index.js +7 -2
- package/dist/runtime/shared/page-routes.d.ts +4 -0
- package/dist/runtime/shared/page-routes.js +41 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { existsSync
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { join, isAbsolute, resolve, relative, dirname } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -10,10 +10,11 @@ import { introspectionFromSchema, buildSchema } from 'graphql';
|
|
|
10
10
|
import { minifyIntrospection, outputIntrospectionFile } from 'gql.tada/internal';
|
|
11
11
|
import { createJiti } from 'jiti';
|
|
12
12
|
import { typeName, blockTypeName, blocksFieldTypeName, renderGraphqlSdl } from '../dist/runtime/shared/graphql-sdl.js';
|
|
13
|
-
import { isTranslatableField, isTranslatableMediaField, isMultiSelect, pageAllFields, PAGE_PATH_FIELD, pageRoutes, fieldConditions, isRequiredField, pageFields, isPrivateField, entryFieldsFor,
|
|
13
|
+
import { isTranslatableField, isTranslatableMediaField, isMultiSelect, pageAllFields, PAGE_PATH_FIELD, pageRoutes, fieldConditions, isRequiredField, pageFields, isPrivateField, entryFieldsFor, mediaTypeFilter, DEFAULT_MEDIA_MAX_FILE_SIZE } from '../dist/runtime/shared/index.js';
|
|
14
14
|
import { scanMediaDirectory, readMediaFileMeta } from '../dist/runtime/server/utils/media-sync.js';
|
|
15
15
|
import { createHash } from 'node:crypto';
|
|
16
16
|
import { readFile } from 'node:fs/promises';
|
|
17
|
+
import { routePathsFromDir, resolvePageRoutes } from '../dist/runtime/shared/page-routes.js';
|
|
17
18
|
|
|
18
19
|
async function collectMediaManifest(root) {
|
|
19
20
|
const files = await scanMediaDirectory(root);
|
|
@@ -154,16 +155,22 @@ function validateConfig(config, i18n) {
|
|
|
154
155
|
for (const [path, override] of Object.entries(entry.overrides ?? {})) {
|
|
155
156
|
const oat = `${at}, override '${path}'`;
|
|
156
157
|
if (known.size && !known.has(path)) errors.push(`${oat}: '${path}' is not a page path`);
|
|
157
|
-
for (const key of Object.
|
|
158
|
-
|
|
158
|
+
for (const [key, field] of Object.entries(override)) {
|
|
159
|
+
const shared = Object.hasOwn(entry.fields ?? {}, key);
|
|
160
|
+
if (field && shared)
|
|
159
161
|
errors.push(`${oat}: field '${key}' is already declared for every page`);
|
|
162
|
+
if (!field && !shared)
|
|
163
|
+
errors.push(
|
|
164
|
+
`${oat}: field '${key}' is not declared for every page, nothing to remove`
|
|
165
|
+
);
|
|
160
166
|
if (key === PAGE_PATH_FIELD)
|
|
161
167
|
errors.push(`${oat}: '${PAGE_PATH_FIELD}' is a reserved field name on pages`);
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
170
|
const declared = /* @__PURE__ */ new Map();
|
|
165
|
-
for (const
|
|
171
|
+
for (const override of Object.values(entry.overrides ?? {})) {
|
|
166
172
|
for (const [key, field] of Object.entries(override)) {
|
|
173
|
+
if (!field) continue;
|
|
167
174
|
const seen = declared.get(key);
|
|
168
175
|
if (seen && seen !== field.type) {
|
|
169
176
|
errors.push(
|
|
@@ -592,45 +599,6 @@ function renderQueriesFile(config) {
|
|
|
592
599
|
].join("\n");
|
|
593
600
|
}
|
|
594
601
|
|
|
595
|
-
const DYNAMIC = /[[\]]/;
|
|
596
|
-
function vueFiles(dir, prefix = "") {
|
|
597
|
-
if (!existsSync(dir)) return [];
|
|
598
|
-
const files = [];
|
|
599
|
-
for (const item of readdirSync(dir, { withFileTypes: true })) {
|
|
600
|
-
const name = `${prefix}${item.name}`;
|
|
601
|
-
if (item.isDirectory()) files.push(...vueFiles(join(dir, item.name), `${name}/`));
|
|
602
|
-
else if (item.name.endsWith(".vue")) files.push(name);
|
|
603
|
-
}
|
|
604
|
-
return files;
|
|
605
|
-
}
|
|
606
|
-
function routePathFromFile(file) {
|
|
607
|
-
if (DYNAMIC.test(file)) return null;
|
|
608
|
-
const segments = file.replace(/\.vue$/, "").split("/").filter((segment) => !/^\(.+\)$/.test(segment));
|
|
609
|
-
if (segments.at(-1) === "index") segments.pop();
|
|
610
|
-
const path = `/${segments.join("/")}`.replace(/\/$/, "");
|
|
611
|
-
return path || "/";
|
|
612
|
-
}
|
|
613
|
-
function routePathsFromDir(pagesDir) {
|
|
614
|
-
const paths = /* @__PURE__ */ new Set();
|
|
615
|
-
for (const file of vueFiles(pagesDir)) {
|
|
616
|
-
const path = routePathFromFile(file);
|
|
617
|
-
if (path) paths.add(path);
|
|
618
|
-
}
|
|
619
|
-
return [...paths];
|
|
620
|
-
}
|
|
621
|
-
function resolvePageRoutes(entry, discovered) {
|
|
622
|
-
const declared = Array.isArray(entry.routes) ? entry.routes : discovered;
|
|
623
|
-
const paths = /* @__PURE__ */ new Set([...declared, ...entry.include ?? []]);
|
|
624
|
-
for (const path of entry.exclude ?? []) paths.delete(path);
|
|
625
|
-
const rank = new Map((entry.order ?? []).map((path, index) => [path, index]));
|
|
626
|
-
const order = entry.order?.length ?? 0;
|
|
627
|
-
return [...paths].sort((a, b) => (rank.get(a) ?? order) - (rank.get(b) ?? order) || a.localeCompare(b)).map((path) => ({
|
|
628
|
-
path,
|
|
629
|
-
key: pageKeyFromPath(path),
|
|
630
|
-
label: entry.labels?.[path] ?? pageLabelFromPath(path)
|
|
631
|
-
}));
|
|
632
|
-
}
|
|
633
|
-
|
|
634
602
|
function mediaTsType(field) {
|
|
635
603
|
const types = mediaTypeFilter(field.mediaType);
|
|
636
604
|
return types ? `CmsMedia<${types.map((type) => `'${type}'`).join(" | ")}>` : "CmsMedia";
|
package/dist/runtime/seed.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import type { CmsConfig, CmsPageRoute } from './shared/index.js';
|
|
1
2
|
import { customId, ID_LENGTH } from './server/utils/custom-id.js';
|
|
2
3
|
export { customId, ID_LENGTH };
|
|
4
|
+
export type { CmsPageRoute };
|
|
5
|
+
export interface ResolveCmsPagesOptions {
|
|
6
|
+
root?: string;
|
|
7
|
+
pagesDir?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveCmsPages<T extends CmsConfig>(config: T, options?: ResolveCmsPagesOptions): T;
|
|
3
10
|
export type SeedDriver = 'sqlite' | 'libsql' | 'postgres';
|
|
4
11
|
export interface CmsSeederOptions {
|
|
5
12
|
driver?: SeedDriver;
|
package/dist/runtime/seed.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { mkdirSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { resolvePageRoutes, routePathsFromDir } from "./shared/page-routes.js";
|
|
3
4
|
import { customId, ID_LENGTH } from "./server/utils/custom-id.js";
|
|
4
5
|
export { customId, ID_LENGTH };
|
|
6
|
+
export function resolveCmsPages(config, options = {}) {
|
|
7
|
+
const root = options.root ?? process.cwd();
|
|
8
|
+
const pagesDir = options.pagesDir ? isAbsolute(options.pagesDir) ? options.pagesDir : resolve(root, options.pagesDir) : resolve(root, "app/pages");
|
|
9
|
+
const discovered = routePathsFromDir(pagesDir);
|
|
10
|
+
for (const entry of Object.values(config)) {
|
|
11
|
+
if (entry.kind === "page") entry.pages = resolvePageRoutes(entry, discovered);
|
|
12
|
+
}
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
5
15
|
function inferDriver(url) {
|
|
6
16
|
if (/^(libsql|wss?|https?):\/\//.test(url)) return "libsql";
|
|
7
17
|
if (/^postgres(ql)?:\/\//.test(url)) return "postgres";
|
|
@@ -106,7 +106,7 @@ export interface CmsEntry {
|
|
|
106
106
|
exclude?: string[];
|
|
107
107
|
order?: string[];
|
|
108
108
|
labels?: Record<string, string>;
|
|
109
|
-
overrides?: Record<string, Record<string, FieldConfig>>;
|
|
109
|
+
overrides?: Record<string, Record<string, FieldConfig | null>>;
|
|
110
110
|
pages?: CmsPageRoute[];
|
|
111
111
|
table?: CmsTable;
|
|
112
112
|
}
|
|
@@ -119,7 +119,7 @@ export declare function pageLabelFromPath(path: string): string;
|
|
|
119
119
|
export declare function pageParentPath(path: string): string | undefined;
|
|
120
120
|
export declare function pageRoutes(entry: CmsEntry): CmsPageRoute[];
|
|
121
121
|
export declare function pageRouteOf(entry: CmsEntry, key: string): CmsPageRoute | undefined;
|
|
122
|
-
export declare function pageOverrideFields(entry: CmsEntry, path: string): Record<string, FieldConfig>;
|
|
122
|
+
export declare function pageOverrideFields(entry: CmsEntry, path: string): Record<string, FieldConfig | null>;
|
|
123
123
|
export declare function pageFields(entry: CmsEntry, path: string): Record<string, FieldConfig>;
|
|
124
124
|
export declare function pageAllFields(entry: CmsEntry): Record<string, FieldConfig>;
|
|
125
125
|
type EntryLike = Pick<CmsEntry, 'fields'> & Partial<Pick<CmsEntry, 'kind' | 'overrides'>>;
|
|
@@ -213,7 +213,7 @@ export interface CmsPageInput extends CmsEntryInputBase {
|
|
|
213
213
|
exclude?: string[];
|
|
214
214
|
order?: string[];
|
|
215
215
|
labels?: Record<string, string>;
|
|
216
|
-
overrides?: Record<string, Record<string, CmsFieldInput>>;
|
|
216
|
+
overrides?: Record<string, Record<string, CmsFieldInput | null>>;
|
|
217
217
|
}
|
|
218
218
|
export type CmsEntryInput = CmsCollectionInput | CmsSingleInput | CmsPageInput;
|
|
219
219
|
export type CmsConfigInput = Record<string, CmsEntryInput>;
|
|
@@ -216,13 +216,18 @@ export function pageOverrideFields(entry, path) {
|
|
|
216
216
|
return entry.overrides?.[path] ?? {};
|
|
217
217
|
}
|
|
218
218
|
export function pageFields(entry, path) {
|
|
219
|
-
|
|
219
|
+
const fields = { ...entry.fields };
|
|
220
|
+
for (const [key, field] of Object.entries(pageOverrideFields(entry, path))) {
|
|
221
|
+
if (field) fields[key] = field;
|
|
222
|
+
else delete fields[key];
|
|
223
|
+
}
|
|
224
|
+
return fields;
|
|
220
225
|
}
|
|
221
226
|
export function pageAllFields(entry) {
|
|
222
227
|
const fields = { ...entry.fields };
|
|
223
228
|
for (const override of Object.values(entry.overrides ?? {})) {
|
|
224
229
|
for (const [key, field] of Object.entries(override)) {
|
|
225
|
-
if (!fields[key]) fields[key] = field;
|
|
230
|
+
if (field && !fields[key]) fields[key] = field;
|
|
226
231
|
}
|
|
227
232
|
}
|
|
228
233
|
return fields;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CmsEntry, CmsPageRoute } from './index.js';
|
|
2
|
+
export declare function routePathFromFile(file: string): string | null;
|
|
3
|
+
export declare function routePathsFromDir(pagesDir: string): string[];
|
|
4
|
+
export declare function resolvePageRoutes(entry: CmsEntry, discovered: string[]): CmsPageRoute[];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { pageKeyFromPath, pageLabelFromPath } from "./index.js";
|
|
4
|
+
const DYNAMIC = /[[\]]/;
|
|
5
|
+
function vueFiles(dir, prefix = "") {
|
|
6
|
+
if (!existsSync(dir)) return [];
|
|
7
|
+
const files = [];
|
|
8
|
+
for (const item of readdirSync(dir, { withFileTypes: true })) {
|
|
9
|
+
const name = `${prefix}${item.name}`;
|
|
10
|
+
if (item.isDirectory()) files.push(...vueFiles(join(dir, item.name), `${name}/`));
|
|
11
|
+
else if (item.name.endsWith(".vue")) files.push(name);
|
|
12
|
+
}
|
|
13
|
+
return files;
|
|
14
|
+
}
|
|
15
|
+
export function routePathFromFile(file) {
|
|
16
|
+
if (DYNAMIC.test(file)) return null;
|
|
17
|
+
const segments = file.replace(/\.vue$/, "").split("/").filter((segment) => !/^\(.+\)$/.test(segment));
|
|
18
|
+
if (segments.at(-1) === "index") segments.pop();
|
|
19
|
+
const path = `/${segments.join("/")}`.replace(/\/$/, "");
|
|
20
|
+
return path || "/";
|
|
21
|
+
}
|
|
22
|
+
export function routePathsFromDir(pagesDir) {
|
|
23
|
+
const paths = /* @__PURE__ */ new Set();
|
|
24
|
+
for (const file of vueFiles(pagesDir)) {
|
|
25
|
+
const path = routePathFromFile(file);
|
|
26
|
+
if (path) paths.add(path);
|
|
27
|
+
}
|
|
28
|
+
return [...paths];
|
|
29
|
+
}
|
|
30
|
+
export function resolvePageRoutes(entry, discovered) {
|
|
31
|
+
const declared = Array.isArray(entry.routes) ? entry.routes : discovered;
|
|
32
|
+
const paths = /* @__PURE__ */ new Set([...declared, ...entry.include ?? []]);
|
|
33
|
+
for (const path of entry.exclude ?? []) paths.delete(path);
|
|
34
|
+
const rank = new Map((entry.order ?? []).map((path, index) => [path, index]));
|
|
35
|
+
const order = entry.order?.length ?? 0;
|
|
36
|
+
return [...paths].sort((a, b) => (rank.get(a) ?? order) - (rank.get(b) ?? order) || a.localeCompare(b)).map((path) => ({
|
|
37
|
+
path,
|
|
38
|
+
key: pageKeyFromPath(path),
|
|
39
|
+
label: entry.labels?.[path] ?? pageLabelFromPath(path)
|
|
40
|
+
}));
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xleddyl/nuxt-cms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
4
4
|
"description": "Lightweight CMS that ships with your Nuxt app: runs on the Nitro server, content types defined in code, /cms admin panel, GraphQL API, SQLite or Postgres. No external CMS needed!",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Edoardo Alberti (https://github.com/xleddyl)",
|