vovk-cli 0.0.1-draft.333 → 0.0.1-draft.335
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/client-templates/readme/README.md.ejs +3 -2
- package/client-templates/schemaCjs/schema.cjs.ejs +1 -4
- package/client-templates/schemaTs/schema.ts.ejs +1 -5
- package/dist/bundle/index.mjs +10 -10
- package/dist/dev/ensureSchemaFiles.d.mts +1 -1
- package/dist/dev/index.d.mts +1 -1
- package/dist/dev/index.mjs +28 -19
- package/dist/dev/writeMetaJson.d.mts +1 -1
- package/dist/dev/writeMetaJson.mjs +5 -2
- package/dist/generate/generate.d.mts +2 -5
- package/dist/generate/generate.mjs +38 -40
- package/dist/generate/getClientTemplateFiles.mjs +1 -1
- package/dist/generate/getProjectFullSchema.d.mts +5 -2
- package/dist/generate/getProjectFullSchema.mjs +7 -7
- package/dist/generate/index.mjs +3 -1
- package/dist/generate/writeOneClientFile.d.mts +4 -3
- package/dist/generate/writeOneClientFile.mjs +11 -5
- package/dist/getProjectInfo/getConfig/getTemplateDefs.mjs +3 -3
- package/dist/getProjectInfo/getConfig/index.d.mts +9 -51
- package/dist/getProjectInfo/getConfig/index.mjs +18 -16
- package/dist/getProjectInfo/getMetaSchema.d.mts +10 -0
- package/dist/getProjectInfo/getMetaSchema.mjs +13 -0
- package/dist/getProjectInfo/index.d.mts +4 -2
- package/dist/getProjectInfo/index.mjs +5 -2
- package/dist/index.mjs +25 -6
- package/dist/init/createConfig.mjs +26 -4
- package/dist/init/createStandardSchemaValidatorFile.d.mts +4 -0
- package/dist/init/createStandardSchemaValidatorFile.mjs +38 -0
- package/dist/init/index.mjs +47 -21
- package/dist/init/updateNPMScripts.d.mts +0 -1
- package/dist/init/updateNPMScripts.mjs +1 -5
- package/dist/initProgram.mjs +1 -1
- package/dist/new/index.d.mts +2 -1
- package/dist/new/index.mjs +3 -2
- package/dist/new/newModule.d.mts +3 -1
- package/dist/new/newModule.mjs +2 -3
- package/dist/new/newSegment.d.mts +3 -1
- package/dist/new/newSegment.mjs +2 -3
- package/dist/types.d.mts +8 -3
- package/dist/utils/generateFnName.d.mts +23 -0
- package/dist/utils/generateFnName.mjs +76 -0
- package/dist/utils/normalizeOpenAPIMixin.d.mts +14 -0
- package/dist/utils/normalizeOpenAPIMixin.mjs +114 -0
- package/module-templates/arktype/controller.ts.ejs +68 -0
- package/module-templates/valibot/controller.ts.ejs +68 -0
- package/package.json +2 -2
- package/dist/generate/mergePackages.d.mts +0 -7
- package/dist/generate/mergePackages.mjs +0 -55
- package/dist/utils/normalizeOpenAPIMixins.d.mts +0 -7
- package/dist/utils/normalizeOpenAPIMixins.mjs +0 -67
- /package/module-templates/{controller.ts.ejs → type/controller.ts.ejs} +0 -0
- /package/module-templates/{service.ts.ejs → type/service.ts.ejs} +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { VovkSchemaIdEnum, type VovkStrictConfig } from 'vovk';
|
|
2
|
-
|
|
2
|
+
import type { LogLevelNames } from 'loglevel';
|
|
3
|
+
export default function getConfig({ configPath, cwd, logLevel, }: {
|
|
3
4
|
configPath?: string;
|
|
4
5
|
cwd: string;
|
|
6
|
+
logLevel?: LogLevelNames;
|
|
5
7
|
}): Promise<{
|
|
6
8
|
config: VovkStrictConfig;
|
|
7
9
|
srcRoot: string | null;
|
|
@@ -12,14 +14,13 @@ export default function getConfig({ configPath, cwd }: {
|
|
|
12
14
|
schemaOutDir?: string;
|
|
13
15
|
modulesDir?: string;
|
|
14
16
|
rootEntry?: string;
|
|
15
|
-
origin?: string;
|
|
16
17
|
logLevel?: "error" | "trace" | "debug" | "info" | "warn" | (string & {});
|
|
17
18
|
libs?: {
|
|
18
19
|
ajv: import("vovk").KnownAny;
|
|
19
20
|
[key: string]: import("vovk").KnownAny;
|
|
20
21
|
};
|
|
21
22
|
devHttps?: boolean;
|
|
22
|
-
composedClient?:
|
|
23
|
+
composedClient?: {
|
|
23
24
|
enabled?: boolean;
|
|
24
25
|
outDir?: string;
|
|
25
26
|
fromTemplates?: string[];
|
|
@@ -30,13 +31,8 @@ export default function getConfig({ configPath, cwd }: {
|
|
|
30
31
|
} | {
|
|
31
32
|
excludeSegments?: string[];
|
|
32
33
|
includeSegments?: never;
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
readme?: {
|
|
36
|
-
banner?: string;
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
segmentedClient?: ({
|
|
34
|
+
});
|
|
35
|
+
segmentedClient?: {
|
|
40
36
|
enabled?: boolean;
|
|
41
37
|
outDir?: string;
|
|
42
38
|
fromTemplates?: string[];
|
|
@@ -47,22 +43,11 @@ export default function getConfig({ configPath, cwd }: {
|
|
|
47
43
|
} | {
|
|
48
44
|
excludeSegments?: string[];
|
|
49
45
|
includeSegments?: never;
|
|
50
|
-
})
|
|
51
|
-
packages?: Record<string, import("type-fest").PackageJson>;
|
|
52
|
-
readmes?: Record<string, {
|
|
53
|
-
banner?: string;
|
|
54
|
-
}>;
|
|
55
|
-
};
|
|
46
|
+
});
|
|
56
47
|
bundle?: {
|
|
57
48
|
requires?: Record<string, string>;
|
|
58
49
|
prebundleOutDir?: string;
|
|
59
50
|
keepPrebundleDir?: boolean;
|
|
60
|
-
origin?: string;
|
|
61
|
-
package?: import("type-fest").PackageJson;
|
|
62
|
-
readme?: {
|
|
63
|
-
banner?: string;
|
|
64
|
-
};
|
|
65
|
-
reExports?: Record<string, string>;
|
|
66
51
|
tsdownBuildOptions?: Parameters<typeof import("tsdown/config-9hj-APNF.mjs").build>[0];
|
|
67
52
|
} & ({
|
|
68
53
|
excludeSegments?: never;
|
|
@@ -71,7 +56,7 @@ export default function getConfig({ configPath, cwd }: {
|
|
|
71
56
|
excludeSegments?: string[];
|
|
72
57
|
includeSegments?: never;
|
|
73
58
|
});
|
|
74
|
-
clientTemplateDefs?: Record<string, import("vovk/
|
|
59
|
+
clientTemplateDefs?: Record<string, import("vovk/types").ClientTemplateDef>;
|
|
75
60
|
imports?: {
|
|
76
61
|
fetcher?: string | [string, string] | [string];
|
|
77
62
|
validateOnClient?: string | [string, string] | [string];
|
|
@@ -83,34 +68,7 @@ export default function getConfig({ configPath, cwd }: {
|
|
|
83
68
|
controller?: string;
|
|
84
69
|
[key: string]: string | undefined;
|
|
85
70
|
};
|
|
86
|
-
|
|
87
|
-
[x: string]: {
|
|
88
|
-
origin?: string;
|
|
89
|
-
rootEntry?: string;
|
|
90
|
-
segmentNameOverride?: string;
|
|
91
|
-
reExports?: Record<string, string>;
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
openApiMixins?: {
|
|
95
|
-
[mixinName: string]: {
|
|
96
|
-
source: {
|
|
97
|
-
file: string;
|
|
98
|
-
} | {
|
|
99
|
-
url: string;
|
|
100
|
-
fallback?: string;
|
|
101
|
-
} | {
|
|
102
|
-
object: import("openapi3-ts/oas31").OpenAPIObject;
|
|
103
|
-
};
|
|
104
|
-
package?: import("type-fest").PackageJson;
|
|
105
|
-
readme?: {
|
|
106
|
-
banner?: string;
|
|
107
|
-
};
|
|
108
|
-
apiRoot?: string;
|
|
109
|
-
getModuleName?: "nestjs-operation-id" | (string & {}) | "api" | import("vovk/mjs/types").GetOpenAPINameFn;
|
|
110
|
-
getMethodName?: "nestjs-operation-id" | "camel-case-operation-id" | "auto" | import("vovk/mjs/types").GetOpenAPINameFn;
|
|
111
|
-
errorMessageKey?: string;
|
|
112
|
-
};
|
|
113
|
-
};
|
|
71
|
+
projectConfig?: import("vovk").VovkProjectConfig;
|
|
114
72
|
} | null;
|
|
115
73
|
log: {
|
|
116
74
|
info: (msg: string) => void;
|
|
@@ -4,14 +4,15 @@ import getLogger from '../../utils/getLogger.mjs';
|
|
|
4
4
|
import getUserConfig from './getUserConfig.mjs';
|
|
5
5
|
import getRelativeSrcRoot from './getRelativeSrcRoot.mjs';
|
|
6
6
|
import getTemplateDefs, { BuiltInTemplateName } from './getTemplateDefs.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import { normalizeOpenAPIMixin } from '../../utils/normalizeOpenAPIMixin.mjs';
|
|
8
8
|
import chalkHighlightThing from '../../utils/chalkHighlightThing.mjs';
|
|
9
|
-
export default async function getConfig({ configPath, cwd }) {
|
|
9
|
+
export default async function getConfig({ configPath, cwd, logLevel, }) {
|
|
10
10
|
const { configAbsolutePaths, error, userConfig } = await getUserConfig({
|
|
11
11
|
configPath,
|
|
12
12
|
cwd,
|
|
13
13
|
});
|
|
14
14
|
const conf = userConfig ?? {};
|
|
15
|
+
const log = getLogger(logLevel ?? conf.logLevel);
|
|
15
16
|
const env = process.env;
|
|
16
17
|
const clientTemplateDefs = getTemplateDefs(conf.clientTemplateDefs);
|
|
17
18
|
const srcRoot = await getRelativeSrcRoot({ cwd });
|
|
@@ -51,9 +52,6 @@ export default async function getConfig({ configPath, cwd }) {
|
|
|
51
52
|
[BuiltInTemplateName.readme]: '.',
|
|
52
53
|
[BuiltInTemplateName.packageJson]: '.',
|
|
53
54
|
},
|
|
54
|
-
package: {},
|
|
55
|
-
readme: {},
|
|
56
|
-
reExports: {},
|
|
57
55
|
...conf.bundle,
|
|
58
56
|
tsdownBuildOptions: {
|
|
59
57
|
outDir: conf.bundle?.tsdownBuildOptions?.outDir ?? 'dist',
|
|
@@ -62,10 +60,9 @@ export default async function getConfig({ configPath, cwd }) {
|
|
|
62
60
|
},
|
|
63
61
|
modulesDir: conf.modulesDir ?? path.join(srcRoot ?? '.', 'modules'),
|
|
64
62
|
schemaOutDir: env.VOVK_SCHEMA_OUT_DIR ?? conf.schemaOutDir ?? './.vovk-schema',
|
|
65
|
-
origin: (env.VOVK_ORIGIN ?? conf.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
|
|
66
63
|
rootEntry: env.VOVK_ROOT_ENTRY ?? conf.rootEntry ?? 'api',
|
|
67
64
|
rootSegmentModulesDirName: conf.rootSegmentModulesDirName ?? '',
|
|
68
|
-
logLevel:
|
|
65
|
+
logLevel: conf.logLevel ?? 'info',
|
|
69
66
|
devHttps: conf.devHttps ?? false,
|
|
70
67
|
moduleTemplates: {
|
|
71
68
|
service: 'vovk-cli/module-templates/service.ts.ejs',
|
|
@@ -73,11 +70,22 @@ export default async function getConfig({ configPath, cwd }) {
|
|
|
73
70
|
...conf.moduleTemplates,
|
|
74
71
|
},
|
|
75
72
|
libs: conf.libs ?? {},
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
projectConfig: {
|
|
74
|
+
...conf.projectConfig,
|
|
75
|
+
origin: (env.VOVK_ORIGIN ?? conf?.projectConfig?.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
|
|
76
|
+
segments: Object.fromEntries(await Promise.all(Object.entries(conf.projectConfig?.segments ?? {}).map(async ([key, value]) => [
|
|
77
|
+
key,
|
|
78
|
+
{
|
|
79
|
+
...value,
|
|
80
|
+
openAPIMixin: value.openAPIMixin
|
|
81
|
+
? await normalizeOpenAPIMixin({ mixinModule: value.openAPIMixin, log, cwd })
|
|
82
|
+
: undefined,
|
|
83
|
+
},
|
|
84
|
+
]))),
|
|
85
|
+
},
|
|
78
86
|
};
|
|
79
87
|
if (typeof conf.emitConfig === 'undefined') {
|
|
80
|
-
config.emitConfig = ['libs'];
|
|
88
|
+
config.emitConfig = ['libs', 'projectConfig'];
|
|
81
89
|
}
|
|
82
90
|
else if (conf.emitConfig === true) {
|
|
83
91
|
config.emitConfig = Object.keys(config);
|
|
@@ -85,12 +93,6 @@ export default async function getConfig({ configPath, cwd }) {
|
|
|
85
93
|
else if (Array.isArray(conf.emitConfig)) {
|
|
86
94
|
config.emitConfig = conf.emitConfig;
|
|
87
95
|
} // else it's false and emitConfig already is []
|
|
88
|
-
const log = getLogger(config.logLevel);
|
|
89
|
-
config.openApiMixins = await normalizeOpenAPIMixins({
|
|
90
|
-
mixinModules: conf.openApiMixins ?? {},
|
|
91
|
-
cwd,
|
|
92
|
-
log,
|
|
93
|
-
});
|
|
94
96
|
if (!userConfig) {
|
|
95
97
|
log.warn(`Unable to load config at ${chalkHighlightThing(cwd)}. Using default values. ${error ?? ''}`);
|
|
96
98
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { VovkSchemaIdEnum, VovkStrictConfig } from 'vovk';
|
|
2
|
+
import { PackageJson } from 'type-fest';
|
|
3
|
+
export default function getMetaSchema({ config, package: packageJson, }: {
|
|
4
|
+
config: VovkStrictConfig;
|
|
5
|
+
package: PackageJson;
|
|
6
|
+
}): {
|
|
7
|
+
config: VovkStrictConfig;
|
|
8
|
+
$schema: VovkSchemaIdEnum;
|
|
9
|
+
package: Pick<PackageJson, "name" | "version" | "description" | "author" | "license">;
|
|
10
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VovkSchemaIdEnum } from 'vovk';
|
|
2
|
+
import pick from 'lodash/pick.js';
|
|
3
|
+
export default function getMetaSchema({ config, package: packageJson, }) {
|
|
4
|
+
return {
|
|
5
|
+
$schema: VovkSchemaIdEnum.META,
|
|
6
|
+
package: pick(packageJson, ['name', 'version', 'description', 'author', 'license']),
|
|
7
|
+
...{
|
|
8
|
+
config: (config
|
|
9
|
+
? pick(config, [...config.emitConfig, '$schema'])
|
|
10
|
+
: {}),
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { LogLevelNames } from 'loglevel';
|
|
1
2
|
export type ProjectInfo = Awaited<ReturnType<typeof getProjectInfo>>;
|
|
2
|
-
export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRootRequired, }?: {
|
|
3
|
+
export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRootRequired, logLevel, }?: {
|
|
3
4
|
port?: number;
|
|
4
5
|
cwd?: string;
|
|
5
6
|
configPath?: string;
|
|
6
7
|
srcRootRequired?: boolean;
|
|
8
|
+
logLevel?: LogLevelNames;
|
|
7
9
|
}): Promise<{
|
|
8
10
|
cwd: string;
|
|
9
11
|
port: string;
|
|
@@ -13,7 +15,7 @@ export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRo
|
|
|
13
15
|
vovkCliPackage: {
|
|
14
16
|
version: string;
|
|
15
17
|
};
|
|
16
|
-
config: import("vovk").VovkStrictConfig;
|
|
18
|
+
config: import("vovk/types").VovkStrictConfig;
|
|
17
19
|
packageJson: import("type-fest").PackageJson;
|
|
18
20
|
isNextInstalled: boolean;
|
|
19
21
|
log: {
|
|
@@ -2,20 +2,23 @@ import path from 'node:path';
|
|
|
2
2
|
import getConfig from './getConfig/index.mjs';
|
|
3
3
|
import { getPackageJson } from '../utils/getPackageJson.mjs';
|
|
4
4
|
import { readFile } from 'node:fs/promises';
|
|
5
|
-
export default async function getProjectInfo({ port: givenPort, cwd = process.cwd(), configPath, srcRootRequired = true, } = {
|
|
5
|
+
export default async function getProjectInfo({ port: givenPort, cwd = process.cwd(), configPath, srcRootRequired = true, logLevel, } = {
|
|
6
|
+
logLevel: 'info',
|
|
7
|
+
}) {
|
|
6
8
|
const port = givenPort?.toString() ?? process.env.PORT ?? '3000';
|
|
7
9
|
// Make PORT available to the config file at getConfig
|
|
8
10
|
process.env.PORT = port;
|
|
9
11
|
const { config, srcRoot, configAbsolutePaths, log } = await getConfig({
|
|
10
12
|
configPath,
|
|
11
13
|
cwd,
|
|
14
|
+
logLevel,
|
|
12
15
|
});
|
|
13
16
|
const packageJson = await getPackageJson(cwd, log);
|
|
14
17
|
const isNextInstalled = !!packageJson?.dependencies?.next || !!packageJson?.devDependencies?.next;
|
|
15
18
|
if (srcRootRequired && !srcRoot) {
|
|
16
19
|
throw new Error(`Could not find app router directory at ${cwd}. Check Next.js docs for more info.`);
|
|
17
20
|
}
|
|
18
|
-
const apiRoot = `${config.origin ?? ''}/${config.rootEntry}`;
|
|
21
|
+
const apiRoot = `${config.projectConfig.origin ?? ''}/${config.rootEntry}`;
|
|
19
22
|
const apiDirAbsolutePath = srcRoot ? path.resolve(cwd, srcRoot, 'app', config.rootEntry) : null;
|
|
20
23
|
if (configAbsolutePaths.length > 1) {
|
|
21
24
|
log.warn(`Multiple config files found. Using the first one: ${configAbsolutePaths[0]}`);
|
package/dist/index.mjs
CHANGED
|
@@ -25,8 +25,9 @@ program
|
|
|
25
25
|
.option('--exit', 'kill the processes when schema and client is generated')
|
|
26
26
|
.option('--schema-out <path>', 'path to schema output directory (default: .vovk-schema)')
|
|
27
27
|
.option('--https, --dev-https', 'use HTTPS for the dev server (default: false)')
|
|
28
|
+
.option('--log-level <level>', 'set the log level')
|
|
28
29
|
.action(async (nextArgs, options) => {
|
|
29
|
-
const { nextDev, exit = false, schemaOut, devHttps } = options;
|
|
30
|
+
const { nextDev, exit = false, schemaOut, devHttps, logLevel } = options;
|
|
30
31
|
const portAttempts = 30;
|
|
31
32
|
const PORT = !nextDev
|
|
32
33
|
? process.env.PORT
|
|
@@ -52,9 +53,11 @@ program
|
|
|
52
53
|
env: {
|
|
53
54
|
PORT,
|
|
54
55
|
__VOVK_START_WATCHER_IN_STANDALONE_MODE__: 'true',
|
|
56
|
+
// TODO: Pass these as flags
|
|
55
57
|
__VOVK_SCHEMA_OUT_FLAG__: schemaOut ?? '',
|
|
56
58
|
__VOVK_DEV_HTTPS_FLAG__: devHttps ? 'true' : 'false',
|
|
57
59
|
__VOVK_EXIT__: exit ? 'true' : 'false',
|
|
60
|
+
__VOVK_LOG_LEVEL__: logLevel ?? undefined,
|
|
58
61
|
},
|
|
59
62
|
},
|
|
60
63
|
], {
|
|
@@ -70,7 +73,7 @@ program
|
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
else {
|
|
73
|
-
void new VovkDev({ schemaOut, devHttps }).start({ exit });
|
|
76
|
+
void new VovkDev({ schemaOut, devHttps, logLevel }).start({ exit });
|
|
74
77
|
}
|
|
75
78
|
});
|
|
76
79
|
program
|
|
@@ -98,8 +101,13 @@ program
|
|
|
98
101
|
.option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
|
|
99
102
|
.option('--openapi-mixin-name <names...>', 'mixin names corresponding to the index of --openapi option')
|
|
100
103
|
.option('--openapi-fallback <paths...>', 'save OpenAPI spec and use it as a fallback if URL is not available')
|
|
104
|
+
.option('--log-level <level>', 'set the log level')
|
|
101
105
|
.action(async (cliGenerateOptions) => {
|
|
102
|
-
const projectInfo = await getProjectInfo({
|
|
106
|
+
const projectInfo = await getProjectInfo({
|
|
107
|
+
configPath: cliGenerateOptions.configPath,
|
|
108
|
+
srcRootRequired: false,
|
|
109
|
+
logLevel: cliGenerateOptions.logLevel,
|
|
110
|
+
});
|
|
103
111
|
await new VovkGenerate({
|
|
104
112
|
projectInfo,
|
|
105
113
|
forceNothingWrittenLog: true,
|
|
@@ -118,17 +126,25 @@ program
|
|
|
118
126
|
.option('--config <config>', 'path to config file')
|
|
119
127
|
.option('--schema <path>', 'path to schema folder (default: .vovk-schema)')
|
|
120
128
|
.option('--origin <url>', 'set the origin URL for the generated client')
|
|
129
|
+
.option('--tsconfig <path>', 'path to tsconfig.json for bundling by tsdown')
|
|
121
130
|
.option('--openapi, --openapi-spec <openapi_path_or_urls...>', 'use OpenAPI schema instead of Vovk schema')
|
|
122
131
|
.option('--openapi-get-module-name <names...>', 'module names corresponding to the index of --openapi option')
|
|
123
132
|
.option('--openapi-get-method-name <names...>', 'method names corresponding to the index of --openapi option')
|
|
124
133
|
.option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
|
|
134
|
+
.option('--log-level <level>', 'set the log level')
|
|
125
135
|
.action(async (cliBundleOptions) => {
|
|
126
|
-
const projectInfo = await getProjectInfo({
|
|
127
|
-
|
|
136
|
+
const projectInfo = await getProjectInfo({
|
|
137
|
+
configPath: cliBundleOptions.config,
|
|
138
|
+
srcRootRequired: false,
|
|
139
|
+
logLevel: cliBundleOptions.logLevel,
|
|
140
|
+
});
|
|
141
|
+
const { cwd, config, log, isNextInstalled, packageJson } = projectInfo;
|
|
128
142
|
const fullSchema = await getProjectFullSchema({
|
|
129
143
|
schemaOutAbsolutePath: path.resolve(cwd, cliBundleOptions?.schema ?? config.schemaOutDir),
|
|
130
144
|
log,
|
|
131
145
|
isNextInstalled,
|
|
146
|
+
package: packageJson,
|
|
147
|
+
config,
|
|
132
148
|
});
|
|
133
149
|
await bundle({
|
|
134
150
|
projectInfo,
|
|
@@ -147,7 +163,10 @@ program
|
|
|
147
163
|
.option('--no-segment-update', 'do not update segment files when creating a new module')
|
|
148
164
|
.option('--dry-run', 'do not write files to disk')
|
|
149
165
|
.option('--static', 'if the segment is static')
|
|
150
|
-
.
|
|
166
|
+
.option('--log-level <level>', 'set the log level')
|
|
167
|
+
.action(async (components, newOptions) => newComponents(components, await getProjectInfo({
|
|
168
|
+
logLevel: newOptions.logLevel,
|
|
169
|
+
}), newOptions));
|
|
151
170
|
program
|
|
152
171
|
.command('help')
|
|
153
172
|
.description('Show help message')
|
|
@@ -11,14 +11,36 @@ export default async function createConfig({ root, log, options: { validationLib
|
|
|
11
11
|
.readFile(path.join(root, 'package.json'), 'utf-8')
|
|
12
12
|
.then((content) => JSON.parse(content).type === 'module');
|
|
13
13
|
const configAbsolutePath = path.join(dir, isModule ? 'vovk.config.mjs' : 'vovk.config.js');
|
|
14
|
+
const typeTemplates = {
|
|
15
|
+
controller: 'vovk-cli/module-templates/type/controller.ts.ejs',
|
|
16
|
+
service: 'vovk-cli/module-templates/type/service.ts.ejs',
|
|
17
|
+
};
|
|
14
18
|
const moduleTemplates = {
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
...typeTemplates,
|
|
20
|
+
...{
|
|
21
|
+
type: typeTemplates,
|
|
22
|
+
zod: {
|
|
23
|
+
controller: 'vovk-zod/module-templates/controller.ts.ejs',
|
|
24
|
+
},
|
|
25
|
+
yup: {
|
|
26
|
+
controller: 'vovk-yup/module-templates/controller.ts.ejs',
|
|
27
|
+
},
|
|
28
|
+
'class-validator': {
|
|
29
|
+
controller: 'vovk-dto/module-templates/controller.ts.ejs',
|
|
30
|
+
},
|
|
31
|
+
valibot: {
|
|
32
|
+
controller: 'vovk-cli/module-templates/valibot/controller.ts.ejs',
|
|
33
|
+
},
|
|
34
|
+
arktype: {
|
|
35
|
+
controller: 'vovk-cli/module-templates/arktype/controller.ts.ejs',
|
|
36
|
+
},
|
|
37
|
+
}[validationLibrary ?? 'type'],
|
|
17
38
|
};
|
|
18
39
|
config.imports ??= {};
|
|
19
|
-
config.imports.validateOnClient = validationLibrary === '
|
|
20
|
-
if (validationLibrary) {
|
|
40
|
+
config.imports.validateOnClient = validationLibrary === 'class-validator' ? 'vovk-dto/validateOnClient' : 'vovk-ajv';
|
|
41
|
+
if (validationLibrary && !moduleTemplates) {
|
|
21
42
|
try {
|
|
43
|
+
// TODO: Legacy, is it useful to keep it?
|
|
22
44
|
const validationTemplates = await getTemplateFilesFromPackage(validationLibrary, channel);
|
|
23
45
|
Object.assign(moduleTemplates, validationTemplates);
|
|
24
46
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import getRelativeSrcRoot from '../getProjectInfo/getConfig/getRelativeSrcRoot.mjs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
function getCode(validationLibrary) {
|
|
5
|
+
if (validationLibrary === 'valibot') {
|
|
6
|
+
return `
|
|
7
|
+
import { createStandardValidation, KnownAny } from 'vovk';
|
|
8
|
+
import { toJsonSchema } from '@valibot/to-json-schema';
|
|
9
|
+
import * as v from 'valibot';
|
|
10
|
+
|
|
11
|
+
const withValibot = createStandardValidation({
|
|
12
|
+
toJSONSchema: (model: v.BaseSchema<KnownAny, KnownAny, KnownAny>) => toJsonSchema(model),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default withValibot;
|
|
16
|
+
`.trimStart();
|
|
17
|
+
}
|
|
18
|
+
if (validationLibrary === 'arktype') {
|
|
19
|
+
return `
|
|
20
|
+
import { createStandardValidation } from 'vovk';
|
|
21
|
+
import { type } from 'arktype';
|
|
22
|
+
|
|
23
|
+
const withArk = createStandardValidation({
|
|
24
|
+
toJSONSchema: (model: type) => model.toJsonSchema(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export default withArk;
|
|
28
|
+
`.trimStart();
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`Unknown validation library: ${validationLibrary}`);
|
|
31
|
+
}
|
|
32
|
+
export async function createStandardSchemaValidatorFile({ cwd, validationLibrary, }) {
|
|
33
|
+
const code = getCode(validationLibrary);
|
|
34
|
+
const srcRoot = (await getRelativeSrcRoot({ cwd })) ?? '.';
|
|
35
|
+
const libDir = path.join(cwd, srcRoot, 'lib');
|
|
36
|
+
await fs.mkdir(libDir, { recursive: true });
|
|
37
|
+
await fs.writeFile(path.join(libDir, `${validationLibrary === 'arktype' ? 'withArk' : 'withValibot'}.ts`), code);
|
|
38
|
+
}
|
package/dist/init/index.mjs
CHANGED
|
@@ -8,18 +8,19 @@ import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
|
|
|
8
8
|
import installDependencies, { getPackageManager } from './installDependencies.mjs';
|
|
9
9
|
import getLogger from '../utils/getLogger.mjs';
|
|
10
10
|
import createConfig from './createConfig.mjs';
|
|
11
|
-
import updateNPMScripts, {
|
|
11
|
+
import updateNPMScripts, { getDevScript } from './updateNPMScripts.mjs';
|
|
12
12
|
import checkTSConfigForExperimentalDecorators from './checkTSConfigForExperimentalDecorators.mjs';
|
|
13
13
|
import updateTypeScriptConfig from './updateTypeScriptConfig.mjs';
|
|
14
14
|
import updateDependenciesWithoutInstalling from './updateDependenciesWithoutInstalling.mjs';
|
|
15
15
|
import logUpdateDependenciesError from './logUpdateDependenciesError.mjs';
|
|
16
16
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
17
|
+
import { createStandardSchemaValidatorFile } from './createStandardSchemaValidatorFile.mjs';
|
|
17
18
|
export class Init {
|
|
18
19
|
root;
|
|
19
20
|
log;
|
|
20
|
-
async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
|
|
21
|
+
async #init({ configPaths, pkgJson, cwd = process.cwd(), }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
|
|
21
22
|
const { log, root } = this;
|
|
22
|
-
const dependencies = ['vovk', 'vovk-client', 'vovk-ajv', '
|
|
23
|
+
const dependencies = ['vovk', 'vovk-client', 'openapi3-ts', 'vovk-ajv', 'ajv'];
|
|
23
24
|
const devDependencies = ['vovk-cli'];
|
|
24
25
|
if (lang?.includes('py')) {
|
|
25
26
|
devDependencies.push('vovk-python');
|
|
@@ -33,9 +34,18 @@ export class Init {
|
|
|
33
34
|
log.debug(`Deleted existing config file${configPaths.length > 1 ? 's' : ''} at ${configPaths.join(', ')}`);
|
|
34
35
|
}
|
|
35
36
|
if (validationLibrary) {
|
|
36
|
-
dependencies.push(
|
|
37
|
-
|
|
38
|
-
'
|
|
37
|
+
dependencies.push(...({
|
|
38
|
+
zod: ['zod', 'vovk-zod'],
|
|
39
|
+
'class-validator': [
|
|
40
|
+
'class-validator',
|
|
41
|
+
'class-transformer',
|
|
42
|
+
'dto-mapped-types',
|
|
43
|
+
'reflect-metadata',
|
|
44
|
+
'vovk-dto',
|
|
45
|
+
],
|
|
46
|
+
yup: ['yup', 'vovk-yup'],
|
|
47
|
+
valibot: ['valibot', '@valibot/to-json-schema'],
|
|
48
|
+
arktype: ['arktype'],
|
|
39
49
|
}[validationLibrary] ?? []));
|
|
40
50
|
}
|
|
41
51
|
if (updateScripts) {
|
|
@@ -56,7 +66,7 @@ export class Init {
|
|
|
56
66
|
const compilerOptions = {
|
|
57
67
|
experimentalDecorators: true,
|
|
58
68
|
};
|
|
59
|
-
if (validationLibrary === '
|
|
69
|
+
if (validationLibrary === 'class-validator') {
|
|
60
70
|
compilerOptions.emitDecoratorMetadata = true;
|
|
61
71
|
}
|
|
62
72
|
if (!dryRun)
|
|
@@ -120,6 +130,12 @@ export class Init {
|
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
}
|
|
133
|
+
if (validationLibrary === 'valibot' || validationLibrary === 'arktype') {
|
|
134
|
+
createStandardSchemaValidatorFile({
|
|
135
|
+
cwd,
|
|
136
|
+
validationLibrary,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
123
139
|
try {
|
|
124
140
|
const { configAbsolutePath } = await createConfig({
|
|
125
141
|
root,
|
|
@@ -135,13 +151,13 @@ export class Init {
|
|
|
135
151
|
async main({ prefix, yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
|
|
136
152
|
const cwd = process.cwd();
|
|
137
153
|
const root = path.resolve(cwd, prefix ?? '.');
|
|
138
|
-
const log = getLogger(logLevel);
|
|
154
|
+
const log = getLogger(logLevel ?? 'info');
|
|
139
155
|
const pkgJson = await NPMCliPackageJson.load(root);
|
|
140
156
|
this.root = root;
|
|
141
157
|
this.log = log;
|
|
142
158
|
const configPaths = await getConfigPaths({ cwd, relativePath: prefix });
|
|
143
159
|
if (yes) {
|
|
144
|
-
return this.#init({ configPaths, pkgJson }, {
|
|
160
|
+
return this.#init({ configPaths, pkgJson, cwd }, {
|
|
145
161
|
prefix: prefix ?? '.',
|
|
146
162
|
useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
|
|
147
163
|
useYarn: useYarn ?? false,
|
|
@@ -150,7 +166,7 @@ export class Init {
|
|
|
150
166
|
skipInstall: skipInstall ?? false,
|
|
151
167
|
updateTsConfig: updateTsConfig ?? true,
|
|
152
168
|
updateScripts: updateScripts ?? 'implicit',
|
|
153
|
-
validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? '
|
|
169
|
+
validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'zod'),
|
|
154
170
|
dryRun: dryRun ?? false,
|
|
155
171
|
channel: channel ?? 'latest',
|
|
156
172
|
lang: lang ?? [],
|
|
@@ -174,17 +190,27 @@ export class Init {
|
|
|
174
190
|
: (validationLibrary ??
|
|
175
191
|
(await select({
|
|
176
192
|
message: 'Choose validation library',
|
|
177
|
-
default: '
|
|
193
|
+
default: 'zod',
|
|
178
194
|
choices: [
|
|
179
195
|
{
|
|
180
|
-
name: '
|
|
181
|
-
value: '
|
|
196
|
+
name: 'Zod',
|
|
197
|
+
value: 'zod',
|
|
182
198
|
description: 'Use Zod for data validation',
|
|
183
199
|
},
|
|
184
200
|
{
|
|
185
|
-
name: '
|
|
186
|
-
value: '
|
|
187
|
-
description: 'Use class-validator for data validation
|
|
201
|
+
name: 'class-validator',
|
|
202
|
+
value: 'class-validator',
|
|
203
|
+
description: 'Use class-validator for data validation',
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: 'Valibot',
|
|
207
|
+
value: 'valibot',
|
|
208
|
+
description: 'Use valibot for data validation.',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: 'ArkType',
|
|
212
|
+
value: 'arktype',
|
|
213
|
+
description: 'Use arktype for data validation.',
|
|
188
214
|
},
|
|
189
215
|
{ name: 'None', value: null, description: 'Install validation library later' },
|
|
190
216
|
],
|
|
@@ -196,12 +222,12 @@ export class Init {
|
|
|
196
222
|
{
|
|
197
223
|
name: 'Yes, use "concurrently" implicitly',
|
|
198
224
|
value: 'implicit',
|
|
199
|
-
description: `The "dev" script will use "concurrently" API to run "next dev" and "vovk dev" commands together and automatically find an available port ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'implicit')}"`)} and the "
|
|
225
|
+
description: `The "dev" script will use "concurrently" API to run "next dev" and "vovk dev" commands together and automatically find an available port ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'implicit')}"`)} and the "prebuild" script will run "vovk generate"`,
|
|
200
226
|
},
|
|
201
227
|
{
|
|
202
228
|
name: 'Yes, use "concurrently" explicitly',
|
|
203
229
|
value: 'explicit',
|
|
204
|
-
description: `The "dev" script will use pre-defined PORT variable and run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'explicit')}"`)} and the "
|
|
230
|
+
description: `The "dev" script will use pre-defined PORT variable and run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'explicit')}"`)} and the "prebuild" script will run "vovk generate"`,
|
|
205
231
|
},
|
|
206
232
|
{
|
|
207
233
|
name: 'No',
|
|
@@ -220,7 +246,7 @@ export class Init {
|
|
|
220
246
|
}
|
|
221
247
|
if (shouldAsk) {
|
|
222
248
|
const keys = ['experimentalDecorators'];
|
|
223
|
-
if (validationLibrary === '
|
|
249
|
+
if (validationLibrary === 'class-validator') {
|
|
224
250
|
keys.push('emitDecoratorMetadata');
|
|
225
251
|
}
|
|
226
252
|
updateTsConfig = await confirm({
|
|
@@ -229,13 +255,13 @@ export class Init {
|
|
|
229
255
|
}
|
|
230
256
|
}
|
|
231
257
|
lang ??= await checkbox({
|
|
232
|
-
message: 'Do you want to generate RPC client for other languages besides TypeScript (
|
|
258
|
+
message: 'Do you want to generate RPC client for other languages besides TypeScript (experimental)?',
|
|
233
259
|
choices: [
|
|
234
260
|
{ name: 'Python', value: 'py' },
|
|
235
261
|
{ name: 'Rust', value: 'rs' },
|
|
236
262
|
],
|
|
237
263
|
});
|
|
238
|
-
await this.#init({ configPaths, pkgJson }, {
|
|
264
|
+
await this.#init({ configPaths, pkgJson, cwd }, {
|
|
239
265
|
useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
|
|
240
266
|
useYarn: useYarn ?? false,
|
|
241
267
|
usePnpm: usePnpm ?? false,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import NPMCliPackageJson from '@npmcli/package-json';
|
|
2
2
|
export declare function getDevScript(pkgJson: NPMCliPackageJson, updateScriptsMode: 'implicit' | 'explicit'): string;
|
|
3
|
-
export declare function getBuildScript(pkgJson: NPMCliPackageJson): string;
|
|
4
3
|
export default function updateNPMScripts(pkgJson: NPMCliPackageJson, root: string, updateScriptsMode: 'implicit' | 'explicit'): Promise<void>;
|
|
@@ -5,16 +5,12 @@ export function getDevScript(pkgJson, updateScriptsMode) {
|
|
|
5
5
|
? `PORT=3000 concurrently '${nextDev}' 'vovk dev' --kill-others`
|
|
6
6
|
: `vovk dev --next-dev${nextDevFlags ? ` -- ${nextDevFlags}` : ''}`;
|
|
7
7
|
}
|
|
8
|
-
export function getBuildScript(pkgJson) {
|
|
9
|
-
const nextBuild = pkgJson.content.scripts?.build ?? 'next build';
|
|
10
|
-
return `vovk generate && ${nextBuild}`;
|
|
11
|
-
}
|
|
12
8
|
export default async function updateNPMScripts(pkgJson, root, updateScriptsMode) {
|
|
13
9
|
pkgJson.update({
|
|
14
10
|
scripts: {
|
|
15
11
|
...pkgJson.content.scripts,
|
|
16
12
|
dev: getDevScript(pkgJson, updateScriptsMode),
|
|
17
|
-
|
|
13
|
+
prebuild: 'vovk generate',
|
|
18
14
|
},
|
|
19
15
|
});
|
|
20
16
|
await pkgJson.save();
|
package/dist/initProgram.mjs
CHANGED
|
@@ -14,7 +14,7 @@ export function initProgram(program) {
|
|
|
14
14
|
.option('--update-ts-config', 'update tsconfig.json')
|
|
15
15
|
.option('--update-scripts <mode>', 'update package.json scripts ("implicit" or "explicit")')
|
|
16
16
|
.option('--lang <languages...>', 'generate client for other programming languages by default ("py" for Python and "rs" for Rust are supported)')
|
|
17
|
-
.option('--validation-library <library>', 'validation library to use ("
|
|
17
|
+
.option('--validation-library <library>', 'validation library to use ("zod", "class-validator", "valibot", "arktype" or another); set to "none" to skip')
|
|
18
18
|
.option('--channel <channel>', 'channel to use for fetching packages', 'latest')
|
|
19
19
|
.option('--dry-run', 'do not write files to disk')
|
|
20
20
|
.action((options) => new Init().main(options));
|
package/dist/new/index.d.mts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { NewOptions } from '../types.mjs';
|
|
2
|
-
|
|
2
|
+
import type { ProjectInfo } from '../getProjectInfo/index.mts';
|
|
3
|
+
export declare function newComponents(components: string[], projectInfo: ProjectInfo, { dryRun, dir, templates, overwrite, noSegmentUpdate, empty, static: isStaticSegment }: NewOptions): Promise<void>;
|