vovk-cli 0.0.1-draft.35 → 0.0.1-draft.351
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +29 -1
- package/client-templates/cjs/index.cjs.ejs +20 -0
- package/client-templates/cjs/index.d.cts.ejs +22 -0
- package/client-templates/mixins/mixins.d.ts.ejs +64 -0
- package/client-templates/mixins/mixins.json.ejs +1 -0
- package/client-templates/mjs/index.d.mts.ejs +22 -0
- package/client-templates/mjs/index.mjs.ejs +18 -0
- package/client-templates/openapiCjs/openapi.cjs.ejs +4 -0
- package/client-templates/openapiCjs/openapi.d.cts.ejs +4 -0
- package/client-templates/openapiJson/openapi.json.ejs +1 -0
- package/client-templates/openapiTs/openapi.ts.ejs +4 -0
- package/client-templates/packageJson/package.json.ejs +1 -0
- package/client-templates/readme/README.md.ejs +39 -0
- package/client-templates/schemaCjs/schema.cjs.ejs +23 -0
- package/client-templates/schemaCjs/schema.d.cts.ejs +10 -0
- package/client-templates/schemaJson/schema.json.ejs +1 -0
- package/client-templates/schemaTs/schema.ts.ejs +31 -0
- package/client-templates/ts/index.ts.ejs +27 -0
- package/dist/bundle/index.d.mts +8 -0
- package/dist/bundle/index.mjs +102 -0
- package/dist/dev/diffSegmentSchema.d.mts +36 -0
- package/dist/dev/{diffSchema.mjs → diffSegmentSchema.mjs} +3 -11
- package/dist/dev/ensureSchemaFiles.d.mts +4 -1
- package/dist/dev/ensureSchemaFiles.mjs +15 -31
- package/dist/dev/index.d.mts +5 -1
- package/dist/dev/index.mjs +192 -80
- package/dist/dev/logDiffResult.d.mts +1 -1
- package/dist/dev/logDiffResult.mjs +6 -43
- package/dist/dev/writeMetaJson.d.mts +2 -0
- package/dist/dev/writeMetaJson.mjs +20 -0
- package/dist/dev/writeOneSegmentSchemaFile.d.mts +12 -0
- package/dist/dev/{writeOneSchemaFile.mjs → writeOneSegmentSchemaFile.mjs} +10 -6
- package/dist/generate/ensureClient.d.mts +3 -0
- package/dist/generate/ensureClient.mjs +28 -0
- package/dist/generate/generate.d.mts +13 -0
- package/dist/generate/generate.mjs +296 -0
- package/dist/generate/getClientTemplateFiles.d.mts +20 -0
- package/dist/generate/getClientTemplateFiles.mjs +85 -0
- package/dist/generate/getProjectFullSchema.d.mts +8 -0
- package/dist/generate/getProjectFullSchema.mjs +64 -0
- package/dist/generate/getTemplateClientImports.d.mts +19 -0
- package/dist/generate/getTemplateClientImports.mjs +49 -0
- package/dist/generate/index.d.mts +33 -0
- package/dist/generate/index.mjs +190 -0
- package/dist/generate/writeOneClientFile.d.mts +41 -0
- package/dist/generate/writeOneClientFile.mjs +136 -0
- package/dist/getProjectInfo/getConfig/getConfigAbsolutePaths.d.mts +5 -0
- package/dist/getProjectInfo/{getConfigAbsolutePaths.mjs → getConfig/getConfigAbsolutePaths.mjs} +4 -1
- package/dist/getProjectInfo/{getRelativeSrcRoot.d.mts → getConfig/getRelativeSrcRoot.d.mts} +1 -1
- package/dist/getProjectInfo/{getRelativeSrcRoot.mjs → getConfig/getRelativeSrcRoot.mjs} +2 -2
- package/dist/getProjectInfo/getConfig/getTemplateDefs.d.mts +24 -0
- package/dist/getProjectInfo/getConfig/getTemplateDefs.mjs +165 -0
- package/dist/getProjectInfo/{getUserConfig.d.mts → getConfig/getUserConfig.d.mts} +3 -2
- package/dist/getProjectInfo/{getUserConfig.mjs → getConfig/getUserConfig.mjs} +3 -3
- package/dist/getProjectInfo/{importUncachedModule.mjs → getConfig/importUncachedModule.mjs} +1 -4
- package/dist/getProjectInfo/getConfig/index.d.mts +76 -0
- package/dist/getProjectInfo/getConfig/index.mjs +91 -0
- package/dist/getProjectInfo/getMetaSchema.d.mts +8 -0
- package/dist/getProjectInfo/getMetaSchema.mjs +14 -0
- package/dist/getProjectInfo/index.d.mts +14 -9
- package/dist/getProjectInfo/index.mjs +24 -22
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +118 -36
- package/dist/init/createConfig.d.mts +2 -2
- package/dist/init/createConfig.mjs +39 -13
- package/dist/init/createStandardSchemaValidatorFile.d.mts +4 -0
- package/dist/init/createStandardSchemaValidatorFile.mjs +39 -0
- package/dist/init/getTemplateFilesFromPackage.mjs +10 -5
- package/dist/init/index.d.mts +2 -2
- package/dist/init/index.mjs +114 -66
- package/dist/init/installDependencies.mjs +4 -2
- package/dist/init/logUpdateDependenciesError.d.mts +3 -1
- package/dist/init/logUpdateDependenciesError.mjs +7 -1
- package/dist/init/updateDependenciesWithoutInstalling.mjs +39 -9
- package/dist/init/updateNPMScripts.d.mts +3 -1
- package/dist/init/updateNPMScripts.mjs +10 -7
- package/dist/init/updateTypeScriptConfig.d.mts +4 -1
- package/dist/init/updateTypeScriptConfig.mjs +11 -7
- package/dist/initProgram.d.mts +1 -1
- package/dist/initProgram.mjs +17 -17
- package/dist/locateSegments.d.mts +8 -1
- package/dist/locateSegments.mjs +13 -3
- package/dist/new/addClassToSegmentCode.d.mts +1 -2
- package/dist/new/addClassToSegmentCode.mjs +3 -3
- package/dist/new/index.d.mts +2 -1
- package/dist/new/index.mjs +4 -2
- package/dist/new/newModule.d.mts +4 -1
- package/dist/new/newModule.mjs +18 -17
- package/dist/new/newSegment.d.mts +4 -1
- package/dist/new/newSegment.mjs +19 -11
- package/dist/new/render.d.mts +7 -3
- package/dist/new/render.mjs +29 -8
- package/dist/types.d.mts +64 -42
- package/dist/utils/compileJSONSchemaToTypeScriptType.d.mts +5 -0
- package/dist/utils/compileJSONSchemaToTypeScriptType.mjs +9 -0
- package/dist/utils/compileTs.d.mts +12 -0
- package/dist/utils/compileTs.mjs +261 -0
- package/dist/utils/debounceWithArgs.d.mts +2 -2
- package/dist/utils/debounceWithArgs.mjs +24 -6
- package/dist/utils/formatLoggedSegmentName.d.mts +3 -1
- package/dist/utils/formatLoggedSegmentName.mjs +3 -2
- package/dist/utils/generateFnName.d.mts +23 -0
- package/dist/utils/generateFnName.mjs +76 -0
- package/dist/utils/getPackageJson.d.mts +3 -0
- package/dist/utils/getPackageJson.mjs +22 -0
- package/dist/utils/getPublicModuleNameFromPath.d.mts +4 -0
- package/dist/utils/getPublicModuleNameFromPath.mjs +9 -0
- package/dist/utils/normalizeOpenAPIMixin.d.mts +14 -0
- package/dist/utils/normalizeOpenAPIMixin.mjs +114 -0
- package/dist/utils/pickSegmentFullSchema.d.mts +3 -0
- package/dist/utils/pickSegmentFullSchema.mjs +15 -0
- package/dist/utils/removeUnlistedDirectories.d.mts +10 -0
- package/dist/utils/removeUnlistedDirectories.mjs +61 -0
- package/dist/utils/resolveAbsoluteModulePath.d.mts +2 -0
- package/dist/utils/resolveAbsoluteModulePath.mjs +32 -0
- package/module-templates/arktype/controller.ts.ejs +68 -0
- package/module-templates/type/controller.ts.ejs +56 -0
- package/module-templates/type/service.ts.ejs +28 -0
- package/module-templates/valibot/controller.ts.ejs +68 -0
- package/package.json +35 -22
- package/dist/dev/diffSchema.d.mts +0 -43
- package/dist/dev/ensureClient.d.mts +0 -5
- package/dist/dev/ensureClient.mjs +0 -31
- package/dist/dev/isMetadataEmpty.d.mts +0 -2
- package/dist/dev/isMetadataEmpty.mjs +0 -4
- package/dist/dev/writeOneSchemaFile.d.mts +0 -11
- package/dist/generateClient.d.mts +0 -7
- package/dist/generateClient.mjs +0 -97
- package/dist/getProjectInfo/getConfig.d.mts +0 -11
- package/dist/getProjectInfo/getConfig.mjs +0 -29
- package/dist/getProjectInfo/getConfigAbsolutePaths.d.mts +0 -4
- package/dist/postinstall.d.mts +0 -1
- package/dist/postinstall.mjs +0 -24
- package/templates/controller.ejs +0 -52
- package/templates/service.ejs +0 -27
- package/templates/worker.ejs +0 -24
- /package/dist/getProjectInfo/{importUncachedModule.d.mts → getConfig/importUncachedModule.d.mts} +0 -0
- /package/dist/getProjectInfo/{importUncachedModuleWorker.d.mts → getConfig/importUncachedModuleWorker.d.mts} +0 -0
- /package/dist/getProjectInfo/{importUncachedModuleWorker.mjs → getConfig/importUncachedModuleWorker.mjs} +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { VovkSchemaIdEnum, type VovkStrictConfig } from 'vovk';
|
|
2
|
+
import type { LogLevelNames } from 'loglevel';
|
|
3
|
+
export default function getConfig({ configPath, cwd, logLevel, }: {
|
|
4
|
+
configPath?: string;
|
|
5
|
+
cwd: string;
|
|
6
|
+
logLevel?: LogLevelNames;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
config: VovkStrictConfig;
|
|
9
|
+
srcRoot: string | null;
|
|
10
|
+
configAbsolutePaths: string[];
|
|
11
|
+
userConfig: {
|
|
12
|
+
$schema?: typeof VovkSchemaIdEnum.CONFIG | (string & {});
|
|
13
|
+
emitConfig?: boolean | (keyof VovkStrictConfig | (string & {}))[];
|
|
14
|
+
schemaOutDir?: string;
|
|
15
|
+
modulesDir?: string;
|
|
16
|
+
rootEntry?: string;
|
|
17
|
+
logLevel?: "error" | "trace" | "debug" | "info" | "warn" | (string & {});
|
|
18
|
+
libs?: {
|
|
19
|
+
ajv: import("vovk").KnownAny;
|
|
20
|
+
[key: string]: import("vovk").KnownAny;
|
|
21
|
+
};
|
|
22
|
+
devHttps?: boolean;
|
|
23
|
+
composedClient?: {
|
|
24
|
+
enabled?: boolean;
|
|
25
|
+
outDir?: string;
|
|
26
|
+
fromTemplates?: string[];
|
|
27
|
+
prettifyClient?: boolean;
|
|
28
|
+
} & ({
|
|
29
|
+
excludeSegments?: never;
|
|
30
|
+
includeSegments?: string[];
|
|
31
|
+
} | {
|
|
32
|
+
excludeSegments?: string[];
|
|
33
|
+
includeSegments?: never;
|
|
34
|
+
});
|
|
35
|
+
segmentedClient?: {
|
|
36
|
+
enabled?: boolean;
|
|
37
|
+
outDir?: string;
|
|
38
|
+
fromTemplates?: string[];
|
|
39
|
+
prettifyClient?: boolean;
|
|
40
|
+
} & ({
|
|
41
|
+
excludeSegments?: never;
|
|
42
|
+
includeSegments?: string[];
|
|
43
|
+
} | {
|
|
44
|
+
excludeSegments?: string[];
|
|
45
|
+
includeSegments?: never;
|
|
46
|
+
});
|
|
47
|
+
bundle?: {
|
|
48
|
+
requires?: Record<string, string>;
|
|
49
|
+
prebundleOutDir?: string;
|
|
50
|
+
keepPrebundleDir?: boolean;
|
|
51
|
+
tsdownBuildOptions?: Parameters<typeof import("tsdown/config-9hj-APNF.mjs").build>[0];
|
|
52
|
+
generatorConfig?: import("vovk").VovkGeneratorConfigCommon;
|
|
53
|
+
} & ({
|
|
54
|
+
excludeSegments?: never;
|
|
55
|
+
includeSegments?: string[];
|
|
56
|
+
} | {
|
|
57
|
+
excludeSegments?: string[];
|
|
58
|
+
includeSegments?: never;
|
|
59
|
+
});
|
|
60
|
+
clientTemplateDefs?: Record<string, import("vovk/types").ClientTemplateDef>;
|
|
61
|
+
rootSegmentModulesDirName?: string;
|
|
62
|
+
moduleTemplates?: {
|
|
63
|
+
service?: string;
|
|
64
|
+
controller?: string;
|
|
65
|
+
[key: string]: string | undefined;
|
|
66
|
+
};
|
|
67
|
+
generatorConfig?: import("vovk").VovkGeneratorConfig;
|
|
68
|
+
} | null;
|
|
69
|
+
log: {
|
|
70
|
+
info: (msg: string) => void;
|
|
71
|
+
warn: (msg: string) => void;
|
|
72
|
+
error: (msg: string) => void;
|
|
73
|
+
debug: (msg: string) => void;
|
|
74
|
+
raw: import("loglevel").RootLogger;
|
|
75
|
+
};
|
|
76
|
+
}>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { VovkSchemaIdEnum } from 'vovk';
|
|
3
|
+
import getLogger from '../../utils/getLogger.mjs';
|
|
4
|
+
import getUserConfig from './getUserConfig.mjs';
|
|
5
|
+
import getRelativeSrcRoot from './getRelativeSrcRoot.mjs';
|
|
6
|
+
import getTemplateDefs, { BuiltInTemplateName } from './getTemplateDefs.mjs';
|
|
7
|
+
import { normalizeOpenAPIMixin } from '../../utils/normalizeOpenAPIMixin.mjs';
|
|
8
|
+
import chalkHighlightThing from '../../utils/chalkHighlightThing.mjs';
|
|
9
|
+
export default async function getConfig({ configPath, cwd, logLevel, }) {
|
|
10
|
+
const { configAbsolutePaths, error, userConfig } = await getUserConfig({
|
|
11
|
+
configPath,
|
|
12
|
+
cwd,
|
|
13
|
+
});
|
|
14
|
+
const conf = userConfig ?? {};
|
|
15
|
+
logLevel = logLevel ?? conf.logLevel ?? 'info';
|
|
16
|
+
const log = getLogger(logLevel);
|
|
17
|
+
const env = process.env;
|
|
18
|
+
const clientTemplateDefs = getTemplateDefs(conf.clientTemplateDefs);
|
|
19
|
+
const srcRoot = await getRelativeSrcRoot({ cwd });
|
|
20
|
+
const config = {
|
|
21
|
+
$schema: VovkSchemaIdEnum.CONFIG,
|
|
22
|
+
clientTemplateDefs,
|
|
23
|
+
emitConfig: [],
|
|
24
|
+
composedClient: {
|
|
25
|
+
...conf.composedClient,
|
|
26
|
+
enabled: conf.composedClient?.enabled ?? true,
|
|
27
|
+
fromTemplates: conf.composedClient?.fromTemplates ?? ['mjs', 'cjs'],
|
|
28
|
+
outDir: conf.composedClient?.outDir ?? './node_modules/.vovk-client',
|
|
29
|
+
prettifyClient: conf.composedClient?.prettifyClient ?? false,
|
|
30
|
+
},
|
|
31
|
+
segmentedClient: {
|
|
32
|
+
...conf.segmentedClient,
|
|
33
|
+
enabled: conf.segmentedClient?.enabled ?? false,
|
|
34
|
+
fromTemplates: conf.segmentedClient?.fromTemplates ?? ['ts'],
|
|
35
|
+
outDir: conf.segmentedClient?.outDir ?? path.join(srcRoot ?? '.', 'client'),
|
|
36
|
+
prettifyClient: conf.segmentedClient?.prettifyClient ?? true,
|
|
37
|
+
},
|
|
38
|
+
bundle: {
|
|
39
|
+
prebundleOutDir: conf.bundle?.prebundleOutDir ?? 'tmp_prebundle',
|
|
40
|
+
keepPrebundleDir: conf.bundle?.keepPrebundleDir ?? false,
|
|
41
|
+
requires: {
|
|
42
|
+
[BuiltInTemplateName.readme]: '.',
|
|
43
|
+
[BuiltInTemplateName.packageJson]: '.',
|
|
44
|
+
},
|
|
45
|
+
generatorConfig: {},
|
|
46
|
+
...conf.bundle,
|
|
47
|
+
tsdownBuildOptions: {
|
|
48
|
+
outDir: conf.bundle?.tsdownBuildOptions?.outDir ?? 'dist',
|
|
49
|
+
...conf.bundle?.tsdownBuildOptions,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
modulesDir: conf.modulesDir ?? path.join(srcRoot ?? '.', 'modules'),
|
|
53
|
+
schemaOutDir: env.VOVK_SCHEMA_OUT_DIR ?? conf.schemaOutDir ?? './.vovk-schema',
|
|
54
|
+
rootEntry: env.VOVK_ROOT_ENTRY ?? conf.rootEntry ?? 'api',
|
|
55
|
+
rootSegmentModulesDirName: conf.rootSegmentModulesDirName ?? '',
|
|
56
|
+
logLevel,
|
|
57
|
+
devHttps: conf.devHttps ?? false,
|
|
58
|
+
moduleTemplates: {
|
|
59
|
+
service: 'vovk-cli/module-templates/service.ts.ejs',
|
|
60
|
+
controller: 'vovk-cli/module-templates/controller.ts.ejs',
|
|
61
|
+
...conf.moduleTemplates,
|
|
62
|
+
},
|
|
63
|
+
libs: conf.libs ?? {},
|
|
64
|
+
generatorConfig: {
|
|
65
|
+
...conf.generatorConfig,
|
|
66
|
+
origin: (env.VOVK_ORIGIN ?? conf?.generatorConfig?.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
|
|
67
|
+
segments: Object.fromEntries(await Promise.all(Object.entries(conf.generatorConfig?.segments ?? {}).map(async ([key, value]) => [
|
|
68
|
+
key,
|
|
69
|
+
{
|
|
70
|
+
...value,
|
|
71
|
+
openAPIMixin: value.openAPIMixin
|
|
72
|
+
? await normalizeOpenAPIMixin({ mixinModule: value.openAPIMixin, log, cwd })
|
|
73
|
+
: undefined,
|
|
74
|
+
},
|
|
75
|
+
]))),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
if (typeof conf.emitConfig === 'undefined') {
|
|
79
|
+
config.emitConfig = ['libs', 'generatorConfig'];
|
|
80
|
+
}
|
|
81
|
+
else if (conf.emitConfig === true) {
|
|
82
|
+
config.emitConfig = Object.keys(config);
|
|
83
|
+
}
|
|
84
|
+
else if (Array.isArray(conf.emitConfig)) {
|
|
85
|
+
config.emitConfig = conf.emitConfig;
|
|
86
|
+
} // else it's false and emitConfig already is []
|
|
87
|
+
if (!userConfig) {
|
|
88
|
+
log.warn(`Unable to load config at ${chalkHighlightThing(cwd)}. Using default values. ${error ?? ''}`);
|
|
89
|
+
}
|
|
90
|
+
return { config, srcRoot, configAbsolutePaths, userConfig, log };
|
|
91
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { VovkSchemaIdEnum } from 'vovk';
|
|
2
|
+
import pick from 'lodash/pick.js';
|
|
3
|
+
export default function getMetaSchema({ config, useEmitConfig }) {
|
|
4
|
+
return {
|
|
5
|
+
$schema: VovkSchemaIdEnum.META,
|
|
6
|
+
...{
|
|
7
|
+
config: useEmitConfig
|
|
8
|
+
? (config
|
|
9
|
+
? pick(config, [...config.emitConfig, '$schema'])
|
|
10
|
+
: {})
|
|
11
|
+
: config,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
+
import { LogLevelNames } from 'loglevel';
|
|
1
2
|
export type ProjectInfo = Awaited<ReturnType<typeof getProjectInfo>>;
|
|
2
|
-
export default function getProjectInfo({ port: givenPort,
|
|
3
|
+
export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRootRequired, logLevel, }?: {
|
|
3
4
|
port?: number;
|
|
4
|
-
clientOutDir?: string;
|
|
5
5
|
cwd?: string;
|
|
6
|
+
configPath?: string;
|
|
7
|
+
srcRootRequired?: boolean;
|
|
8
|
+
logLevel?: LogLevelNames;
|
|
6
9
|
}): Promise<{
|
|
7
10
|
cwd: string;
|
|
8
11
|
port: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
srcRoot: string;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
config:
|
|
12
|
+
apiRoot: string;
|
|
13
|
+
apiDirAbsolutePath: string | null;
|
|
14
|
+
srcRoot: string | null;
|
|
15
|
+
vovkCliPackage: {
|
|
16
|
+
version: string;
|
|
17
|
+
};
|
|
18
|
+
config: import("vovk/types").VovkStrictConfig;
|
|
19
|
+
packageJson: import("type-fest").PackageJson;
|
|
20
|
+
isNextInstalled: boolean;
|
|
16
21
|
log: {
|
|
17
22
|
info: (msg: string) => void;
|
|
18
23
|
warn: (msg: string) => void;
|
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import getConfig from './getConfig.mjs';
|
|
3
|
-
import
|
|
4
|
-
|
|
2
|
+
import getConfig from './getConfig/index.mjs';
|
|
3
|
+
import { getPackageJson } from '../utils/getPackageJson.mjs';
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
export default async function getProjectInfo({ port: givenPort, cwd = process.cwd(), configPath, srcRootRequired = true, logLevel, } = {
|
|
6
|
+
logLevel: 'info',
|
|
7
|
+
}) {
|
|
5
8
|
const port = givenPort?.toString() ?? process.env.PORT ?? '3000';
|
|
6
9
|
// Make PORT available to the config file at getConfig
|
|
7
10
|
process.env.PORT = port;
|
|
8
|
-
const { config, srcRoot, configAbsolutePaths,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
11
|
+
const { config, srcRoot, configAbsolutePaths, log } = await getConfig({
|
|
12
|
+
configPath,
|
|
13
|
+
cwd,
|
|
14
|
+
logLevel,
|
|
15
|
+
});
|
|
16
|
+
const packageJson = await getPackageJson(cwd, log);
|
|
17
|
+
const isNextInstalled = !!packageJson?.dependencies?.next || !!packageJson?.devDependencies?.next;
|
|
18
|
+
if (srcRootRequired && !srcRoot) {
|
|
19
|
+
throw new Error(`Could not find app router directory at ${cwd}. Check Next.js docs for more info.`);
|
|
20
|
+
}
|
|
21
|
+
const apiRoot = `${config.generatorConfig.origin ?? ''}/${config.rootEntry}`;
|
|
22
|
+
const apiDirAbsolutePath = srcRoot ? path.resolve(cwd, srcRoot, 'app', config.rootEntry) : null;
|
|
19
23
|
if (configAbsolutePaths.length > 1) {
|
|
20
24
|
log.warn(`Multiple config files found. Using the first one: ${configAbsolutePaths[0]}`);
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
log.error(`Error reading config file at ${configAbsolutePaths[0]}: ${error?.message ?? 'Unknown Error'}`);
|
|
24
|
-
}
|
|
26
|
+
const vovkCliPackage = JSON.parse(await readFile(path.join(import.meta.dirname, '../../package.json'), 'utf-8'));
|
|
25
27
|
return {
|
|
26
28
|
cwd,
|
|
27
29
|
port,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
apiRoot,
|
|
31
|
+
apiDirAbsolutePath,
|
|
30
32
|
srcRoot,
|
|
31
|
-
|
|
32
|
-
fetcherClientImportPath,
|
|
33
|
-
validateOnClientImportPath,
|
|
33
|
+
vovkCliPackage,
|
|
34
34
|
config,
|
|
35
|
+
packageJson,
|
|
36
|
+
isNextInstalled,
|
|
35
37
|
log,
|
|
36
38
|
};
|
|
37
39
|
}
|
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,54 +1,69 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
|
+
import 'dotenv/config';
|
|
4
5
|
import { Command } from 'commander';
|
|
5
6
|
import concurrently from 'concurrently';
|
|
6
7
|
import getAvailablePort from './utils/getAvailablePort.mjs';
|
|
7
8
|
import getProjectInfo from './getProjectInfo/index.mjs';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
9
|
+
import { VovkGenerate } from './generate/index.mjs';
|
|
10
|
+
import { bundle } from './bundle/index.mjs';
|
|
10
11
|
import { VovkDev } from './dev/index.mjs';
|
|
11
|
-
import newComponents from './new/index.mjs';
|
|
12
|
-
import '
|
|
13
|
-
import
|
|
14
|
-
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { newComponents } from './new/index.mjs';
|
|
13
|
+
import { initProgram } from './initProgram.mjs';
|
|
14
|
+
import { getProjectFullSchema } from './generate/getProjectFullSchema.mjs';
|
|
15
15
|
const program = new Command();
|
|
16
|
-
const
|
|
17
|
-
program.name('vovk').description('Vovk CLI').version(
|
|
16
|
+
const vovkCliPackage = JSON.parse(readFileSync(path.join(import.meta.dirname, '../package.json'), 'utf-8'));
|
|
17
|
+
program.name('vovk').description('Vovk CLI').version(vovkCliPackage.version);
|
|
18
18
|
initProgram(program.command('init'));
|
|
19
19
|
program
|
|
20
20
|
.command('dev')
|
|
21
|
+
.alias('d')
|
|
21
22
|
.description('Start schema watcher (optional flag --next-dev to start it with Next.js)')
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.
|
|
23
|
+
.argument('[nextArgs...]', 'extra arguments for the dev command')
|
|
24
|
+
.option('--next-dev', 'start schema watcher and Next.js with automatic port allocation')
|
|
25
|
+
.option('--exit', 'kill the processes when schema and client is generated')
|
|
26
|
+
.option('--schema-out <path>', 'path to schema output directory (default: .vovk-schema)')
|
|
27
|
+
.option('--https, --dev-https', 'use HTTPS for the dev server (default: false)')
|
|
28
|
+
.option('--log-level <level>', 'set the log level')
|
|
29
|
+
.action(async (nextArgs, options) => {
|
|
30
|
+
const { nextDev, exit = false, schemaOut, devHttps, logLevel } = options;
|
|
25
31
|
const portAttempts = 30;
|
|
26
|
-
const PORT = !
|
|
32
|
+
const PORT = !nextDev
|
|
27
33
|
? process.env.PORT
|
|
28
34
|
: process.env.PORT ||
|
|
29
35
|
(await getAvailablePort(3000, portAttempts, 0, (failedPort, tryingPort) =>
|
|
30
36
|
// eslint-disable-next-line no-console
|
|
31
|
-
console.warn(`🐺
|
|
32
|
-
throw new Error(`🐺 ❌ Failed to find available
|
|
37
|
+
console.warn(`🐺 Port ${failedPort} is in use, trying ${tryingPort} instead.`)).catch(() => {
|
|
38
|
+
throw new Error(`🐺 ❌ Failed to find an available port after ${portAttempts} attempts`);
|
|
33
39
|
}));
|
|
34
40
|
if (!PORT) {
|
|
35
41
|
throw new Error('🐺 ❌ PORT env variable is required');
|
|
36
42
|
}
|
|
37
|
-
if (
|
|
43
|
+
if (nextDev) {
|
|
38
44
|
const { result } = concurrently([
|
|
39
45
|
{
|
|
40
|
-
command: `npx next dev ${
|
|
46
|
+
command: `npx next dev ${nextArgs.join(' ')}`,
|
|
41
47
|
name: 'Next.js Development Server',
|
|
42
48
|
env: { PORT },
|
|
43
49
|
},
|
|
44
50
|
{
|
|
45
51
|
command: `node ${import.meta.dirname}/dev/index.mjs`,
|
|
46
|
-
name: 'Vovk Dev
|
|
47
|
-
env: {
|
|
52
|
+
name: 'Vovk Dev Watcher',
|
|
53
|
+
env: {
|
|
54
|
+
PORT,
|
|
55
|
+
__VOVK_START_WATCHER_IN_STANDALONE_MODE__: 'true',
|
|
56
|
+
// TODO: Pass these as flags
|
|
57
|
+
__VOVK_SCHEMA_OUT_FLAG__: schemaOut ?? '',
|
|
58
|
+
__VOVK_DEV_HTTPS_FLAG__: devHttps ? 'true' : 'false',
|
|
59
|
+
__VOVK_EXIT__: exit ? 'true' : 'false',
|
|
60
|
+
__VOVK_LOG_LEVEL__: logLevel ?? undefined,
|
|
61
|
+
},
|
|
48
62
|
},
|
|
49
63
|
], {
|
|
50
|
-
|
|
64
|
+
killOthersOn: ['failure', 'success'],
|
|
51
65
|
prefix: 'none',
|
|
66
|
+
successCondition: 'first',
|
|
52
67
|
});
|
|
53
68
|
try {
|
|
54
69
|
await result;
|
|
@@ -58,32 +73,99 @@ program
|
|
|
58
73
|
}
|
|
59
74
|
}
|
|
60
75
|
else {
|
|
61
|
-
void new VovkDev().start();
|
|
76
|
+
void new VovkDev({ schemaOut, devHttps, logLevel }).start({ exit });
|
|
62
77
|
}
|
|
63
78
|
});
|
|
64
79
|
program
|
|
65
80
|
.command('generate')
|
|
66
|
-
.
|
|
67
|
-
.
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
.alias('g')
|
|
82
|
+
.description('Generate RPC client from schema')
|
|
83
|
+
.option('--composed-only', 'generate only composed client even if segmented client is enabled')
|
|
84
|
+
.option('--out, --composed-out <path>', 'path to output directory for composed client')
|
|
85
|
+
.option('--from, --composed-from <templates...>', 'client template names for composed client')
|
|
86
|
+
.option('--include, --composed-include-segments <segments...>', 'include segments in composed client')
|
|
87
|
+
.option('--exclude, --composed-exclude-segments <segments...>', 'exclude segments in composed client')
|
|
88
|
+
.option('--segmented-only', 'generate only segmented client even if composed client is enabled')
|
|
89
|
+
.option('--segmented-out <path>', 'path to output directory for segmented client')
|
|
90
|
+
.option('--segmented-from <templates...>', 'client template names for segmented client')
|
|
91
|
+
.option('--segmented-include-segments <segments...>', 'include segments in segmented client')
|
|
92
|
+
.option('--segmented-exclude-segments <segments...>', 'exclude segments in segmented client')
|
|
93
|
+
.option('--prettify', 'prettify output files')
|
|
94
|
+
.option('--schema, --schema-path <path>', 'path to schema folder (default: ./.vovk-schema)')
|
|
95
|
+
.option('--config, --config-path <config>', 'path to config file')
|
|
96
|
+
.option('--origin <url>', 'set the origin URL for the generated client')
|
|
97
|
+
.option('--watch <s>', 'watch for changes in schema or openapi spec and regenerate client; accepts a number in seconds to throttle the watcher or make an HTTP request to the OpenAPI spec URL')
|
|
98
|
+
.option('--openapi, --openapi-spec <openapi_path_or_urls...>', 'use OpenAPI schema for client generation')
|
|
99
|
+
.option('--openapi-get-module-name <names...>', 'module names corresponding to the index of --openapi option')
|
|
100
|
+
.option('--openapi-get-method-name <names...>', 'method names corresponding to the index of --openapi option')
|
|
101
|
+
.option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
|
|
102
|
+
.option('--openapi-mixin-name <names...>', 'mixin names corresponding to the index of --openapi option')
|
|
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')
|
|
105
|
+
.action(async (cliGenerateOptions) => {
|
|
106
|
+
const projectInfo = await getProjectInfo({
|
|
107
|
+
configPath: cliGenerateOptions.configPath,
|
|
108
|
+
srcRootRequired: false,
|
|
109
|
+
logLevel: cliGenerateOptions.logLevel,
|
|
110
|
+
});
|
|
111
|
+
await new VovkGenerate({
|
|
112
|
+
projectInfo,
|
|
113
|
+
forceNothingWrittenLog: true,
|
|
114
|
+
cliGenerateOptions,
|
|
115
|
+
}).start();
|
|
116
|
+
});
|
|
117
|
+
program
|
|
118
|
+
.command('bundle')
|
|
119
|
+
.alias('b')
|
|
120
|
+
.description('Generate TypeScript RPC and bundle it')
|
|
121
|
+
.option('--out, --out-dir <path>', 'path to output directory for bundle')
|
|
122
|
+
.option('--include, --include-segments <segments...>', 'include segments')
|
|
123
|
+
.option('--exclude, --exclude-segments <segments...>', 'exclude segments')
|
|
124
|
+
.option('--prebundle-out-dir, --prebundle-out <path>', 'path to output directory for prebundle')
|
|
125
|
+
.option('--keep-prebundle-dir', 'do not delete prebundle directory after bundling')
|
|
126
|
+
.option('--schema, --schema-path <path>', 'path to schema folder (default: .vovk-schema)')
|
|
127
|
+
.option('--config, --config-path <config>', 'path to config file')
|
|
128
|
+
.option('--origin <url>', 'set the origin URL for the generated client')
|
|
129
|
+
.option('--tsconfig <path>', 'path to tsconfig.json for bundling by tsdown')
|
|
130
|
+
.option('--openapi, --openapi-spec <openapi_path_or_urls...>', 'use OpenAPI schema instead of Vovk schema')
|
|
131
|
+
.option('--openapi-get-module-name <names...>', 'module names corresponding to the index of --openapi option')
|
|
132
|
+
.option('--openapi-get-method-name <names...>', 'method names corresponding to the index of --openapi option')
|
|
133
|
+
.option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
|
|
134
|
+
.option('--log-level <level>', 'set the log level')
|
|
135
|
+
.action(async (cliBundleOptions) => {
|
|
136
|
+
const projectInfo = await getProjectInfo({
|
|
137
|
+
configPath: cliBundleOptions.configPath,
|
|
138
|
+
srcRootRequired: false,
|
|
139
|
+
logLevel: cliBundleOptions.logLevel,
|
|
140
|
+
});
|
|
141
|
+
const { cwd, config, log, isNextInstalled } = projectInfo;
|
|
142
|
+
const fullSchema = await getProjectFullSchema({
|
|
143
|
+
schemaOutAbsolutePath: path.resolve(cwd, cliBundleOptions?.schema ?? config.schemaOutDir),
|
|
144
|
+
log,
|
|
145
|
+
isNextInstalled,
|
|
146
|
+
config,
|
|
147
|
+
});
|
|
148
|
+
await bundle({
|
|
149
|
+
projectInfo,
|
|
150
|
+
fullSchema,
|
|
151
|
+
cliBundleOptions,
|
|
152
|
+
});
|
|
76
153
|
});
|
|
77
154
|
program
|
|
78
155
|
.command('new [components...]')
|
|
79
156
|
.alias('n')
|
|
80
157
|
.description('Create new components. "vovk new [...components] [segmentName/]moduleName" to create a new module or "vovk new segment [segmentName]" to create a new segment')
|
|
81
|
-
.option('-o, --overwrite', '
|
|
82
|
-
.option('--template, --templates <templates...>', '
|
|
83
|
-
.option('--dir <dirname>', '
|
|
84
|
-
.option('--
|
|
85
|
-
.option('--
|
|
86
|
-
.
|
|
158
|
+
.option('-o, --overwrite', 'overwrite existing files')
|
|
159
|
+
.option('--template, --templates <templates...>', 'override config template; accepts an array of strings that correspond the order of the components')
|
|
160
|
+
.option('--dir <dirname>', 'override dirName in template file; relative to the root of the project')
|
|
161
|
+
.option('--empty', 'create an empty module')
|
|
162
|
+
.option('--no-segment-update', 'do not update segment files when creating a new module')
|
|
163
|
+
.option('--dry-run', 'do not write files to disk')
|
|
164
|
+
.option('--static', 'if the segment is static')
|
|
165
|
+
.option('--log-level <level>', 'set the log level')
|
|
166
|
+
.action(async (components, newOptions) => newComponents(components, await getProjectInfo({
|
|
167
|
+
logLevel: newOptions.logLevel,
|
|
168
|
+
}), newOptions));
|
|
87
169
|
program
|
|
88
170
|
.command('help')
|
|
89
171
|
.description('Show help message')
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type getLogger from '../utils/getLogger.mjs';
|
|
2
2
|
import type { InitOptions } from '../types.mjs';
|
|
3
|
-
export default function createConfig({ root, log, options: { validationLibrary,
|
|
3
|
+
export default function createConfig({ root, log, options: { validationLibrary, lang, channel, dryRun }, }: {
|
|
4
4
|
root: string;
|
|
5
5
|
log: ReturnType<typeof getLogger>;
|
|
6
|
-
options: Pick<InitOptions, 'validationLibrary' | '
|
|
6
|
+
options: Pick<InitOptions, 'validationLibrary' | 'lang' | 'channel' | 'dryRun'>;
|
|
7
7
|
}): Promise<{
|
|
8
8
|
configAbsolutePath: string;
|
|
9
9
|
}>;
|
|
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import getTemplateFilesFromPackage from './getTemplateFilesFromPackage.mjs';
|
|
4
4
|
import prettify from '../utils/prettify.mjs';
|
|
5
5
|
import getFileSystemEntryType, { FileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
|
|
6
|
-
export default async function createConfig({ root, log, options: { validationLibrary,
|
|
6
|
+
export default async function createConfig({ root, log, options: { validationLibrary, lang, channel, dryRun }, }) {
|
|
7
7
|
const config = {};
|
|
8
8
|
const dotConfigPath = path.join(root, '.config');
|
|
9
9
|
const dir = (await getFileSystemEntryType(dotConfigPath)) === FileSystemEntryType.DIRECTORY ? dotConfigPath : root;
|
|
@@ -11,26 +11,52 @@ 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
|
|
15
|
-
controller: 'vovk-cli/templates/controller.ejs',
|
|
16
|
-
service: 'vovk-cli/templates/service.ejs',
|
|
17
|
-
worker: 'vovk-cli/templates/worker.ejs',
|
|
14
|
+
const typeTemplates = {
|
|
15
|
+
controller: 'vovk-cli/module-templates/type/controller.ts.ejs',
|
|
16
|
+
service: 'vovk-cli/module-templates/type/service.ts.ejs',
|
|
18
17
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
const moduleTemplates = {
|
|
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'],
|
|
38
|
+
};
|
|
39
|
+
config.generatorConfig ??= {};
|
|
40
|
+
config.generatorConfig.imports ??= {};
|
|
41
|
+
config.generatorConfig.imports.validateOnClient =
|
|
42
|
+
validationLibrary === 'class-validator' ? 'vovk-dto/validateOnClient' : 'vovk-ajv';
|
|
43
|
+
if (validationLibrary && !moduleTemplates) {
|
|
24
44
|
try {
|
|
45
|
+
// TODO: Legacy, is it useful to keep it?
|
|
25
46
|
const validationTemplates = await getTemplateFilesFromPackage(validationLibrary, channel);
|
|
26
|
-
Object.assign(
|
|
47
|
+
Object.assign(moduleTemplates, validationTemplates);
|
|
27
48
|
}
|
|
28
49
|
catch (error) {
|
|
29
50
|
log.warn(`Failed to fetch validation library templates: ${error.message}`);
|
|
30
51
|
}
|
|
31
52
|
}
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
if (lang?.length) {
|
|
54
|
+
config.composedClient ??= {};
|
|
55
|
+
config.composedClient.fromTemplates = ['mjs', 'cjs', ...lang];
|
|
56
|
+
}
|
|
57
|
+
config.moduleTemplates = moduleTemplates;
|
|
58
|
+
const configStr = await prettify(`// @ts-check
|
|
59
|
+
/** @type {import('vovk').VovkConfig} */
|
|
34
60
|
const config = ${JSON.stringify(config, null, 2)};
|
|
35
61
|
${isModule ? '\nexport default config;' : 'module.exports = config;'}`, configAbsolutePath);
|
|
36
62
|
if (!dryRun)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import getRelativeSrcRoot from '../getProjectInfo/getConfig/getRelativeSrcRoot.mjs';
|
|
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({ root, validationLibrary, }) {
|
|
33
|
+
const code = getCode(validationLibrary);
|
|
34
|
+
const srcRoot = (await getRelativeSrcRoot({ cwd: root })) ?? '.';
|
|
35
|
+
const libDir = path.resolve(root, srcRoot, 'lib');
|
|
36
|
+
const filePath = path.join(libDir, `${validationLibrary === 'arktype' ? 'withArk' : 'withValibot'}.ts`);
|
|
37
|
+
await fs.mkdir(libDir, { recursive: true });
|
|
38
|
+
await fs.writeFile(filePath, code);
|
|
39
|
+
}
|