nuxt-directus-sdk 5.0.1 → 6.0.0-beta.0
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 +6 -0
- package/dist/cli/index.mjs +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +31 -33
- package/dist/rules/index.mjs +2 -2
- package/dist/runtime/components/directus-edit-button.d.vue.ts +2 -2
- package/dist/runtime/components/directus-edit-button.vue.d.ts +2 -2
- package/dist/runtime/components/directus-visual-editor.d.vue.ts +2 -2
- package/dist/runtime/components/directus-visual-editor.vue.d.ts +2 -2
- package/dist/runtime/middleware/auth.d.ts +1 -1
- package/dist/runtime/middleware/guest.d.ts +1 -1
- package/dist/runtime/plugin.d.ts +1 -1
- package/dist/runtime/plugins/visual-editor.client.d.ts +2 -2
- package/dist/runtime/types/extensions/index.d.ts +15 -0
- package/dist/runtime/types/extensions/index.js +15 -0
- package/dist/runtime/types/extensions/seo-plugin.d.ts +2 -0
- package/dist/runtime/types/extensions/seo-plugin.js +24 -0
- package/dist/runtime/types/generate.d.ts +32 -4
- package/dist/runtime/types/generate.js +420 -36
- package/dist/runtime/types/index.d.ts +1 -1
- package/dist/runtime/types/index.js +1 -1
- package/dist/shared/{nuxt-directus-sdk.VgzMwq7f.mjs → nuxt-directus-sdk.1qEbZAZ_.mjs} +1 -1
- package/package.json +27 -26
package/README.md
CHANGED
|
@@ -70,10 +70,16 @@ For cross-domain setups (e.g., `app.example.com` ↔ `api.example.com`), see the
|
|
|
70
70
|
|
|
71
71
|
## Development
|
|
72
72
|
|
|
73
|
+
> [!IMPORTANT] The playground uses [directus-template-cli](https://github.com/directus-labs/directus-template-cli?tab=readme-ov-file#applying-a-template) `cms` template.
|
|
74
|
+
> Apply the template with `npx directus-template-cli@latest apply` and follow the interactive prompts.
|
|
75
|
+
|
|
73
76
|
```bash
|
|
74
77
|
# Install dependencies
|
|
75
78
|
bun install
|
|
76
79
|
|
|
80
|
+
# Add DIRECTUS_ADMIN_TOKEN to playground .env (don't forget to update your token)
|
|
81
|
+
cp ./playground/.env.example ./playground/.env
|
|
82
|
+
|
|
77
83
|
# Generate type stubs
|
|
78
84
|
bun run dev:prepare
|
|
79
85
|
|
package/dist/cli/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { parseArgs } from 'node:util';
|
|
5
5
|
import { createDirectus, staticToken, rest } from '@directus/sdk';
|
|
6
|
-
import {
|
|
6
|
+
import { d as diffRemoteRules, e as formatDiff, c as compareRulesPayloads, f as fetchRemoteRules, k as loadRulesFromPayload, o as pushRules, g as formatPushResult, b as fetchRemoteRulesAsJson } from '../shared/nuxt-directus-sdk.1qEbZAZ_.mjs';
|
|
7
7
|
|
|
8
8
|
function loadEnv() {
|
|
9
9
|
const envPath = resolve(process.cwd(), ".env");
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { useLogger, defineNuxtModule, createResolver, addServerHandler, hasNuxtModule, tryResolveModule, addPlugin, addRouteMiddleware, addImportsDir,
|
|
1
|
+
import { useLogger, defineNuxtModule, createResolver, addServerHandler, hasNuxtModule, tryResolveModule, addPlugin, addComponentsDir, addRouteMiddleware, addImportsDir, addImportsSources, addTypeTemplate, installModule } from '@nuxt/kit';
|
|
2
2
|
import { colors } from 'consola/utils';
|
|
3
3
|
import { defu } from 'defu';
|
|
4
4
|
import { joinURL } from 'ufo';
|
|
5
|
-
import {
|
|
5
|
+
import { generateTypesFromDirectus } from '../dist/runtime/types/index.js';
|
|
6
6
|
import { useUrl } from '../dist/runtime/utils/index.js';
|
|
7
7
|
|
|
8
8
|
const name = "nuxt-directus-sdk";
|
|
9
|
-
const version = "
|
|
9
|
+
const version = "6.0.0-beta.0";
|
|
10
10
|
|
|
11
11
|
const configKey = "directus";
|
|
12
12
|
const logger = useLogger("nuxt-directus-sdk");
|
|
@@ -59,17 +59,17 @@ const module$1 = defineNuxtModule({
|
|
|
59
59
|
nuxtApp.options[key] = defu(nuxtApp.options[key], moduleOptions);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
const loggerMessage = [];
|
|
62
63
|
const devProxyConfig = typeof options.devProxy === "boolean" ? { enabled: options.devProxy } : { ...options.devProxy };
|
|
63
64
|
const directusUrl = serverUrl || clientUrl;
|
|
64
65
|
const devProxyEnabled = devProxyConfig.enabled ?? nuxtApp.options.dev;
|
|
65
66
|
const devProxyPath = devProxyConfig.path ?? "/directus";
|
|
66
67
|
const wsProxyPath = devProxyConfig.wsPath ?? `${devProxyPath}-ws`;
|
|
67
68
|
const wsTarget = joinURL(directusUrl, "websocket");
|
|
68
|
-
const loggerMessage = [];
|
|
69
69
|
if (devProxyEnabled && nuxtApp.options.dev) {
|
|
70
|
-
loggerMessage.push(`\u{1F310} Development
|
|
71
|
-
loggerMessage.push(`URL${colors.dim(` ${devProxyPath}`)} proxies ${colors.underline(colors.green(`${directusUrl}`))}`);
|
|
72
|
-
loggerMessage.push(`WS URL${colors.dim(` ${wsProxyPath}`)} proxies ${colors.underline(colors.green(`${wsTarget}`))}
|
|
70
|
+
loggerMessage.push(`\u{1F310} Development Proxy Mode Enabled:`);
|
|
71
|
+
loggerMessage.push(` - URL${colors.dim(` ${devProxyPath}`)} proxies ${colors.underline(colors.green(`${directusUrl}`))}`);
|
|
72
|
+
loggerMessage.push(` - WS URL${colors.dim(` ${wsProxyPath}`)} proxies ${colors.underline(colors.green(`${wsTarget}`))}`, "");
|
|
73
73
|
nuxtApp.options.nitro = nuxtApp.options.nitro || {};
|
|
74
74
|
nuxtApp.options.nitro.devProxy = nuxtApp.options.nitro.devProxy || {};
|
|
75
75
|
nuxtApp.options.nitro.devProxy[wsProxyPath] = {
|
|
@@ -128,7 +128,7 @@ const module$1 = defineNuxtModule({
|
|
|
128
128
|
wsPath: wsProxyPath
|
|
129
129
|
};
|
|
130
130
|
} else if (!nuxtApp.options.dev) {
|
|
131
|
-
loggerMessage.push(`\u{1F310} Production
|
|
131
|
+
loggerMessage.push(`\u{1F310} Production Mode:`, ` - SDK connects directly to ${colors.dim(`${directusUrl}`)}`, "");
|
|
132
132
|
options.devProxy = false;
|
|
133
133
|
}
|
|
134
134
|
options.directusUrl = clientUrl;
|
|
@@ -153,11 +153,22 @@ const module$1 = defineNuxtModule({
|
|
|
153
153
|
modifiers
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
|
+
loggerMessage.push("\u{1F4F7} Nuxt/Image default provider is set to Directus", "");
|
|
156
157
|
}
|
|
157
158
|
addPlugin(resolver.resolve("./runtime/plugin"));
|
|
158
159
|
const hasVisualEditing = options.visualEditor && await tryResolveModule("@directus/visual-editing", new URL(import.meta.url));
|
|
159
160
|
if (hasVisualEditing) {
|
|
160
161
|
addPlugin(resolver.resolve("./runtime/plugins/visual-editor.client"));
|
|
162
|
+
addComponentsDir({
|
|
163
|
+
path: resolver.resolve("./runtime/components"),
|
|
164
|
+
pathPrefix: false,
|
|
165
|
+
prefix: "",
|
|
166
|
+
global: true
|
|
167
|
+
});
|
|
168
|
+
loggerMessage.push("\u{1F4DD} Visual Editor Components Added", "");
|
|
169
|
+
}
|
|
170
|
+
if (options.auth?.enableGlobalAuthMiddleware) {
|
|
171
|
+
loggerMessage.push("\u{1F512} Auth middleware installed globally.", "");
|
|
161
172
|
}
|
|
162
173
|
addRouteMiddleware({
|
|
163
174
|
name: "auth",
|
|
@@ -169,14 +180,6 @@ const module$1 = defineNuxtModule({
|
|
|
169
180
|
path: resolver.resolve("./runtime/middleware/guest")
|
|
170
181
|
});
|
|
171
182
|
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
172
|
-
if (hasVisualEditing) {
|
|
173
|
-
addComponentsDir({
|
|
174
|
-
path: resolver.resolve("./runtime/components"),
|
|
175
|
-
pathPrefix: false,
|
|
176
|
-
prefix: "",
|
|
177
|
-
global: true
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
183
|
const directusSdkImports = {
|
|
181
184
|
from: "@directus/sdk",
|
|
182
185
|
imports: [
|
|
@@ -251,9 +254,8 @@ const module$1 = defineNuxtModule({
|
|
|
251
254
|
]
|
|
252
255
|
});
|
|
253
256
|
});
|
|
254
|
-
loggerMessage.push(``);
|
|
255
257
|
if (options.devtools) {
|
|
256
|
-
loggerMessage.push(
|
|
258
|
+
loggerMessage.push(`\u{1F4E6} Directus added to Nuxt DevTools`, "");
|
|
257
259
|
nuxtApp.hook("devtools:customTabs", (iframeTabs) => {
|
|
258
260
|
iframeTabs.push({
|
|
259
261
|
name: "directus",
|
|
@@ -265,33 +267,29 @@ const module$1 = defineNuxtModule({
|
|
|
265
267
|
}
|
|
266
268
|
});
|
|
267
269
|
});
|
|
268
|
-
} else {
|
|
269
|
-
loggerMessage.push(`${colors.dim(` Directus Admin was not added to Nuxt DevTools`)}`);
|
|
270
270
|
}
|
|
271
271
|
const typesEnabled = typeof options.types === "boolean" && options.types || options.types && options.types.enabled === true;
|
|
272
272
|
const typesPrefix = typeof options.types === "object" ? options.types.prefix ?? "" : "";
|
|
273
273
|
if (typesEnabled) {
|
|
274
|
+
loggerMessage.push("\u{1F4CB} Directus Type Generator Enabled");
|
|
274
275
|
if (!options.adminToken) {
|
|
275
|
-
loggerMessage.push(
|
|
276
|
+
loggerMessage.push(` ${colors.bgRedBright(`${colors.red("\u2691 ERROR:")} Unable to generate Types`)}`, ` Fix: Set adminToken in config or DIRECTUS_ADMIN_TOKEN in .env`);
|
|
276
277
|
} else {
|
|
277
278
|
try {
|
|
278
|
-
|
|
279
|
+
const { typeString, logs } = await generateTypesFromDirectus(directusUrl, options.adminToken, typesPrefix);
|
|
280
|
+
loggerMessage.push(...logs);
|
|
279
281
|
addTypeTemplate({
|
|
280
282
|
filename: `types/${configKey}.d.ts`,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
cachedTypes = await generateTypes({
|
|
284
|
-
url: directusUrl,
|
|
285
|
-
token: options.adminToken,
|
|
286
|
-
prefix: typesPrefix
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
return cachedTypes;
|
|
283
|
+
getContents() {
|
|
284
|
+
return typeString;
|
|
290
285
|
}
|
|
291
286
|
}, { nitro: true, nuxt: true });
|
|
292
|
-
|
|
287
|
+
if (logs.some((log) => log.toLowerCase().includes("error"))) {
|
|
288
|
+
throw new Error(` ${colors.bgRedBright(`${colors.red("\u2691 ERROR:")} TypeGenerator returned an error`)}`);
|
|
289
|
+
}
|
|
290
|
+
loggerMessage.push(` - Directus Types saved successfully to ${colors.dim(`#build/types/${configKey}.d.ts`)}`);
|
|
293
291
|
} catch (error) {
|
|
294
|
-
|
|
292
|
+
loggerMessage.push(`${error instanceof Error ? error.message : String(error)}`, ` - Fallback DirectusSchema is being used ${colors.dim("(not recommended)")}`);
|
|
295
293
|
}
|
|
296
294
|
}
|
|
297
295
|
}
|
package/dist/rules/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as isStandardSchema } from '../shared/nuxt-directus-sdk.
|
|
2
|
-
export {
|
|
1
|
+
import { i as isStandardSchema } from '../shared/nuxt-directus-sdk.1qEbZAZ_.mjs';
|
|
2
|
+
export { c as compareRulesPayloads, d as diffRemoteRules, a as diffRules, f as fetchRemoteRules, b as fetchRemoteRulesAsJson, e as formatDiff, g as formatPushResult, h as isValidationStandardSchema, l as loadRulesFromJson, j as loadRulesFromJsonFile, k as loadRulesFromPayload, m as loadRulesFromPayloadFile, n as normalizeRules, p as pullRules, o as pushRules, r as rulesToJson, s as serializeToDirectusApi, q as serializeToJson, t as toDirectusValidation } from '../shared/nuxt-directus-sdk.1qEbZAZ_.mjs';
|
|
3
3
|
import '@directus/sdk';
|
|
4
4
|
|
|
5
5
|
function isPolicyReference(input) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { PrimaryKey } from '@directus/types';
|
|
2
2
|
declare const __VLS_export: <T extends keyof DirectusSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
3
|
-
props: __VLS_PrettifyLocal<{
|
|
3
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
4
4
|
collection: T;
|
|
5
5
|
item: PrimaryKey;
|
|
6
6
|
mode?: "drawer" | "modal" | "popover";
|
|
7
|
-
}> &
|
|
7
|
+
}> & (typeof globalThis extends {
|
|
8
8
|
__VLS_PROPS_FALLBACK: infer P;
|
|
9
9
|
} ? P : {});
|
|
10
10
|
expose: (exposed: {}) => void;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { PrimaryKey } from '@directus/types';
|
|
2
2
|
declare const __VLS_export: <T extends keyof DirectusSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
3
|
-
props: __VLS_PrettifyLocal<{
|
|
3
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
4
4
|
collection: T;
|
|
5
5
|
item: PrimaryKey;
|
|
6
6
|
mode?: "drawer" | "modal" | "popover";
|
|
7
|
-
}> &
|
|
7
|
+
}> & (typeof globalThis extends {
|
|
8
8
|
__VLS_PROPS_FALLBACK: infer P;
|
|
9
9
|
} ? P : {});
|
|
10
10
|
expose: (exposed: {}) => void;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { PrimaryKey } from '@directus/types';
|
|
2
2
|
declare const __VLS_export: <T extends keyof DirectusSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
3
|
-
props: __VLS_PrettifyLocal<{
|
|
3
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
4
4
|
collection: T;
|
|
5
5
|
item: PrimaryKey;
|
|
6
6
|
fields?: (string | number | symbol) | (string | number | symbol)[];
|
|
7
7
|
mode?: "drawer" | "modal" | "popover";
|
|
8
|
-
}> &
|
|
8
|
+
}> & (typeof globalThis extends {
|
|
9
9
|
__VLS_PROPS_FALLBACK: infer P;
|
|
10
10
|
} ? P : {});
|
|
11
11
|
expose: (exposed: {}) => void;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { PrimaryKey } from '@directus/types';
|
|
2
2
|
declare const __VLS_export: <T extends keyof DirectusSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
3
|
-
props: __VLS_PrettifyLocal<{
|
|
3
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
4
4
|
collection: T;
|
|
5
5
|
item: PrimaryKey;
|
|
6
6
|
fields?: (string | number | symbol) | (string | number | symbol)[];
|
|
7
7
|
mode?: "drawer" | "modal" | "popover";
|
|
8
|
-
}> &
|
|
8
|
+
}> & (typeof globalThis extends {
|
|
9
9
|
__VLS_PROPS_FALLBACK: infer P;
|
|
10
10
|
} ? P : {});
|
|
11
11
|
expose: (exposed: {}) => void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("nuxt/app").RouteMiddleware;
|
|
2
2
|
export default _default;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("nuxt/app").RouteMiddleware;
|
|
2
2
|
export default _default;
|
package/dist/runtime/plugin.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
|
|
2
2
|
export default _default;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("nuxt/app").Plugin<{
|
|
2
2
|
directusVisualEditing: {
|
|
3
3
|
refresh: () => Promise<void>;
|
|
4
4
|
};
|
|
5
|
-
}> & import("
|
|
5
|
+
}> & import("nuxt/app").ObjectPlugin<{
|
|
6
6
|
directusVisualEditing: {
|
|
7
7
|
refresh: () => Promise<void>;
|
|
8
8
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SnapshotField } from '@directus/types';
|
|
2
|
+
export interface TypegenExtension {
|
|
3
|
+
name: (prefix?: string) => string;
|
|
4
|
+
isMatch: (field: SnapshotField) => boolean;
|
|
5
|
+
output: (prefix: string | undefined) => string;
|
|
6
|
+
}
|
|
7
|
+
export declare const typegenExtensions: TypegenExtension[];
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the first matching extension or false if no extension matches
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveTypegenExtension(field: SnapshotField, prefix?: unknown): {
|
|
13
|
+
name: string;
|
|
14
|
+
output: string;
|
|
15
|
+
} | false;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { extension as seoPlugin } from "./seo-plugin.js";
|
|
2
|
+
export const typegenExtensions = [
|
|
3
|
+
seoPlugin
|
|
4
|
+
];
|
|
5
|
+
export function resolveTypegenExtension(field, prefix) {
|
|
6
|
+
const safePrefix = typeof prefix === "string" ? prefix : "";
|
|
7
|
+
const match = typegenExtensions.find((ext) => ext.isMatch(field));
|
|
8
|
+
if (!match) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
name: match.name(safePrefix),
|
|
13
|
+
output: match.output(safePrefix)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const interfaceName = "DirectusLabsSeoPlugin";
|
|
2
|
+
export const extension = {
|
|
3
|
+
name(prefix) {
|
|
4
|
+
return `${prefix}${interfaceName}`;
|
|
5
|
+
},
|
|
6
|
+
isMatch(field) {
|
|
7
|
+
return field.type === "json" && field.meta?.interface === "seo-interface" && field.meta?.special?.includes("cast-json") === true;
|
|
8
|
+
},
|
|
9
|
+
output(prefix) {
|
|
10
|
+
return `
|
|
11
|
+
interface ${prefix}${interfaceName} {
|
|
12
|
+
title?: string;
|
|
13
|
+
meta_description?: string;
|
|
14
|
+
og_image?: string;
|
|
15
|
+
additional_fields?: Record<string, unknown>;
|
|
16
|
+
sitemap?: {
|
|
17
|
+
change_frequency: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
18
|
+
priority: string;
|
|
19
|
+
};
|
|
20
|
+
no_index?: boolean;
|
|
21
|
+
no_follow?: boolean;
|
|
22
|
+
}`;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SnapshotCollection, SnapshotField, SnapshotRelation } from '@directus/types';
|
|
2
|
+
import type { TypegenExtension } from './extensions/index.js';
|
|
3
|
+
export declare const FALLBACK_TYPE_STRING = "declare global {\n\ninterface DirectusFile {\n\tid: string;\n}\ninterface DirectusUser {\n\tid: string;\n}\ninterface DirectusSchema { }\n}\n\nexport {};";
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
+
* Fetches collections, fields, and relations from a live Directus instance and
|
|
6
|
+
* generates a TypeScript declaration string.
|
|
7
|
+
*
|
|
8
|
+
* @param url - Base URL of the Directus instance.
|
|
9
|
+
* @param token - Static access token for authentication.
|
|
10
|
+
* @param prefix - Prefix used when generating interface names.
|
|
11
|
+
* @returns The generated TypeScript string and an array of log messages.
|
|
5
12
|
*/
|
|
6
|
-
export declare function
|
|
13
|
+
export declare function generateTypesFromDirectus(url: string, token: string, prefix: string): Promise<{
|
|
14
|
+
typeString: string;
|
|
15
|
+
logs: string[];
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Transforms Directus collections, fields, and relations into a TypeScript declaration string.
|
|
19
|
+
*
|
|
20
|
+
* - Builds a relation map from relations.
|
|
21
|
+
* - Separates custom and system collections and infers missing system ones.
|
|
22
|
+
* - Tracks singleton collections.
|
|
23
|
+
* - Generates collection interfaces and deduplicated extension outputs.
|
|
24
|
+
* - Generates `DirectusSchema` and `CollectionNames` enum.
|
|
25
|
+
* - Wraps everything in a `declare global` block.
|
|
26
|
+
*
|
|
27
|
+
* @param collections - Collection definitions from the Directus snapshot.
|
|
28
|
+
* @param fields - Field definitions from the Directus snapshot.
|
|
29
|
+
* @param relations - Relation definitions from the Directus snapshot.
|
|
30
|
+
* @param prefix - Prefix used for generating interface names.
|
|
31
|
+
* @param extensions - Optional type generation extensions.
|
|
32
|
+
* @returns A TypeScript declaration file as a string.
|
|
33
|
+
*/
|
|
34
|
+
export declare function transformSnapshotToTypeString(collections: SnapshotCollection[], fields: SnapshotField[], relations: SnapshotRelation[], prefix: string, extensions?: TypegenExtension[]): string;
|
|
@@ -1,44 +1,428 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { createDirectus, isDirectusError, readCollections, readFields, readRelations, rest, staticToken } from "@directus/sdk";
|
|
2
|
+
import { typegenExtensions } from "./extensions/index.js";
|
|
3
|
+
export const FALLBACK_TYPE_STRING = "declare global {\n\ninterface DirectusFile {\n id: string;\n}\ninterface DirectusUser {\n id: string;\n}\ninterface DirectusSchema { }\n}\n\nexport {};";
|
|
4
|
+
export async function generateTypesFromDirectus(url, token, prefix) {
|
|
5
|
+
const logs = [];
|
|
6
|
+
const client = createDirectus(url).with(rest()).with(staticToken(token));
|
|
7
|
+
let result = null;
|
|
8
|
+
try {
|
|
9
|
+
const [collections, fields, relations] = await Promise.all([
|
|
10
|
+
client.request(readCollections()),
|
|
11
|
+
client.request(readFields()),
|
|
12
|
+
client.request(readRelations())
|
|
13
|
+
]);
|
|
14
|
+
logs.push(` - Fetched ${collections.length} collections, ${fields.length} fields, ${relations.length} relations`);
|
|
15
|
+
if (collections.length === 0 || fields.length === 0 || relations.length === 0) {
|
|
16
|
+
throw new Error(`Empty response from Directus \u2014 collections: ${collections.length}, fields: ${fields.length}, relations: ${relations.length}`);
|
|
17
|
+
}
|
|
18
|
+
result = [
|
|
19
|
+
collections,
|
|
20
|
+
fields,
|
|
21
|
+
relations
|
|
22
|
+
];
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (isDirectusError(error)) {
|
|
25
|
+
logs.push(` - Directus error ${error.errors.map((e) => `[${e.extensions?.code}] ${e.message}`).join(", ")}`);
|
|
26
|
+
} else {
|
|
27
|
+
logs.push(` - Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
28
|
+
}
|
|
29
|
+
return { typeString: FALLBACK_TYPE_STRING, logs };
|
|
30
|
+
}
|
|
31
|
+
const typeString = transformSnapshotToTypeString(...result, prefix);
|
|
32
|
+
return { typeString, logs };
|
|
33
|
+
}
|
|
34
|
+
export function transformSnapshotToTypeString(collections, fields, relations, prefix, extensions = typegenExtensions) {
|
|
35
|
+
const relationMap = buildRelationMapFromSnapshot(relations);
|
|
36
|
+
const collectionsWithDatabaseTables = collections.filter(
|
|
37
|
+
(c) => c.schema !== null
|
|
38
|
+
);
|
|
39
|
+
const customCollections = collectionsWithDatabaseTables.filter(
|
|
40
|
+
(c) => !collectionIsDirectusSystem(c.collection)
|
|
41
|
+
);
|
|
42
|
+
const systemCollectionsFromSnapshot = collectionsWithDatabaseTables.filter(
|
|
43
|
+
(c) => collectionIsDirectusSystem(c.collection)
|
|
44
|
+
);
|
|
45
|
+
const systemCollectionNamesAlreadyPresent = new Set(
|
|
46
|
+
systemCollectionsFromSnapshot.map((c) => c.collection)
|
|
47
|
+
);
|
|
48
|
+
const impliedSystemCollections = [
|
|
49
|
+
...new Set(
|
|
50
|
+
relations.flatMap((r) => [r.collection, r.related_collection ?? ""]).filter(
|
|
51
|
+
(name) => collectionIsDirectusSystem(name) && !systemCollectionNamesAlreadyPresent.has(name)
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
].map((name) => ({ collection: name, schema: { name }, meta: null }));
|
|
55
|
+
const allCollectionsForSchema = [
|
|
56
|
+
...collectionsWithDatabaseTables,
|
|
57
|
+
...impliedSystemCollections
|
|
58
|
+
];
|
|
59
|
+
const singletonCollectionNames = new Set(
|
|
60
|
+
allCollectionsForSchema.filter((c) => c.meta?.singleton === true).map((c) => c.collection)
|
|
61
|
+
);
|
|
62
|
+
const generatedCollections = [
|
|
63
|
+
...customCollections,
|
|
64
|
+
...systemCollectionsFromSnapshot
|
|
65
|
+
].map(
|
|
66
|
+
(collection) => generateInterfaceForCollection(collection, fields, relationMap, prefix, extensions, singletonCollectionNames)
|
|
67
|
+
);
|
|
68
|
+
const seenExtensionOutputs = /* @__PURE__ */ new Set();
|
|
69
|
+
const uniqueExtensionOutputs = generatedCollections.flatMap((g) => g.extensionOutputs).filter((output) => {
|
|
70
|
+
if (seenExtensionOutputs.has(output))
|
|
71
|
+
return false;
|
|
72
|
+
seenExtensionOutputs.add(output);
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
const customInterfaceBlocks = generatedCollections.map((g) => g.interfaceBlock);
|
|
76
|
+
const directusSchemaBlock = generateDirectusSchemaInterface(allCollectionsForSchema, prefix, singletonCollectionNames);
|
|
77
|
+
const allCollectionNames = allCollectionsForSchema.map((c) => c.collection);
|
|
78
|
+
const enumBlock = generateCollectionNamesEnum(allCollectionNames, prefix);
|
|
79
|
+
const bodyParts = [
|
|
80
|
+
...uniqueExtensionOutputs,
|
|
81
|
+
...customInterfaceBlocks,
|
|
82
|
+
directusSchemaBlock,
|
|
83
|
+
enumBlock
|
|
84
|
+
];
|
|
85
|
+
return [
|
|
86
|
+
"declare global {",
|
|
87
|
+
"",
|
|
88
|
+
bodyParts.join("\n\n"),
|
|
89
|
+
"}",
|
|
90
|
+
"",
|
|
91
|
+
"export {};"
|
|
92
|
+
].join("\n");
|
|
93
|
+
}
|
|
94
|
+
function collectionIsDirectusSystem(collectionName) {
|
|
95
|
+
return collectionName.startsWith("directus_");
|
|
96
|
+
}
|
|
97
|
+
function collectionNameToInterfaceName(collectionName, prefix, singletons = /* @__PURE__ */ new Set()) {
|
|
98
|
+
const isSingleton = singletons.has(collectionName);
|
|
99
|
+
const transform = (name) => pascalCase(isSingleton ? name : singularize(name));
|
|
100
|
+
if (collectionIsDirectusSystem(collectionName)) {
|
|
101
|
+
return transform(collectionName);
|
|
102
|
+
}
|
|
103
|
+
return `${prefix}${transform(collectionName)}`;
|
|
104
|
+
}
|
|
105
|
+
function resolveExtensionForField(field, prefix, extensions) {
|
|
106
|
+
const match = extensions.find((ext) => ext.isMatch(field));
|
|
107
|
+
if (!match)
|
|
108
|
+
return null;
|
|
109
|
+
return {
|
|
110
|
+
name: match.name(prefix),
|
|
111
|
+
output: match.output(prefix)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function buildRelationMapFromSnapshot(relations) {
|
|
115
|
+
const relationMap = /* @__PURE__ */ new Map();
|
|
116
|
+
const getOrCreateCollectionRelations = (collection) => {
|
|
117
|
+
if (!relationMap.has(collection)) {
|
|
118
|
+
relationMap.set(collection, { m2o: /* @__PURE__ */ new Map(), o2m: /* @__PURE__ */ new Map(), m2a: /* @__PURE__ */ new Map() });
|
|
119
|
+
}
|
|
120
|
+
return relationMap.get(collection);
|
|
121
|
+
};
|
|
122
|
+
for (const relation of relations) {
|
|
123
|
+
const { collection, field, related_collection, meta } = relation;
|
|
124
|
+
if (!meta)
|
|
125
|
+
continue;
|
|
126
|
+
const isM2A = meta.one_allowed_collections && meta.one_allowed_collections.length > 0;
|
|
127
|
+
if (isM2A) {
|
|
128
|
+
getOrCreateCollectionRelations(collection).m2a.set(field, meta.one_allowed_collections);
|
|
129
|
+
} else if (related_collection) {
|
|
130
|
+
getOrCreateCollectionRelations(collection).m2o.set(field, { relatedCollection: related_collection });
|
|
131
|
+
if (meta.one_field) {
|
|
132
|
+
getOrCreateCollectionRelations(related_collection).o2m.set(meta.one_field, { relatedCollection: collection });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return relationMap;
|
|
137
|
+
}
|
|
138
|
+
function resolveFieldTypeString(snapshotField, collectionRelations, prefix, extensions, singletons = /* @__PURE__ */ new Set()) {
|
|
139
|
+
if (collectionRelations?.m2a.has(snapshotField.field)) {
|
|
140
|
+
const allowedCollections = collectionRelations.m2a.get(snapshotField.field);
|
|
141
|
+
const unionTypes = allowedCollections.map((c) => collectionNameToInterfaceName(c, prefix, singletons)).join(" | ");
|
|
142
|
+
return { tsType: `${unionTypes} | string`, extensionOutput: null };
|
|
143
|
+
}
|
|
144
|
+
if (collectionRelations?.m2o.has(snapshotField.field)) {
|
|
145
|
+
const related = collectionRelations.m2o.get(snapshotField.field);
|
|
146
|
+
return { tsType: `${collectionNameToInterfaceName(related.relatedCollection, prefix, singletons)} | string`, extensionOutput: null };
|
|
147
|
+
}
|
|
148
|
+
if (collectionRelations?.o2m.has(snapshotField.field)) {
|
|
149
|
+
const related = collectionRelations.o2m.get(snapshotField.field);
|
|
150
|
+
return { tsType: `${collectionNameToInterfaceName(related.relatedCollection, prefix, singletons)}[] | string[]`, extensionOutput: null };
|
|
151
|
+
}
|
|
152
|
+
const extensionMatch = resolveExtensionForField(snapshotField, prefix, extensions);
|
|
153
|
+
if (extensionMatch) {
|
|
154
|
+
return { tsType: extensionMatch.name, extensionOutput: extensionMatch.output };
|
|
155
|
+
}
|
|
156
|
+
return { tsType: determineFieldType(snapshotField), extensionOutput: null };
|
|
157
|
+
}
|
|
158
|
+
const ALIAS_SPECIAL_TYPES = /* @__PURE__ */ new Set(["alias", "no-data", "group"]);
|
|
159
|
+
function fieldIsUiOnlyAlias(field) {
|
|
160
|
+
const special = field.meta?.special ?? [];
|
|
161
|
+
return field.type === "alias" && special.some((s) => ALIAS_SPECIAL_TYPES.has(s)) && !special.includes("o2m") && !special.includes("m2o") && !special.includes("m2a") && !special.includes("files") && !special.includes("file");
|
|
162
|
+
}
|
|
163
|
+
function buildInterfaceField(snapshotField, collectionRelations, prefix, extensions, singletons = /* @__PURE__ */ new Set()) {
|
|
164
|
+
if (fieldIsUiOnlyAlias(snapshotField))
|
|
165
|
+
return null;
|
|
166
|
+
const isPrimaryKey = snapshotField.schema?.is_primary_key === true;
|
|
167
|
+
const isRequired = snapshotField.meta?.required === true;
|
|
168
|
+
const isNullable = snapshotField.schema?.is_nullable !== false;
|
|
169
|
+
const { tsType, extensionOutput } = resolveFieldTypeString(snapshotField, collectionRelations, prefix, extensions, singletons);
|
|
170
|
+
const shouldAppendNull = isNullable && !isRequired && !isPrimaryKey;
|
|
171
|
+
const finalType = shouldAppendNull ? `${tsType} | null` : tsType;
|
|
172
|
+
return {
|
|
173
|
+
interfaceField: {
|
|
174
|
+
fieldName: snapshotField.field,
|
|
175
|
+
typeString: finalType,
|
|
176
|
+
isOptional: !isPrimaryKey && !isRequired,
|
|
177
|
+
snapshotField,
|
|
178
|
+
sortOrder: snapshotField.meta?.sort ?? 9999
|
|
179
|
+
},
|
|
180
|
+
extensionOutput
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function generateInterfaceForCollection(collection, allFields, relationMap, prefix, extensions, singletons = /* @__PURE__ */ new Set()) {
|
|
184
|
+
const collectionName = collection.collection;
|
|
185
|
+
const interfaceName = collectionNameToInterfaceName(collectionName, prefix, singletons);
|
|
186
|
+
const collectionRelations = relationMap.get(collectionName);
|
|
187
|
+
const builtFields = allFields.filter((f) => f.collection === collectionName).map((f) => buildInterfaceField(f, collectionRelations, prefix, extensions, singletons)).filter((f) => f !== null).sort((a, b) => a.interfaceField.sortOrder - b.interfaceField.sortOrder);
|
|
188
|
+
const extensionOutputs = builtFields.map((f) => f.extensionOutput).filter((o) => o !== null);
|
|
189
|
+
const fieldLines = builtFields.map(({ interfaceField }) => {
|
|
190
|
+
const jsDoc = generateJSDocComment(interfaceField.snapshotField);
|
|
191
|
+
const optionalMarker = interfaceField.isOptional ? "?" : "";
|
|
192
|
+
const declaration = ` ${interfaceField.fieldName}${optionalMarker}: ${interfaceField.typeString};`;
|
|
193
|
+
return jsDoc ? `${jsDoc} ${interfaceField.fieldName}${optionalMarker}: ${interfaceField.typeString};` : declaration;
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
interfaceBlock: `interface ${interfaceName} {
|
|
197
|
+
${fieldLines.join("\n")}
|
|
198
|
+
}`,
|
|
199
|
+
extensionOutputs
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function generateDirectusSchemaInterface(allCollections, prefix, singletons = /* @__PURE__ */ new Set()) {
|
|
203
|
+
const entries = allCollections.map((collection) => {
|
|
204
|
+
const isSingleton = collection.meta?.singleton === true;
|
|
205
|
+
const interfaceName = collectionNameToInterfaceName(collection.collection, prefix, singletons);
|
|
206
|
+
const valueType = isSingleton ? interfaceName : `${interfaceName}[]`;
|
|
207
|
+
return ` ${collection.collection}: ${valueType};`;
|
|
10
208
|
});
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
209
|
+
return `interface DirectusSchema {
|
|
210
|
+
${entries.join("\n")}
|
|
211
|
+
}`;
|
|
212
|
+
}
|
|
213
|
+
function generateCollectionNamesEnum(collectionNames, prefix) {
|
|
214
|
+
const entries = collectionNames.map((name) => ` ${name} = '${name}'`);
|
|
215
|
+
return `export enum ${prefix}CollectionNames {
|
|
216
|
+
${entries.join(",\n")}
|
|
217
|
+
}`;
|
|
218
|
+
}
|
|
219
|
+
function determineFieldType(field) {
|
|
220
|
+
if (field.meta?.special?.includes("translations")) {
|
|
221
|
+
const translationsCollection = field.relation?.collection;
|
|
222
|
+
if (translationsCollection) {
|
|
223
|
+
const translationType = pascalCase(singularize(translationsCollection));
|
|
224
|
+
return `${translationType}[] | null`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (field.relation?.collection) {
|
|
228
|
+
const relatedTypeName = pascalCase(singularize(field.relation.collection));
|
|
229
|
+
switch (field.relation.type) {
|
|
230
|
+
case "many":
|
|
231
|
+
return `${relatedTypeName}[] | string[]`;
|
|
232
|
+
case "m2a": {
|
|
233
|
+
const allowedCollections = field.relation.allowedCollections;
|
|
234
|
+
if (Array.isArray(allowedCollections) && allowedCollections.length > 0) {
|
|
235
|
+
const unionTypes = allowedCollections.map((collection) => pascalCase(singularize(collection))).join(" | ");
|
|
236
|
+
return `${unionTypes} | string`;
|
|
18
237
|
}
|
|
19
|
-
|
|
238
|
+
console.warn(
|
|
239
|
+
"[determineFieldType] m2a relation missing allowedCollections. Falling back to string."
|
|
240
|
+
);
|
|
241
|
+
return "string";
|
|
20
242
|
}
|
|
243
|
+
default:
|
|
244
|
+
return `${relatedTypeName} | string`;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const choices = field.meta?.options?.choices;
|
|
248
|
+
if (Array.isArray(choices) && choices.length > 0) {
|
|
249
|
+
const choiceValues = choices.map(
|
|
250
|
+
(choice) => choice.value === null ? "null" : escapeStringLiteral(choice.value)
|
|
21
251
|
);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
252
|
+
const unionOfChoices = [...new Set(choiceValues)].join(" | ");
|
|
253
|
+
const interfacesWithMultiSelect = ["select-multiple", "select-multiple-dropdown", "select-multiple-checkbox"];
|
|
254
|
+
if (interfacesWithMultiSelect.includes(field.meta.interface)) {
|
|
255
|
+
return `Array<${unionOfChoices}>`;
|
|
256
|
+
}
|
|
257
|
+
return unionOfChoices;
|
|
258
|
+
}
|
|
259
|
+
switch (field.type) {
|
|
260
|
+
case "boolean":
|
|
261
|
+
return "boolean";
|
|
262
|
+
case "json": {
|
|
263
|
+
const nestedFields = field.meta?.options?.fields;
|
|
264
|
+
if (Array.isArray(nestedFields) && nestedFields.length > 0) {
|
|
265
|
+
const nestedTypes = nestedFields.map((nestedField) => {
|
|
266
|
+
const propertyName = nestedField.field ?? nestedField.name;
|
|
267
|
+
const fieldType = determineFieldType(nestedField);
|
|
268
|
+
return `${propertyName}: ${fieldType}`;
|
|
269
|
+
});
|
|
270
|
+
return `Array<{ ${nestedTypes.join("; ")} }>`;
|
|
25
271
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
272
|
+
if (field.meta?.interface === "input-code") {
|
|
273
|
+
return "Record<string, unknown>";
|
|
274
|
+
}
|
|
275
|
+
if (field.meta?.interface === "tags") {
|
|
276
|
+
return "string[]";
|
|
277
|
+
}
|
|
278
|
+
return "'json'";
|
|
279
|
+
}
|
|
280
|
+
case "csv":
|
|
281
|
+
return "'csv'";
|
|
282
|
+
case "dateTime":
|
|
283
|
+
case "timestamp":
|
|
284
|
+
return "'datetime'";
|
|
285
|
+
case "date":
|
|
286
|
+
return "'date'";
|
|
287
|
+
case "time":
|
|
288
|
+
return "'time'";
|
|
289
|
+
case "integer":
|
|
290
|
+
case "bigInteger":
|
|
291
|
+
case "float":
|
|
292
|
+
case "decimal":
|
|
293
|
+
return "number";
|
|
294
|
+
default:
|
|
295
|
+
return "string";
|
|
36
296
|
}
|
|
37
|
-
const typesWithoutExport = processedTypes.replace(/export interface Schema/g, "interface DirectusSchema").replace(/^export interface /gm, "interface ");
|
|
38
|
-
return `declare global {
|
|
39
|
-
${typesWithoutExport}
|
|
40
297
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
298
|
+
function escapeStringLiteral(value) {
|
|
299
|
+
switch (typeof value) {
|
|
300
|
+
case "string": {
|
|
301
|
+
const backslashEscaped = value.replace(/\\/g, "\\\\");
|
|
302
|
+
if (/^\w+$/.test(backslashEscaped)) {
|
|
303
|
+
const singleQuoteEscaped = backslashEscaped.replace(/'/g, "\\'");
|
|
304
|
+
return `'${singleQuoteEscaped}'`;
|
|
305
|
+
}
|
|
306
|
+
const templateLiteralEscaped = backslashEscaped.replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
307
|
+
return `\`${templateLiteralEscaped}\``;
|
|
308
|
+
}
|
|
309
|
+
case "boolean":
|
|
310
|
+
case "number":
|
|
311
|
+
return String(value);
|
|
312
|
+
case "undefined":
|
|
313
|
+
return "null";
|
|
314
|
+
default:
|
|
315
|
+
if (value === void 0 || value === null) {
|
|
316
|
+
return "null";
|
|
317
|
+
}
|
|
318
|
+
return JSON.stringify(value);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function generateJSDocComment(field) {
|
|
322
|
+
const comments = [];
|
|
323
|
+
if (field.meta?.note && !field.meta.note.startsWith("$t")) {
|
|
324
|
+
comments.push(`@description ${field.meta.note}`);
|
|
325
|
+
}
|
|
326
|
+
if (field.schema?.is_primary_key) {
|
|
327
|
+
comments.push("@primaryKey");
|
|
328
|
+
}
|
|
329
|
+
if (field.meta?.required) {
|
|
330
|
+
comments.push("@required");
|
|
331
|
+
}
|
|
332
|
+
return comments.length > 0 ? ` /** ${comments.join(" ")} */
|
|
333
|
+
` : "";
|
|
334
|
+
}
|
|
335
|
+
function pascalCase(value) {
|
|
336
|
+
return value.split(/[\s_-]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
337
|
+
}
|
|
338
|
+
const singularizeExceptions = /* @__PURE__ */ new Map([
|
|
339
|
+
// invariant (same singular/plural)
|
|
340
|
+
["sheep", "sheep"],
|
|
341
|
+
["fish", "fish"],
|
|
342
|
+
["series", "series"],
|
|
343
|
+
["species", "species"],
|
|
344
|
+
["deer", "deer"],
|
|
345
|
+
["aircraft", "aircraft"],
|
|
346
|
+
["news", "news"],
|
|
347
|
+
// irregular
|
|
348
|
+
["children", "child"],
|
|
349
|
+
["men", "man"],
|
|
350
|
+
["women", "woman"],
|
|
351
|
+
["teeth", "tooth"],
|
|
352
|
+
["feet", "foot"],
|
|
353
|
+
["mice", "mouse"],
|
|
354
|
+
["geese", "goose"],
|
|
355
|
+
["oxen", "ox"],
|
|
356
|
+
// -ves special cases (fe endings)
|
|
357
|
+
["knives", "knife"],
|
|
358
|
+
["wives", "wife"],
|
|
359
|
+
["lives", "life"],
|
|
360
|
+
["leaves", "leaf"],
|
|
361
|
+
["loaves", "loaf"],
|
|
362
|
+
["wolves", "wolf"],
|
|
363
|
+
["calves", "calf"],
|
|
364
|
+
["halves", "half"],
|
|
365
|
+
["selves", "self"],
|
|
366
|
+
["elves", "elf"],
|
|
367
|
+
// Latin / Greek
|
|
368
|
+
["analyses", "analysis"],
|
|
369
|
+
["diagnoses", "diagnosis"],
|
|
370
|
+
["theses", "thesis"],
|
|
371
|
+
["crises", "crisis"],
|
|
372
|
+
["phenomena", "phenomenon"],
|
|
373
|
+
["criteria", "criterion"],
|
|
374
|
+
// -us -> -i
|
|
375
|
+
["cacti", "cactus"],
|
|
376
|
+
["fungi", "fungus"],
|
|
377
|
+
["nuclei", "nucleus"],
|
|
378
|
+
["syllabi", "syllabus"],
|
|
379
|
+
// -a -> -um
|
|
380
|
+
["bacteria", "bacterium"],
|
|
381
|
+
["curricula", "curriculum"],
|
|
382
|
+
// exceptions to oes -> o
|
|
383
|
+
["toes", "toe"]
|
|
384
|
+
]);
|
|
385
|
+
const singularizeRules = [
|
|
386
|
+
// ies -> y
|
|
387
|
+
(word) => {
|
|
388
|
+
if (word.endsWith("ies") && word.length > 3) {
|
|
389
|
+
return `${word.slice(0, -3)}y`;
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
},
|
|
393
|
+
// oes -> o
|
|
394
|
+
(word) => {
|
|
395
|
+
if (word.endsWith("oes")) {
|
|
396
|
+
return word.slice(0, -2);
|
|
397
|
+
}
|
|
398
|
+
return null;
|
|
399
|
+
},
|
|
400
|
+
// es -> remove (ch, sh, s, x, z)
|
|
401
|
+
(word) => {
|
|
402
|
+
if (/(?:ch|sh|[sxz])es$/.test(word)) {
|
|
403
|
+
return word.slice(0, -2);
|
|
404
|
+
}
|
|
405
|
+
return null;
|
|
406
|
+
},
|
|
407
|
+
// fallback: trailing s (guarded)
|
|
408
|
+
(word) => {
|
|
409
|
+
if (word.endsWith("s") && !word.endsWith("ss") && word.length > 3 && !word.endsWith("us") && !word.endsWith("is")) {
|
|
410
|
+
return word.slice(0, -1);
|
|
411
|
+
}
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
];
|
|
415
|
+
function singularize(word) {
|
|
416
|
+
if (!word || typeof word !== "string")
|
|
417
|
+
return "";
|
|
418
|
+
const lower = word.toLowerCase();
|
|
419
|
+
const exception = singularizeExceptions.get(lower);
|
|
420
|
+
if (exception)
|
|
421
|
+
return exception;
|
|
422
|
+
for (const rule of singularizeRules) {
|
|
423
|
+
const result = rule(lower);
|
|
424
|
+
if (result)
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
return word;
|
|
44
428
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { FALLBACK_TYPE_STRING, generateTypesFromDirectus } from './generate.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { FALLBACK_TYPE_STRING, generateTypesFromDirectus } from "./generate.js";
|
|
@@ -1413,4 +1413,4 @@ function formatPushResult(result) {
|
|
|
1413
1413
|
return lines.join("\n");
|
|
1414
1414
|
}
|
|
1415
1415
|
|
|
1416
|
-
export {
|
|
1416
|
+
export { diffRules as a, fetchRemoteRulesAsJson as b, compareRulesPayloads as c, diffRemoteRules as d, formatDiff as e, fetchRemoteRules as f, formatPushResult as g, isValidationStandardSchema as h, isStandardSchema as i, loadRulesFromJsonFile as j, loadRulesFromPayload as k, loadRulesFromJson as l, loadRulesFromPayloadFile as m, normalizeRules as n, pushRules as o, pullRules as p, serializeToJson as q, rulesToJson as r, serializeToDirectusApi as s, toDirectusValidation as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-directus-sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6.0.0-beta.0",
|
|
5
|
+
"packageManager": "pnpm@10.32.1",
|
|
5
6
|
"description": "A Directus nuxt module that uses the Directus SDK",
|
|
6
7
|
"author": "Matthew Rollinson <matt@rolley.io>",
|
|
7
8
|
"license": "MIT",
|
|
@@ -30,22 +31,23 @@
|
|
|
30
31
|
],
|
|
31
32
|
"scripts": {
|
|
32
33
|
"prepack": "nuxt-module-build build",
|
|
33
|
-
"dev": "
|
|
34
|
-
"dev:build": "
|
|
35
|
-
"dev:prepare": "nuxt-module-build --stub &&
|
|
36
|
-
"release": "
|
|
37
|
-
"release:next": "
|
|
38
|
-
"lint": "eslint .
|
|
34
|
+
"dev": "pnpm run dev:prepare && nuxt dev playground",
|
|
35
|
+
"dev:build": "nuxt build playground",
|
|
36
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt prepare playground",
|
|
37
|
+
"release": "pnpm run lint && pnpm run test && pnpm run prepack && changelogen --release --push --no-github",
|
|
38
|
+
"release:next": "pnpm run lint && pnpm run test && pnpm run prepack && changelogen --release --prerelease beta --push --no-github",
|
|
39
|
+
"lint": "eslint .",
|
|
40
|
+
"lint:fix": "eslint . --fix",
|
|
39
41
|
"test": "vitest run",
|
|
40
42
|
"test:watch": "vitest watch",
|
|
41
|
-
"docs:dev": "
|
|
42
|
-
"docs:build": "
|
|
43
|
+
"docs:dev": "pnpm run dev:prepare && vitepress dev docs",
|
|
44
|
+
"docs:build": "pnpm run dev:prepare && vitepress build docs",
|
|
43
45
|
"docs:preview": "vitepress preview docs"
|
|
44
46
|
},
|
|
45
47
|
"peerDependencies": {
|
|
46
|
-
"@directus/sdk": ">=
|
|
47
|
-
"@directus/types": ">=
|
|
48
|
-
"@directus/visual-editing": ">=
|
|
48
|
+
"@directus/sdk": ">=21.0.0",
|
|
49
|
+
"@directus/types": ">=15.0.0",
|
|
50
|
+
"@directus/visual-editing": ">=2.0.0",
|
|
49
51
|
"@nuxt/image": ">=2.0.0"
|
|
50
52
|
},
|
|
51
53
|
"peerDependenciesMeta": {
|
|
@@ -60,29 +62,28 @@
|
|
|
60
62
|
}
|
|
61
63
|
},
|
|
62
64
|
"dependencies": {
|
|
63
|
-
"@nuxt/kit": "^4.
|
|
64
|
-
"
|
|
65
|
-
"defu": "^6.1.1",
|
|
66
|
-
"directus-sdk-typegen": "^0.2.1",
|
|
65
|
+
"@nuxt/kit": "^4.4.2",
|
|
66
|
+
"defu": "^6.1.7",
|
|
67
67
|
"http-proxy": "^1.18.1",
|
|
68
|
-
"ufo": "^1.6.
|
|
68
|
+
"ufo": "^1.6.3"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@antfu/eslint-config": "^4.10.0",
|
|
72
|
-
"@directus/sdk": "^
|
|
73
|
-
"@directus/types": "^
|
|
74
|
-
"@directus/visual-editing": "^
|
|
75
|
-
"@nuxt/devtools": "
|
|
72
|
+
"@directus/sdk": "^21.2.2",
|
|
73
|
+
"@directus/types": "^15.0.2",
|
|
74
|
+
"@directus/visual-editing": "^2.0.0",
|
|
75
|
+
"@nuxt/devtools": "^3.2.4",
|
|
76
76
|
"@nuxt/image": "^2.0.0",
|
|
77
77
|
"@nuxt/module-builder": "^1.0.2",
|
|
78
|
-
"@nuxt/schema": "^4.
|
|
79
|
-
"@nuxt/test-utils": "^
|
|
78
|
+
"@nuxt/schema": "^4.4.2",
|
|
79
|
+
"@nuxt/test-utils": "^4.0.2",
|
|
80
80
|
"@types/http-proxy": "^1.17.17",
|
|
81
81
|
"changelogen": "^0.6.1",
|
|
82
82
|
"eslint": "^9.22.0",
|
|
83
|
-
"nuxt": "^4.
|
|
84
|
-
"
|
|
85
|
-
"
|
|
83
|
+
"nuxt": "^4.4.2",
|
|
84
|
+
"typescript": "^6.0.3",
|
|
85
|
+
"vitepress": "^1.6.4",
|
|
86
|
+
"vitest": "^4.1.4",
|
|
86
87
|
"vue-tsc": "^3.0.8"
|
|
87
88
|
},
|
|
88
89
|
"unbuild": {
|