vovk-cli 0.0.1-draft.39 → 0.0.1-draft.392
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 +31 -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 +19 -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 +24 -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 +28 -0
- package/client-templates/ts/index.ts.ejs +33 -0
- package/dist/bundle/index.d.mts +8 -0
- package/dist/bundle/index.mjs +74 -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 +141 -66
- 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 +300 -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 +66 -0
- package/dist/generate/getTemplateClientImports.d.mts +21 -0
- package/dist/generate/getTemplateClientImports.mjs +56 -0
- package/dist/generate/index.d.mts +33 -0
- package/dist/generate/index.mjs +186 -0
- package/dist/generate/writeOneClientFile.d.mts +42 -0
- package/dist/generate/writeOneClientFile.mjs +151 -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 +91 -0
- package/dist/getProjectInfo/getConfig/index.mjs +92 -0
- package/dist/getProjectInfo/getMetaSchema.d.mts +8 -0
- package/dist/getProjectInfo/getMetaSchema.mjs +27 -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 +116 -35
- package/dist/init/createConfig.d.mts +2 -2
- package/dist/init/createConfig.mjs +40 -13
- package/dist/init/createStandardSchemaValidatorFile.d.mts +4 -0
- package/dist/init/createStandardSchemaValidatorFile.mjs +52 -0
- package/dist/init/getTemplateFilesFromPackage.mjs +10 -5
- package/dist/init/index.d.mts +2 -2
- package/dist/init/index.mjs +121 -72
- 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.mjs +1 -1
- 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 +5 -3
- package/dist/new/newModule.d.mts +5 -2
- package/dist/new/newModule.mjs +26 -24
- package/dist/new/newSegment.d.mts +4 -1
- package/dist/new/newSegment.mjs +20 -12
- package/dist/new/render.d.mts +7 -3
- package/dist/new/render.mjs +31 -10
- package/dist/types.d.mts +66 -44
- 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 +1 -1
- package/dist/utils/deepExtend.d.mts +54 -0
- package/dist/utils/deepExtend.mjs +129 -0
- 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 +78 -0
- package/module-templates/type/controller.ts.ejs +64 -0
- package/module-templates/type/service.ts.ejs +37 -0
- package/module-templates/valibot/controller.ts.ejs +78 -0
- package/package.json +39 -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,52 @@
|
|
|
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 } from 'vovk';
|
|
8
|
+
import { toJsonSchema } from '@valibot/to-json-schema';
|
|
9
|
+
|
|
10
|
+
const withValibot = createStandardValidation({
|
|
11
|
+
toJSONSchema: (model) => toJsonSchema(model, {
|
|
12
|
+
overrideSchema(context) {
|
|
13
|
+
if (context.valibotSchema.type === 'file') {
|
|
14
|
+
return { type: 'string', format: 'binary' };
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default withValibot;
|
|
21
|
+
`.trimStart();
|
|
22
|
+
}
|
|
23
|
+
if (validationLibrary === 'arktype') {
|
|
24
|
+
return `
|
|
25
|
+
import { createStandardValidation } from 'vovk';
|
|
26
|
+
import type { type } from 'arktype';
|
|
27
|
+
|
|
28
|
+
const withArk = createStandardValidation({
|
|
29
|
+
toJSONSchema: (model: type) => model.toJsonSchema({
|
|
30
|
+
fallback: {
|
|
31
|
+
proto: (ctx) => ctx.proto === File ? {
|
|
32
|
+
type: "string",
|
|
33
|
+
format: "binary",
|
|
34
|
+
} : ctx.base,
|
|
35
|
+
default: (ctx) => ctx.base
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export default withArk;
|
|
41
|
+
`.trimStart();
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`Unknown validation library: ${validationLibrary}`);
|
|
44
|
+
}
|
|
45
|
+
export async function createStandardSchemaValidatorFile({ root, validationLibrary, }) {
|
|
46
|
+
const code = getCode(validationLibrary);
|
|
47
|
+
const srcRoot = (await getRelativeSrcRoot({ cwd: root })) ?? '.';
|
|
48
|
+
const libDir = path.resolve(root, srcRoot, 'lib');
|
|
49
|
+
const filePath = path.join(libDir, `${validationLibrary === 'arktype' ? 'withArk' : 'withValibot'}.ts`);
|
|
50
|
+
await fs.mkdir(libDir, { recursive: true });
|
|
51
|
+
await fs.writeFile(filePath, code);
|
|
52
|
+
}
|
|
@@ -2,7 +2,6 @@ import { Readable } from 'node:stream';
|
|
|
2
2
|
import { createGunzip } from 'node:zlib';
|
|
3
3
|
import tar from 'tar-stream';
|
|
4
4
|
import getNPMPackageMetadata from '../utils/getNPMPackageMetadata.mjs';
|
|
5
|
-
// Crereated with AI
|
|
6
5
|
/**
|
|
7
6
|
* Retrieves a list of files in the 'templates' folder of an NPM package.
|
|
8
7
|
* @param packageName - The name of the NPM package.
|
|
@@ -22,8 +21,14 @@ export default async function getTemplateFilesFromPackage(packageName, channel =
|
|
|
22
21
|
// Extract the tarball in memory and collect template files
|
|
23
22
|
const templateFiles = await extractTemplatesFromTarball(tarballBuffer);
|
|
24
23
|
const entries = templateFiles
|
|
25
|
-
.filter((fileName) => fileName.startsWith('templates/') && !fileName.endsWith('/') && fileName.endsWith('.ejs'))
|
|
26
|
-
.map((fileName) => [
|
|
24
|
+
.filter((fileName) => fileName.startsWith('module-templates/') && !fileName.endsWith('/') && fileName.endsWith('.ts.ejs'))
|
|
25
|
+
.map((fileName) => [
|
|
26
|
+
fileName
|
|
27
|
+
.substring('module-templates/'.length)
|
|
28
|
+
.replace(/\.ts\.ejs$/, '')
|
|
29
|
+
.toLowerCase(),
|
|
30
|
+
`${packageName}/${fileName}`,
|
|
31
|
+
]);
|
|
27
32
|
return Object.fromEntries(entries);
|
|
28
33
|
}
|
|
29
34
|
/**
|
|
@@ -37,8 +42,8 @@ function extractTemplatesFromTarball(tarballBuffer) {
|
|
|
37
42
|
const files = [];
|
|
38
43
|
extract.on('entry', (header, stream, next) => {
|
|
39
44
|
const filePath = header.name;
|
|
40
|
-
// Check if the file is in the 'templates' folder
|
|
41
|
-
if (filePath.startsWith('package/templates/')) {
|
|
45
|
+
// Check if the file is in the 'module-templates' folder
|
|
46
|
+
if (filePath.startsWith('package/module-templates/')) {
|
|
42
47
|
files.push(filePath.replace('package/', ''));
|
|
43
48
|
}
|
|
44
49
|
stream.on('end', () => next());
|
package/dist/init/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { InitOptions } from '../types.mjs';
|
|
2
1
|
import getLogger from '../utils/getLogger.mjs';
|
|
2
|
+
import type { InitOptions } from '../types.mjs';
|
|
3
3
|
export declare class Init {
|
|
4
4
|
#private;
|
|
5
5
|
root: string;
|
|
6
6
|
log: ReturnType<typeof getLogger>;
|
|
7
|
-
main(prefix
|
|
7
|
+
main({ prefix, yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }: InitOptions): Promise<void>;
|
|
8
8
|
}
|
package/dist/init/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { confirm, select } from '@inquirer/prompts';
|
|
1
|
+
import { confirm, select, checkbox } from '@inquirer/prompts';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import fs from 'node:fs/promises';
|
|
4
|
-
import getConfigPaths from '../getProjectInfo/getConfigAbsolutePaths.mjs';
|
|
5
4
|
import chalk from 'chalk';
|
|
5
|
+
import NPMCliPackageJson from '@npmcli/package-json';
|
|
6
|
+
import getConfigPaths from '../getProjectInfo/getConfig/getConfigAbsolutePaths.mjs';
|
|
6
7
|
import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
|
|
7
8
|
import installDependencies, { getPackageManager } from './installDependencies.mjs';
|
|
8
9
|
import getLogger from '../utils/getLogger.mjs';
|
|
@@ -13,30 +14,43 @@ import updateTypeScriptConfig from './updateTypeScriptConfig.mjs';
|
|
|
13
14
|
import updateDependenciesWithoutInstalling from './updateDependenciesWithoutInstalling.mjs';
|
|
14
15
|
import logUpdateDependenciesError from './logUpdateDependenciesError.mjs';
|
|
15
16
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
16
|
-
import
|
|
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,
|
|
21
|
+
async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
|
|
21
22
|
const { log, root } = this;
|
|
22
|
-
const dependencies = ['vovk', 'vovk-client'];
|
|
23
|
+
const dependencies = ['vovk', 'vovk-client', 'vovk-ajv'];
|
|
23
24
|
const devDependencies = ['vovk-cli'];
|
|
25
|
+
if (lang?.includes('py')) {
|
|
26
|
+
devDependencies.push('vovk-python');
|
|
27
|
+
}
|
|
28
|
+
if (lang?.includes('rs')) {
|
|
29
|
+
devDependencies.push('vovk-rust');
|
|
30
|
+
}
|
|
24
31
|
// delete older config files
|
|
25
32
|
if (configPaths.length) {
|
|
26
33
|
await Promise.all(configPaths.map((configPath) => fs.rm(configPath)));
|
|
27
34
|
log.debug(`Deleted existing config file${configPaths.length > 1 ? 's' : ''} at ${configPaths.join(', ')}`);
|
|
28
35
|
}
|
|
29
36
|
if (validationLibrary) {
|
|
30
|
-
dependencies.push(validationLibrary);
|
|
31
37
|
dependencies.push(...({
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
|
|
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'],
|
|
35
49
|
}[validationLibrary] ?? []));
|
|
36
50
|
}
|
|
37
51
|
if (updateScripts) {
|
|
38
52
|
try {
|
|
39
|
-
if (!dryRun)
|
|
53
|
+
if (!dryRun && pkgJson)
|
|
40
54
|
await updateNPMScripts(pkgJson, root, updateScripts);
|
|
41
55
|
log.info('Updated scripts at package.json');
|
|
42
56
|
}
|
|
@@ -49,15 +63,23 @@ export class Init {
|
|
|
49
63
|
}
|
|
50
64
|
if (updateTsConfig) {
|
|
51
65
|
try {
|
|
66
|
+
const compilerOptions = {
|
|
67
|
+
experimentalDecorators: true,
|
|
68
|
+
};
|
|
69
|
+
if (validationLibrary === 'class-validator') {
|
|
70
|
+
compilerOptions.emitDecoratorMetadata = true;
|
|
71
|
+
}
|
|
52
72
|
if (!dryRun)
|
|
53
|
-
await updateTypeScriptConfig(root);
|
|
54
|
-
log.info(
|
|
73
|
+
await updateTypeScriptConfig(root, compilerOptions);
|
|
74
|
+
log.info(`Added ${Object.keys(compilerOptions)
|
|
75
|
+
.map((k) => `"${k}"`)
|
|
76
|
+
.join(' and ')} to tsconfig.json`);
|
|
55
77
|
}
|
|
56
78
|
catch (error) {
|
|
57
79
|
log.error(`Failed to update tsconfig.json: ${error.message}`);
|
|
58
80
|
}
|
|
59
81
|
}
|
|
60
|
-
if (!dryRun) {
|
|
82
|
+
if (!dryRun && pkgJson) {
|
|
61
83
|
let depsUpdated = false;
|
|
62
84
|
try {
|
|
63
85
|
await updateDependenciesWithoutInstalling({
|
|
@@ -71,7 +93,17 @@ export class Init {
|
|
|
71
93
|
}
|
|
72
94
|
catch (e) {
|
|
73
95
|
const error = e;
|
|
74
|
-
logUpdateDependenciesError({
|
|
96
|
+
logUpdateDependenciesError({
|
|
97
|
+
log,
|
|
98
|
+
error,
|
|
99
|
+
useNpm,
|
|
100
|
+
useYarn,
|
|
101
|
+
usePnpm,
|
|
102
|
+
useBun,
|
|
103
|
+
dependencies,
|
|
104
|
+
devDependencies,
|
|
105
|
+
channel,
|
|
106
|
+
});
|
|
75
107
|
}
|
|
76
108
|
if (depsUpdated) {
|
|
77
109
|
const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun });
|
|
@@ -93,33 +125,40 @@ export class Init {
|
|
|
93
125
|
log.info('Dependencies installed successfully');
|
|
94
126
|
}
|
|
95
127
|
catch (error) {
|
|
96
|
-
log.warn(`Failed to install dependencies
|
|
128
|
+
log.warn(`Failed to install dependencies. ${error.message}. Please, install them manually with ${chalkHighlightThing(packageManager + ' install')}`);
|
|
97
129
|
}
|
|
98
130
|
}
|
|
99
131
|
}
|
|
100
132
|
}
|
|
133
|
+
if (validationLibrary === 'valibot' || validationLibrary === 'arktype') {
|
|
134
|
+
createStandardSchemaValidatorFile({
|
|
135
|
+
root,
|
|
136
|
+
validationLibrary,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
101
139
|
try {
|
|
102
140
|
const { configAbsolutePath } = await createConfig({
|
|
103
141
|
root,
|
|
104
142
|
log,
|
|
105
|
-
options: { validationLibrary,
|
|
143
|
+
options: { validationLibrary, channel, lang, dryRun },
|
|
106
144
|
});
|
|
107
|
-
log.info('Config created successfully at ' + configAbsolutePath);
|
|
145
|
+
log.info('Config created successfully at ' + chalkHighlightThing(configAbsolutePath));
|
|
108
146
|
}
|
|
109
147
|
catch (error) {
|
|
110
148
|
log.error(`Failed to create config: ${error.message}`);
|
|
111
149
|
}
|
|
112
150
|
}
|
|
113
|
-
async main(prefix,
|
|
151
|
+
async main({ prefix, yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
|
|
114
152
|
const cwd = process.cwd();
|
|
115
|
-
const root = path.resolve(cwd, prefix);
|
|
116
|
-
const log = getLogger(logLevel);
|
|
117
|
-
const pkgJson = await NPMCliPackageJson.load(root);
|
|
153
|
+
const root = path.resolve(cwd, prefix ?? '.');
|
|
154
|
+
const log = getLogger(logLevel ?? 'info');
|
|
155
|
+
const pkgJson = await NPMCliPackageJson.load(root).catch(() => null);
|
|
118
156
|
this.root = root;
|
|
119
157
|
this.log = log;
|
|
120
158
|
const configPaths = await getConfigPaths({ cwd, relativePath: prefix });
|
|
121
159
|
if (yes) {
|
|
122
|
-
return this.#init({ configPaths, pkgJson }, {
|
|
160
|
+
return this.#init({ configPaths, pkgJson, cwd }, {
|
|
161
|
+
prefix: prefix ?? '.',
|
|
123
162
|
useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
|
|
124
163
|
useYarn: useYarn ?? false,
|
|
125
164
|
usePnpm: usePnpm ?? false,
|
|
@@ -127,17 +166,18 @@ export class Init {
|
|
|
127
166
|
skipInstall: skipInstall ?? false,
|
|
128
167
|
updateTsConfig: updateTsConfig ?? true,
|
|
129
168
|
updateScripts: updateScripts ?? 'implicit',
|
|
130
|
-
validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? '
|
|
131
|
-
validateOnClient: validateOnClient ?? true,
|
|
169
|
+
validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'zod'),
|
|
132
170
|
dryRun: dryRun ?? false,
|
|
133
171
|
channel: channel ?? 'latest',
|
|
172
|
+
lang: lang ?? [],
|
|
134
173
|
});
|
|
135
174
|
}
|
|
136
175
|
if (!(await getFileSystemEntryType(path.join(root, 'package.json')))) {
|
|
137
|
-
|
|
176
|
+
log.warn(`${chalkHighlightThing('package.json')} not found at ${chalkHighlightThing(root)}. Run "npx create-next-app" to create a new Next.js project
|
|
177
|
+
.`);
|
|
138
178
|
}
|
|
139
|
-
if (!(await getFileSystemEntryType(path.join(root, 'tsconfig.json')))) {
|
|
140
|
-
|
|
179
|
+
else if (pkgJson && !(await getFileSystemEntryType(path.join(root, 'tsconfig.json')))) {
|
|
180
|
+
log.warn(`${chalkHighlightThing('tsconfig.json')} not found at ${chalkHighlightThing(root)}. Run "npx tsc --init" to create a new tsconfig.json file.`);
|
|
141
181
|
}
|
|
142
182
|
if (configPaths.length) {
|
|
143
183
|
if (!(await confirm({
|
|
@@ -151,71 +191,80 @@ export class Init {
|
|
|
151
191
|
: (validationLibrary ??
|
|
152
192
|
(await select({
|
|
153
193
|
message: 'Choose validation library',
|
|
154
|
-
default: '
|
|
194
|
+
default: 'zod',
|
|
155
195
|
choices: [
|
|
156
196
|
{
|
|
157
|
-
name: '
|
|
158
|
-
value: '
|
|
197
|
+
name: 'Zod',
|
|
198
|
+
value: 'zod',
|
|
159
199
|
description: 'Use Zod for data validation',
|
|
160
200
|
},
|
|
161
201
|
{
|
|
162
|
-
name: '
|
|
163
|
-
value: '
|
|
164
|
-
description: 'Use
|
|
202
|
+
name: 'class-validator',
|
|
203
|
+
value: 'class-validator',
|
|
204
|
+
description: 'Use class-validator for data validation',
|
|
165
205
|
},
|
|
166
206
|
{
|
|
167
|
-
name: '
|
|
168
|
-
value: '
|
|
169
|
-
description: 'Use
|
|
207
|
+
name: 'ArkType',
|
|
208
|
+
value: 'arktype',
|
|
209
|
+
description: 'Use ArkType for data validation.',
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: 'Valibot',
|
|
213
|
+
value: 'valibot',
|
|
214
|
+
description: 'Use Valibot for data validation.',
|
|
170
215
|
},
|
|
171
216
|
{ name: 'None', value: null, description: 'Install validation library later' },
|
|
172
217
|
],
|
|
173
218
|
})));
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
name: 'No',
|
|
199
|
-
value: undefined,
|
|
200
|
-
description: 'Add the NPM scripts manually',
|
|
201
|
-
},
|
|
202
|
-
],
|
|
203
|
-
}));
|
|
204
|
-
if (typeof updateTsConfig === 'undefined') {
|
|
219
|
+
updateScripts ??= !pkgJson
|
|
220
|
+
? undefined
|
|
221
|
+
: await select({
|
|
222
|
+
message: 'Do you want to update "dev" and add "prebuild" NPM scripts at package.json?',
|
|
223
|
+
default: 'implicit',
|
|
224
|
+
choices: [
|
|
225
|
+
{
|
|
226
|
+
name: 'Yes, use "concurrently" implicitly',
|
|
227
|
+
value: 'implicit',
|
|
228
|
+
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"`,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'Yes, use "concurrently" explicitly',
|
|
232
|
+
value: 'explicit',
|
|
233
|
+
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"`,
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: 'No',
|
|
237
|
+
value: undefined,
|
|
238
|
+
description: 'Add the NPM scripts manually',
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
});
|
|
242
|
+
if (typeof updateTsConfig === 'undefined' && pkgJson) {
|
|
205
243
|
let shouldAsk = false;
|
|
206
244
|
try {
|
|
207
|
-
shouldAsk = !(await checkTSConfigForExperimentalDecorators(root));
|
|
245
|
+
shouldAsk = !(await checkTSConfigForExperimentalDecorators(root)); // TODO also check for emitDecoratorMetadata when vovk-dto is used
|
|
208
246
|
}
|
|
209
247
|
catch (error) {
|
|
210
|
-
log.error(`Failed to check tsconfig.json for experimentalDecorators: ${error.message}`);
|
|
248
|
+
log.error(`Failed to check tsconfig.json for "experimentalDecorators": ${error.message}`);
|
|
211
249
|
}
|
|
212
250
|
if (shouldAsk) {
|
|
251
|
+
const keys = ['experimentalDecorators'];
|
|
252
|
+
if (validationLibrary === 'class-validator') {
|
|
253
|
+
keys.push('emitDecoratorMetadata');
|
|
254
|
+
}
|
|
213
255
|
updateTsConfig = await confirm({
|
|
214
|
-
message:
|
|
256
|
+
message: `Do you want to add ${keys.map((k) => `"${k}"`).join(' and ')} to tsconfig.json? (recommended)`,
|
|
215
257
|
});
|
|
216
258
|
}
|
|
217
259
|
}
|
|
218
|
-
await
|
|
260
|
+
lang ??= await checkbox({
|
|
261
|
+
message: 'Do you want to generate RPC client for other languages besides TypeScript (experimental)?',
|
|
262
|
+
choices: [
|
|
263
|
+
{ name: 'Python', value: 'py' },
|
|
264
|
+
{ name: 'Rust', value: 'rs' },
|
|
265
|
+
],
|
|
266
|
+
});
|
|
267
|
+
await this.#init({ configPaths, pkgJson, cwd }, {
|
|
219
268
|
useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
|
|
220
269
|
useYarn: useYarn ?? false,
|
|
221
270
|
usePnpm: usePnpm ?? false,
|
|
@@ -224,7 +273,7 @@ export class Init {
|
|
|
224
273
|
updateTsConfig,
|
|
225
274
|
updateScripts,
|
|
226
275
|
validationLibrary,
|
|
227
|
-
|
|
276
|
+
lang,
|
|
228
277
|
dryRun,
|
|
229
278
|
channel,
|
|
230
279
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
2
3
|
export function getPackageManager(options) {
|
|
3
4
|
if (options.useNpm)
|
|
4
5
|
return 'npm';
|
|
@@ -12,9 +13,10 @@ export function getPackageManager(options) {
|
|
|
12
13
|
}
|
|
13
14
|
export default async function installDependencies({ log, cwd, options, }) {
|
|
14
15
|
const packageManager = getPackageManager(options);
|
|
15
|
-
log.info(`Installing dependencies at ${cwd} using ${packageManager}...`);
|
|
16
|
+
log.info(`Installing dependencies at ${chalkHighlightThing(cwd)} using ${chalkHighlightThing(packageManager)}...`);
|
|
16
17
|
await new Promise((resolve, reject) => {
|
|
17
|
-
const
|
|
18
|
+
const args = packageManager === 'yarn' ? ['install', '--non-interactive'] : ['install'];
|
|
19
|
+
const child = spawn(packageManager, args, { cwd, stdio: 'inherit' });
|
|
18
20
|
child.on('close', (code) => {
|
|
19
21
|
if (code === 0) {
|
|
20
22
|
resolve();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { InitOptions } from '../types.mjs';
|
|
1
2
|
import type getLogger from '../utils/getLogger.mjs';
|
|
2
|
-
export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, }: {
|
|
3
|
+
export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, channel, }: {
|
|
3
4
|
useNpm?: boolean;
|
|
4
5
|
useYarn?: boolean;
|
|
5
6
|
usePnpm?: boolean;
|
|
@@ -8,4 +9,5 @@ export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, u
|
|
|
8
9
|
dependencies: string[];
|
|
9
10
|
devDependencies: string[];
|
|
10
11
|
error: Error;
|
|
12
|
+
channel: InitOptions['channel'];
|
|
11
13
|
}): void;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
2
2
|
import { getPackageManager } from './installDependencies.mjs';
|
|
3
|
-
export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, }) {
|
|
3
|
+
export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, channel, }) {
|
|
4
4
|
const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun });
|
|
5
5
|
const installCommands = [];
|
|
6
|
+
const addChannel = (packageName) => {
|
|
7
|
+
const isVovk = packageName.startsWith('vovk') && packageName !== 'dto-mapped-types';
|
|
8
|
+
return isVovk ? (!channel || channel !== 'latest' ? `${packageName}@${channel}` : packageName) : packageName;
|
|
9
|
+
};
|
|
10
|
+
dependencies = dependencies.map(addChannel);
|
|
11
|
+
devDependencies = devDependencies.map(addChannel);
|
|
6
12
|
if (dependencies.length > 0) {
|
|
7
13
|
let depInstallCmd = '';
|
|
8
14
|
switch (packageManager) {
|
|
@@ -2,22 +2,52 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import getNPMPackageMetadata from '../utils/getNPMPackageMetadata.mjs';
|
|
5
|
-
async function updateDeps({ packageJson, packageNames, channel, key, }) {
|
|
5
|
+
async function updateDeps({ packageJson, packageNames, channel, key, log, }) {
|
|
6
6
|
return Promise.all(packageNames.map(async (packageName) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
let name;
|
|
8
|
+
let version;
|
|
9
|
+
if (packageName.startsWith('@')) {
|
|
10
|
+
// Handle scoped packages (@org/name@version)
|
|
11
|
+
const lastAtIndex = packageName.lastIndexOf('@');
|
|
12
|
+
if (lastAtIndex > 0) {
|
|
13
|
+
name = packageName.substring(0, lastAtIndex);
|
|
14
|
+
version = packageName.substring(lastAtIndex + 1);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
name = packageName;
|
|
18
|
+
version = undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
// Handle regular packages (name@version)
|
|
23
|
+
const parts = packageName.split('@');
|
|
24
|
+
name = parts[0];
|
|
25
|
+
version = parts[1];
|
|
26
|
+
}
|
|
27
|
+
if (version) {
|
|
28
|
+
packageJson[key] ??= {};
|
|
29
|
+
packageJson[key][name] = version;
|
|
30
|
+
return;
|
|
12
31
|
}
|
|
13
|
-
|
|
32
|
+
let metadata;
|
|
33
|
+
try {
|
|
34
|
+
metadata = await getNPMPackageMetadata(name);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
log.error(`Failed to fetch metadata for package ${name}@${channel ?? 'latest'}: ${error}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const isVovk = name.startsWith('vovk') && name !== 'dto-mapped-types';
|
|
41
|
+
const latestVersion = metadata['dist-tags'][isVovk ? (channel ?? 'latest') : 'latest'];
|
|
42
|
+
packageJson[key] ??= {};
|
|
43
|
+
packageJson[key][name] = `^${latestVersion}`;
|
|
14
44
|
}));
|
|
15
45
|
}
|
|
16
46
|
export default async function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }) {
|
|
17
47
|
const packageJsonPath = path.join(dir, 'package.json');
|
|
18
48
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
19
|
-
await updateDeps({ packageJson, packageNames: dependencyNames, channel, key: 'dependencies' });
|
|
20
|
-
await updateDeps({ packageJson, packageNames: devDependencyNames, channel, key: 'devDependencies' });
|
|
49
|
+
await updateDeps({ packageJson, packageNames: dependencyNames, channel, log, key: 'dependencies' });
|
|
50
|
+
await updateDeps({ packageJson, packageNames: devDependencyNames, channel, log, key: 'devDependencies' });
|
|
21
51
|
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
22
52
|
log.info('Added dependencies to package.json:');
|
|
23
53
|
for (const dependency of dependencyNames) {
|
|
@@ -9,8 +9,8 @@ export default async function updateNPMScripts(pkgJson, root, updateScriptsMode)
|
|
|
9
9
|
pkgJson.update({
|
|
10
10
|
scripts: {
|
|
11
11
|
...pkgJson.content.scripts,
|
|
12
|
-
generate: 'vovk generate',
|
|
13
12
|
dev: getDevScript(pkgJson, updateScriptsMode),
|
|
13
|
+
prebuild: 'vovk generate',
|
|
14
14
|
},
|
|
15
15
|
});
|
|
16
16
|
await pkgJson.save();
|
|
@@ -2,14 +2,18 @@ import path from 'node:path';
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import * as jsonc from 'jsonc-parser';
|
|
4
4
|
import prettify from '../utils/prettify.mjs';
|
|
5
|
-
export default async function updateTypeScriptConfig(root) {
|
|
5
|
+
export default async function updateTypeScriptConfig(root, compilerOptions) {
|
|
6
6
|
const tsconfigPath = path.join(root, 'tsconfig.json');
|
|
7
7
|
const tsconfigContent = await fs.readFile(tsconfigPath, 'utf8');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
let updatedContent = tsconfigContent;
|
|
9
|
+
// Apply each compiler option
|
|
10
|
+
for (const [key, value] of Object.entries(compilerOptions)) {
|
|
11
|
+
const edits = jsonc.modify(updatedContent, ['compilerOptions', key], value, {
|
|
12
|
+
formattingOptions: {},
|
|
13
|
+
});
|
|
14
|
+
updatedContent = jsonc.applyEdits(updatedContent, edits);
|
|
15
|
+
}
|
|
16
|
+
// Prettify the final content
|
|
17
|
+
updatedContent = await prettify(updatedContent, tsconfigPath);
|
|
14
18
|
await fs.writeFile(tsconfigPath, updatedContent, 'utf8');
|
|
15
19
|
}
|
package/dist/initProgram.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
export
|
|
2
|
+
export declare function initProgram(program: Command): Command;
|
package/dist/initProgram.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { Init } from './init/index.mjs';
|
|
2
2
|
// reused at vovk-init
|
|
3
|
-
export
|
|
3
|
+
export function initProgram(program) {
|
|
4
4
|
return program
|
|
5
|
-
.
|
|
6
|
-
.
|
|
7
|
-
.option('-y, --yes', '
|
|
8
|
-
.option('--log-level <level>', '
|
|
9
|
-
.option('--use-npm', '
|
|
10
|
-
.option('--use-yarn', '
|
|
11
|
-
.option('--use-pnpm', '
|
|
12
|
-
.option('--use-bun', '
|
|
13
|
-
.option('--skip-install', '
|
|
14
|
-
.option('--update-ts-config', '
|
|
15
|
-
.option('--update-scripts <mode>', '
|
|
16
|
-
.option('--
|
|
17
|
-
.option('--
|
|
18
|
-
.option('--channel <channel>', '
|
|
19
|
-
.option('--dry-run', '
|
|
20
|
-
.action((
|
|
5
|
+
.description('Initialize Vovk.ts at existing Next.js project')
|
|
6
|
+
.option('--prefix <prefix>', 'directory to initialize project in')
|
|
7
|
+
.option('-y, --yes', 'skip all prompts and use default values')
|
|
8
|
+
.option('--log-level <level>', 'set log level', 'info')
|
|
9
|
+
.option('--use-npm', 'use npm as package manager')
|
|
10
|
+
.option('--use-yarn', 'use yarn as package manager')
|
|
11
|
+
.option('--use-pnpm', 'use pnpm as package manager')
|
|
12
|
+
.option('--use-bun', 'use bun as package manager')
|
|
13
|
+
.option('--skip-install', 'skip installing dependencies')
|
|
14
|
+
.option('--update-ts-config', 'update tsconfig.json')
|
|
15
|
+
.option('--update-scripts <mode>', 'update package.json scripts ("implicit" or "explicit")')
|
|
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 ("zod", "class-validator", "valibot", "arktype" or another); set to "none" to skip')
|
|
18
|
+
.option('--channel <channel>', 'channel to use for fetching packages', 'latest')
|
|
19
|
+
.option('--dry-run', 'do not write files to disk')
|
|
20
|
+
.action((options) => new Init().main(options));
|
|
21
21
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import type { VovkStrictConfig } from 'vovk';
|
|
2
|
+
import type { ProjectInfo } from './getProjectInfo/index.mjs';
|
|
1
3
|
export type Segment = {
|
|
2
4
|
routeFilePath: string;
|
|
3
5
|
segmentName: string;
|
|
4
6
|
};
|
|
5
|
-
export
|
|
7
|
+
export declare function locateSegments({ dir, rootDir, config, log, }: {
|
|
8
|
+
dir: string | null;
|
|
9
|
+
rootDir?: string;
|
|
10
|
+
config: VovkStrictConfig | null;
|
|
11
|
+
log: ProjectInfo['log'];
|
|
12
|
+
}): Promise<Segment[]>;
|