vovk-cli 0.0.1-draft.3 → 0.0.1-draft.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{watcher → dev}/diffSchema.d.mts +2 -2
- package/dist/{watcher → dev}/diffSchema.mjs +1 -1
- package/dist/dev/ensureClient.d.mts +5 -0
- package/dist/dev/ensureClient.mjs +31 -0
- package/dist/{watcher → dev}/ensureSchemaFiles.mjs +20 -8
- package/dist/dev/index.d.mts +4 -0
- package/dist/{watcher → dev}/index.mjs +30 -30
- package/dist/{watcher → dev}/logDiffResult.d.mts +2 -2
- package/dist/{watcher → dev}/logDiffResult.mjs +13 -9
- package/dist/{watcher → dev}/writeOneSchemaFile.d.mts +1 -1
- package/dist/{watcher → dev}/writeOneSchemaFile.mjs +4 -3
- package/dist/generateClient.d.mts +1 -1
- package/dist/generateClient.mjs +6 -6
- package/dist/getProjectInfo/getConfigAbsolutePaths.mjs +2 -2
- package/dist/getProjectInfo/getRelativeSrcRoot.mjs +4 -4
- package/dist/getProjectInfo/getUserConfig.mjs +1 -1
- package/dist/getProjectInfo/index.mjs +1 -1
- package/dist/index.d.mts +2 -24
- package/dist/index.mjs +15 -41
- package/dist/init/checkTSConfigForExperimentalDecorators.mjs +2 -2
- package/dist/init/createConfig.d.mts +3 -4
- package/dist/init/createConfig.mjs +5 -5
- package/dist/init/getTemplateFilesFromPackage.d.mts +2 -1
- package/dist/init/getTemplateFilesFromPackage.mjs +3 -4
- package/dist/init/index.d.mts +1 -2
- package/dist/init/index.mjs +36 -85
- package/dist/init/installDependencies.d.mts +4 -1
- package/dist/init/installDependencies.mjs +2 -2
- package/dist/init/logUpdateDependenciesError.d.mts +11 -0
- package/dist/init/logUpdateDependenciesError.mjs +45 -0
- package/dist/init/updateDependenciesWithoutInstalling.d.mts +3 -2
- package/dist/init/updateDependenciesWithoutInstalling.mjs +12 -7
- package/dist/init/updateNPMScripts.mjs +2 -1
- package/dist/init/updateTypeScriptConfig.mjs +2 -2
- package/dist/initProgram.d.mts +2 -0
- package/dist/initProgram.mjs +21 -0
- package/dist/locateSegments.mjs +2 -2
- package/dist/new/addClassToSegmentCode.mjs +6 -2
- package/dist/new/index.d.mts +2 -2
- package/dist/new/index.mjs +13 -3
- package/dist/new/newModule.d.mts +6 -2
- package/dist/new/newModule.mjs +50 -26
- package/dist/new/newSegment.d.mts +3 -2
- package/dist/new/newSegment.mjs +5 -5
- package/dist/new/render.d.mts +3 -7
- package/dist/new/render.mjs +11 -7
- package/dist/postinstall.mjs +5 -3
- package/dist/types.d.mts +37 -2
- package/dist/utils/debounceWithArgs.mjs +1 -4
- package/dist/utils/formatLoggedSegmentName.mjs +1 -1
- package/dist/utils/getAvailablePort.mjs +3 -2
- package/dist/utils/getFileSystemEntryType.mjs +1 -1
- package/package.json +8 -6
- package/templates/controller.ejs +18 -17
- package/templates/service.ejs +24 -4
- package/templates/worker.ejs +24 -1
- package/dist/getProjectInfo/directoryExists.d.mts +0 -1
- package/dist/getProjectInfo/directoryExists.mjs +0 -10
- package/dist/watcher/index.d.mts +0 -6
- package/templates_old/MyThingController.c.only.template.ts +0 -32
- package/templates_old/MyThingController.c.template.ts +0 -34
- package/templates_old/MyThingService.s.template.ts +0 -18
- package/templates_old/controller.ejs +0 -85
- package/templates_old/service.ejs +0 -9
- package/templates_old/worker.ejs +0 -9
- package/templates_old/zod/MyThingController.c.only.template.ts +0 -32
- package/templates_old/zod/MyThingController.c.template.ts +0 -39
- package/templates_old/zod/MyThingService.s.template.ts +0 -18
- /package/dist/{watcher → dev}/ensureSchemaFiles.d.mts +0 -0
- /package/dist/{watcher → dev}/isMetadataEmpty.d.mts +0 -0
- /package/dist/{watcher → dev}/isMetadataEmpty.mjs +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type getLogger from '../utils/getLogger.mjs';
|
|
2
|
-
import type { InitOptions } from '../
|
|
3
|
-
export default function createConfig({ root, log,
|
|
2
|
+
import type { InitOptions } from '../types.mjs';
|
|
3
|
+
export default function createConfig({ root, log, options: { validationLibrary, validateOnClient, channel, dryRun }, }: {
|
|
4
4
|
root: string;
|
|
5
5
|
log: ReturnType<typeof getLogger>;
|
|
6
|
-
dryRun
|
|
7
|
-
options: Pick<InitOptions, 'validationLibrary' | 'validateOnClient'>;
|
|
6
|
+
options: Pick<InitOptions, 'validationLibrary' | 'validateOnClient' | 'channel' | 'dryRun'>;
|
|
8
7
|
}): Promise<{
|
|
9
8
|
configAbsolutePath: string;
|
|
10
9
|
}>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import getFileSystemEntryType, { FileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
4
3
|
import getTemplateFilesFromPackage from './getTemplateFilesFromPackage.mjs';
|
|
5
4
|
import prettify from '../utils/prettify.mjs';
|
|
6
|
-
|
|
5
|
+
import getFileSystemEntryType, { FileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
|
|
6
|
+
export default async function createConfig({ root, log, options: { validationLibrary, validateOnClient, 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;
|
|
@@ -22,7 +22,7 @@ export default async function createConfig({ root, log, dryRun, options: { valid
|
|
|
22
22
|
config.validateOnClient = `${validationLibrary}/validateOnClient`;
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
|
-
const validationTemplates = await getTemplateFilesFromPackage(validationLibrary);
|
|
25
|
+
const validationTemplates = await getTemplateFilesFromPackage(validationLibrary, channel);
|
|
26
26
|
Object.assign(templates, validationTemplates);
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { InitOptions } from '../types.mjs';
|
|
1
2
|
/**
|
|
2
3
|
* Retrieves a list of files in the 'templates' folder of an NPM package.
|
|
3
4
|
* @param packageName - The name of the NPM package.
|
|
4
5
|
* @returns A promise that resolves to an array of file paths.
|
|
5
6
|
*/
|
|
6
|
-
export default function
|
|
7
|
+
export default function getTemplateFilesFromPackage(packageName: string, channel?: InitOptions['channel']): Promise<Record<string, string>>;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { createGunzip } from 'node:zlib';
|
|
2
3
|
import tar from 'tar-stream';
|
|
3
|
-
import { Readable } from 'stream';
|
|
4
4
|
import getNPMPackageMetadata from '../utils/getNPMPackageMetadata.mjs';
|
|
5
5
|
/**
|
|
6
6
|
* Retrieves a list of files in the 'templates' folder of an NPM package.
|
|
7
7
|
* @param packageName - The name of the NPM package.
|
|
8
8
|
* @returns A promise that resolves to an array of file paths.
|
|
9
9
|
*/
|
|
10
|
-
export default async function
|
|
11
|
-
) {
|
|
10
|
+
export default async function getTemplateFilesFromPackage(packageName, channel = 'latest') {
|
|
12
11
|
const metadata = await getNPMPackageMetadata(packageName);
|
|
13
12
|
const latestVersion = metadata['dist-tags'][channel];
|
|
14
13
|
const tarballUrl = metadata.versions[latestVersion].dist.tarball;
|
package/dist/init/index.d.mts
CHANGED
package/dist/init/index.mjs
CHANGED
|
@@ -1,74 +1,18 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/*
|
|
3
|
-
npx vovk-cli init
|
|
4
|
-
- Check if the project is already initialized
|
|
5
|
-
- Do you want to reinitialize the project?
|
|
6
|
-
- Yes
|
|
7
|
-
- No (exit)
|
|
8
|
-
- Check for package.json, if not found, show error and exit
|
|
9
|
-
- Check for tsconfig.json, if not found, show error and exit
|
|
10
|
-
- Check Next.js installed
|
|
11
|
-
- Choose validation library: add to the installation list
|
|
12
|
-
- vovk-zod
|
|
13
|
-
- Further installation notes: install zod
|
|
14
|
-
- vovk-yup
|
|
15
|
-
- Further installation notes: install yup
|
|
16
|
-
- vovk-dto
|
|
17
|
-
- Further installation notes: install class-validator and class-transformer
|
|
18
|
-
- None
|
|
19
|
-
- If validation library is not None,
|
|
20
|
-
- Do you want to enable client validation?
|
|
21
|
-
- Yes
|
|
22
|
-
- Add client validation to the config
|
|
23
|
-
- No
|
|
24
|
-
- Do you want to update NPM scripts?
|
|
25
|
-
- Yes
|
|
26
|
-
- Update NPM scripts
|
|
27
|
-
- No
|
|
28
|
-
- Do you want to use explicit concurrently?
|
|
29
|
-
- Yes (recommended)
|
|
30
|
-
- Add concurrently to the installation list
|
|
31
|
-
- No
|
|
32
|
-
- if experimentalDecorators is not found in tsconfig.json,
|
|
33
|
-
- Do you want to add experimentalDecorators to tsconfig.json?
|
|
34
|
-
- Yes
|
|
35
|
-
- Add experimentalDecorators to tsconfig.json
|
|
36
|
-
- No
|
|
37
|
-
- Do you want to create route file with example service and controller? (NO NEED)
|
|
38
|
-
- Yes
|
|
39
|
-
- Create route file with example controller
|
|
40
|
-
- No, I will create it myself
|
|
41
|
-
- End
|
|
42
|
-
- If there are any packages to install, install them
|
|
43
|
-
- Show installation notes
|
|
44
|
-
- If there are any files to create, create
|
|
45
|
-
- If there are any config files to update, update
|
|
46
|
-
- If example route file is NOT created, show example route file and controller
|
|
47
|
-
- Show how to run the project
|
|
48
|
-
- If npm scripts are updated
|
|
49
|
-
- npm run dev
|
|
50
|
-
- If npm scripts are NOT updated
|
|
51
|
-
- If concurrently is installed
|
|
52
|
-
- concurrently "vovk dev" "next dev"
|
|
53
|
-
- If concurrently is NOT installed
|
|
54
|
-
- vovk dev --next-dev
|
|
55
|
-
- Open http://localhost:3000/api/hello-world
|
|
56
|
-
- Show how to make a request to the example route
|
|
57
|
-
- Show success message
|
|
58
|
-
*/
|
|
59
1
|
import { confirm, select } from '@inquirer/prompts';
|
|
60
|
-
import path from 'path';
|
|
61
|
-
import fs from 'fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
62
4
|
import getConfigPaths from '../getProjectInfo/getConfigAbsolutePaths.mjs';
|
|
63
5
|
import chalk from 'chalk';
|
|
64
6
|
import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
|
|
65
|
-
import installDependencies from './installDependencies.mjs';
|
|
7
|
+
import installDependencies, { getPackageManager } from './installDependencies.mjs';
|
|
66
8
|
import getLogger from '../utils/getLogger.mjs';
|
|
67
9
|
import createConfig from './createConfig.mjs';
|
|
68
10
|
import updateNPMScripts from './updateNPMScripts.mjs';
|
|
69
11
|
import checkTSConfigForExperimentalDecorators from './checkTSConfigForExperimentalDecorators.mjs';
|
|
70
12
|
import updateTypeScriptConfig from './updateTypeScriptConfig.mjs';
|
|
71
13
|
import updateDependenciesWithoutInstalling from './updateDependenciesWithoutInstalling.mjs';
|
|
14
|
+
import logUpdateDependenciesError from './logUpdateDependenciesError.mjs';
|
|
15
|
+
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
72
16
|
export class Init {
|
|
73
17
|
root;
|
|
74
18
|
log;
|
|
@@ -113,6 +57,7 @@ export class Init {
|
|
|
113
57
|
}
|
|
114
58
|
}
|
|
115
59
|
if (!dryRun) {
|
|
60
|
+
let depsUpdated = false;
|
|
116
61
|
try {
|
|
117
62
|
await updateDependenciesWithoutInstalling({
|
|
118
63
|
log,
|
|
@@ -121,27 +66,34 @@ export class Init {
|
|
|
121
66
|
devDependencyNames: devDependencies,
|
|
122
67
|
channel: channel ?? 'latest',
|
|
123
68
|
});
|
|
124
|
-
|
|
69
|
+
depsUpdated = true;
|
|
125
70
|
}
|
|
126
|
-
catch (
|
|
127
|
-
|
|
71
|
+
catch (e) {
|
|
72
|
+
const error = e;
|
|
73
|
+
logUpdateDependenciesError({ log, error, useNpm, useYarn, usePnpm, useBun, dependencies, devDependencies });
|
|
128
74
|
}
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
cwd: root,
|
|
134
|
-
options: {
|
|
135
|
-
useNpm,
|
|
136
|
-
useYarn,
|
|
137
|
-
usePnpm,
|
|
138
|
-
useBun,
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
log.info('Dependencies installed successfully');
|
|
75
|
+
if (depsUpdated) {
|
|
76
|
+
const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun });
|
|
77
|
+
if (skipInstall) {
|
|
78
|
+
log.info(`Installation skipped. Please, install them manually with ${chalkHighlightThing(packageManager + ' install')}`);
|
|
142
79
|
}
|
|
143
|
-
|
|
144
|
-
|
|
80
|
+
else {
|
|
81
|
+
try {
|
|
82
|
+
await installDependencies({
|
|
83
|
+
log,
|
|
84
|
+
cwd: root,
|
|
85
|
+
options: {
|
|
86
|
+
useNpm,
|
|
87
|
+
useYarn,
|
|
88
|
+
usePnpm,
|
|
89
|
+
useBun,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
log.info('Dependencies installed successfully');
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
log.warn(`Failed to install dependencies: ${error.message}. Please, install them manually with ${chalkHighlightThing(packageManager + ' install')}`);
|
|
96
|
+
}
|
|
145
97
|
}
|
|
146
98
|
}
|
|
147
99
|
}
|
|
@@ -149,8 +101,7 @@ export class Init {
|
|
|
149
101
|
const { configAbsolutePath } = await createConfig({
|
|
150
102
|
root,
|
|
151
103
|
log,
|
|
152
|
-
options: { validationLibrary, validateOnClient },
|
|
153
|
-
dryRun,
|
|
104
|
+
options: { validationLibrary, validateOnClient, channel, dryRun },
|
|
154
105
|
});
|
|
155
106
|
log.info('Config created successfully at ' + configAbsolutePath);
|
|
156
107
|
}
|
|
@@ -228,23 +179,23 @@ export class Init {
|
|
|
228
179
|
updateScripts =
|
|
229
180
|
updateScripts ??
|
|
230
181
|
(await select({
|
|
231
|
-
message: 'Do you want to update package.json by adding "generate" and "dev" scripts?',
|
|
182
|
+
message: 'Do you want to update package.json by adding "generate" and "dev" NPM scripts?',
|
|
232
183
|
default: 'implicit',
|
|
233
184
|
choices: [
|
|
234
185
|
{
|
|
235
186
|
name: 'Yes, use "concurrently" implicitly',
|
|
236
|
-
description: `The "dev" script will use "concurrently" API internally in order to run "next dev" and "vovk dev" together and automatically look for an available port ${chalk.whiteBright.bold(`"vovk dev --next-dev"`)}`,
|
|
237
187
|
value: 'implicit',
|
|
188
|
+
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(`"vovk dev --next-dev"`)}`,
|
|
238
189
|
},
|
|
239
190
|
{
|
|
240
191
|
name: 'Yes, use "concurrently" explicitly',
|
|
241
192
|
value: 'explicit',
|
|
242
|
-
description: `The "dev" script will use pre-defined PORT variable and run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.whiteBright.bold(`"PORT=3000 concurrently '
|
|
193
|
+
description: `The "dev" script will use pre-defined PORT variable and run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.whiteBright.bold(`"PORT=3000 concurrently 'next dev' 'vovk dev' --kill-others"`)}`,
|
|
243
194
|
},
|
|
244
195
|
{
|
|
245
196
|
name: 'No',
|
|
246
197
|
value: undefined,
|
|
247
|
-
description: 'Add the scripts manually',
|
|
198
|
+
description: 'Add the NPM scripts manually',
|
|
248
199
|
},
|
|
249
200
|
],
|
|
250
201
|
}));
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { InitOptions } from '../index.mjs';
|
|
2
1
|
import getLogger from '../utils/getLogger.mjs';
|
|
2
|
+
import type { InitOptions } from '../types.mjs';
|
|
3
|
+
type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';
|
|
4
|
+
export declare function getPackageManager(options: Pick<InitOptions, 'useNpm' | 'useYarn' | 'usePnpm' | 'useBun'>): PackageManager;
|
|
3
5
|
export default function installDependencies({ log, cwd, options, }: {
|
|
4
6
|
log: ReturnType<typeof getLogger>;
|
|
5
7
|
cwd: string;
|
|
6
8
|
options: Pick<InitOptions, 'useNpm' | 'useYarn' | 'usePnpm' | 'useBun'>;
|
|
7
9
|
}): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type getLogger from '../utils/getLogger.mjs';
|
|
2
|
+
export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, }: {
|
|
3
|
+
useNpm?: boolean;
|
|
4
|
+
useYarn?: boolean;
|
|
5
|
+
usePnpm?: boolean;
|
|
6
|
+
useBun?: boolean;
|
|
7
|
+
log: ReturnType<typeof getLogger>;
|
|
8
|
+
dependencies: string[];
|
|
9
|
+
devDependencies: string[];
|
|
10
|
+
error: Error;
|
|
11
|
+
}): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
2
|
+
import { getPackageManager } from './installDependencies.mjs';
|
|
3
|
+
export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, }) {
|
|
4
|
+
const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun });
|
|
5
|
+
const installCommands = [];
|
|
6
|
+
if (dependencies.length > 0) {
|
|
7
|
+
let depInstallCmd = '';
|
|
8
|
+
switch (packageManager) {
|
|
9
|
+
case 'npm':
|
|
10
|
+
depInstallCmd = `npm install ${dependencies.join(' ')}`;
|
|
11
|
+
break;
|
|
12
|
+
case 'yarn':
|
|
13
|
+
depInstallCmd = `yarn add ${dependencies.join(' ')}`;
|
|
14
|
+
break;
|
|
15
|
+
case 'pnpm':
|
|
16
|
+
depInstallCmd = `pnpm add ${dependencies.join(' ')}`;
|
|
17
|
+
break;
|
|
18
|
+
case 'bun':
|
|
19
|
+
depInstallCmd = `bun add ${dependencies.join(' ')}`;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
installCommands.push(depInstallCmd);
|
|
23
|
+
}
|
|
24
|
+
if (devDependencies.length > 0) {
|
|
25
|
+
let devDepInstallCmd = '';
|
|
26
|
+
switch (packageManager) {
|
|
27
|
+
case 'npm':
|
|
28
|
+
devDepInstallCmd = `npm install -D ${devDependencies.join(' ')}`;
|
|
29
|
+
break;
|
|
30
|
+
case 'yarn':
|
|
31
|
+
devDepInstallCmd = `yarn add --dev ${devDependencies.join(' ')}`;
|
|
32
|
+
break;
|
|
33
|
+
case 'pnpm':
|
|
34
|
+
devDepInstallCmd = `pnpm add -D ${devDependencies.join(' ')}`;
|
|
35
|
+
break;
|
|
36
|
+
case 'bun':
|
|
37
|
+
devDepInstallCmd = `bun add -d ${devDependencies.join(' ')}`;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
installCommands.push(devDepInstallCmd);
|
|
41
|
+
}
|
|
42
|
+
const installCmd = installCommands.join(' && ');
|
|
43
|
+
// Log the error with the appropriate manual installation instructions
|
|
44
|
+
log.warn(`Failed to update dependencies: ${error.message}. Please, install them manually with ${chalkHighlightThing(installCmd)}`);
|
|
45
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import getLogger from '../utils/getLogger.mjs';
|
|
1
|
+
import type getLogger from '../utils/getLogger.mjs';
|
|
2
|
+
import { InitOptions } from '../types.mjs';
|
|
2
3
|
export default function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }: {
|
|
3
4
|
log: ReturnType<typeof getLogger>;
|
|
4
5
|
dir: string;
|
|
5
6
|
dependencyNames: string[];
|
|
6
7
|
devDependencyNames: string[];
|
|
7
|
-
channel: '
|
|
8
|
+
channel: InitOptions['channel'];
|
|
8
9
|
}): Promise<void>;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
2
4
|
import getNPMPackageMetadata from '../utils/getNPMPackageMetadata.mjs';
|
|
3
|
-
import path from 'path';
|
|
4
5
|
async function updateDeps({ packageJson, packageNames, channel, key, }) {
|
|
5
6
|
return Promise.all(packageNames.map(async (packageName) => {
|
|
6
|
-
if (packageJson[key]?.[packageName])
|
|
7
|
-
return; // Skip if already present
|
|
8
7
|
const metadata = await getNPMPackageMetadata(packageName);
|
|
9
8
|
const isVovk = packageName.startsWith('vovk');
|
|
10
|
-
const latestVersion = metadata['dist-tags'][isVovk ? channel : 'latest'];
|
|
9
|
+
const latestVersion = metadata['dist-tags'][isVovk ? (channel ?? 'latest') : 'latest'];
|
|
11
10
|
if (!packageJson[key]) {
|
|
12
11
|
packageJson[key] = {};
|
|
13
12
|
}
|
|
@@ -18,8 +17,14 @@ export default async function updateDependenciesWithoutInstalling({ log, dir, de
|
|
|
18
17
|
const packageJsonPath = path.join(dir, 'package.json');
|
|
19
18
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
20
19
|
await updateDeps({ packageJson, packageNames: dependencyNames, channel, key: 'dependencies' });
|
|
21
|
-
log.debug('Updated dependencies in package.json');
|
|
22
20
|
await updateDeps({ packageJson, packageNames: devDependencyNames, channel, key: 'devDependencies' });
|
|
23
|
-
log.debug('Updated devDependencies in package.json');
|
|
24
21
|
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
22
|
+
log.info('Added dependencies to package.json:');
|
|
23
|
+
for (const dependency of dependencyNames) {
|
|
24
|
+
log.raw.info(` - ${chalk.cyan(dependency)}`);
|
|
25
|
+
}
|
|
26
|
+
log.info('Added devDependencies to package.json:');
|
|
27
|
+
for (const dependency of devDependencyNames) {
|
|
28
|
+
log.raw.info(` - ${chalk.cyan(dependency)}`);
|
|
29
|
+
}
|
|
25
30
|
}
|
|
@@ -3,9 +3,10 @@ export default async function updateNPMScripts(root, updateScriptsMode) {
|
|
|
3
3
|
const pkgJson = await NPMCliPackageJson.load(root);
|
|
4
4
|
pkgJson.update({
|
|
5
5
|
scripts: {
|
|
6
|
+
...pkgJson.content.scripts,
|
|
6
7
|
generate: 'vovk generate',
|
|
7
8
|
dev: updateScriptsMode === 'explicit'
|
|
8
|
-
? "PORT=3000 concurrently '
|
|
9
|
+
? "PORT=3000 concurrently 'next dev' 'vovk dev' --kill-others"
|
|
9
10
|
: 'vovk dev --next-dev',
|
|
10
11
|
},
|
|
11
12
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs/promises';
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
3
|
import * as jsonc from 'jsonc-parser';
|
|
4
4
|
import prettify from '../utils/prettify.mjs';
|
|
5
5
|
export default async function updateTypeScriptConfig(root) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Init } from './init/index.mjs';
|
|
2
|
+
// reused at vovk-init
|
|
3
|
+
export default function initProgram(program) {
|
|
4
|
+
return program
|
|
5
|
+
.argument('[prefix]', 'Directory to initialize project in', '.')
|
|
6
|
+
.description('Initialize Vovk project')
|
|
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('--validation-library <library>', 'Validation library to use ("vovk-zod", "vovk-yup", "vovk-dto" or another). Set to "none" to skip validation')
|
|
17
|
+
.option('--validate-on-client', 'Validate on client')
|
|
18
|
+
.option('--channel <channel>', 'Channel to use for fetching packages', 'latest')
|
|
19
|
+
.option('--dry-run', 'Do not write files to disk')
|
|
20
|
+
.action((prefix = '.', options) => new Init().main(prefix, options));
|
|
21
|
+
}
|
package/dist/locateSegments.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import getFileSystemEntryType from './utils/getFileSystemEntryType.mjs';
|
|
4
4
|
export default async function locateSegments(dir, rootDir = dir) {
|
|
5
5
|
let results = [];
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { Project, SyntaxKind } from 'ts-morph';
|
|
1
|
+
import { Project, QuoteKind, SyntaxKind } from 'ts-morph';
|
|
2
2
|
export default function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName, type, importPath, }) {
|
|
3
|
-
const project = new Project(
|
|
3
|
+
const project = new Project({
|
|
4
|
+
manipulationSettings: {
|
|
5
|
+
quoteKind: QuoteKind.Single,
|
|
6
|
+
},
|
|
7
|
+
});
|
|
4
8
|
const sourceFile = project.createSourceFile('route.ts', segmentSourceCode, { overwrite: true });
|
|
5
9
|
// Add the import if it doesn't exist
|
|
6
10
|
let importDeclaration = sourceFile.getImportDeclaration((imp) => {
|
package/dist/new/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { NewOptions } from '../
|
|
2
|
-
export default function newComponents(components: string[],
|
|
1
|
+
import type { NewOptions } from '../types.mjs';
|
|
2
|
+
export default function newComponents(components: string[], { dryRun, dir, templates, overwrite, noSegmentUpdate }: NewOptions): Promise<void>;
|
package/dist/new/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import newModule from './newModule.mjs';
|
|
2
2
|
import newSegment from './newSegment.mjs';
|
|
3
|
-
export default async function newComponents(components,
|
|
3
|
+
export default async function newComponents(components, { dryRun, dir, templates, overwrite, noSegmentUpdate }) {
|
|
4
4
|
if (components[0] === 'segment' || components[0] === 'segments') {
|
|
5
|
+
// vovk new segment [segmentName]
|
|
5
6
|
let segmentNames = components
|
|
6
7
|
.slice(1)
|
|
7
8
|
.map((segmentName) => (segmentName === '""' || segmentName === "''" ? '' : segmentName));
|
|
@@ -9,10 +10,11 @@ export default async function newComponents(components, options) {
|
|
|
9
10
|
segmentNames = [''];
|
|
10
11
|
}
|
|
11
12
|
for (const segmentName of segmentNames) {
|
|
12
|
-
await newSegment({ segmentName,
|
|
13
|
+
await newSegment({ segmentName, overwrite, dryRun });
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
else {
|
|
17
|
+
// vovk new [what...] [moduleNameWithOptionalSegment]
|
|
16
18
|
if (components.length < 2) {
|
|
17
19
|
throw new Error('Invalid command invocation. Please provide at least two arguments.');
|
|
18
20
|
}
|
|
@@ -21,6 +23,14 @@ export default async function newComponents(components, options) {
|
|
|
21
23
|
if (!moduleNameWithOptionalSegment) {
|
|
22
24
|
throw new Error('A module name with an optional segment cannot be empty');
|
|
23
25
|
}
|
|
24
|
-
await newModule({
|
|
26
|
+
await newModule({
|
|
27
|
+
what,
|
|
28
|
+
moduleNameWithOptionalSegment,
|
|
29
|
+
dir,
|
|
30
|
+
templates,
|
|
31
|
+
overwrite,
|
|
32
|
+
noSegmentUpdate,
|
|
33
|
+
dryRun,
|
|
34
|
+
});
|
|
25
35
|
}
|
|
26
36
|
}
|
package/dist/new/newModule.d.mts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
export default function newModule({ what, moduleNameWithOptionalSegment, dryRun, }: {
|
|
1
|
+
export default function newModule({ what, moduleNameWithOptionalSegment, dryRun, dir: dirFlag, templates: templatesFlag, noSegmentUpdate, overwrite, }: {
|
|
2
2
|
what: string[];
|
|
3
3
|
moduleNameWithOptionalSegment: string;
|
|
4
|
-
dryRun
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
dir?: string;
|
|
6
|
+
templates?: string[];
|
|
7
|
+
noSegmentUpdate?: boolean;
|
|
8
|
+
overwrite?: boolean;
|
|
5
9
|
}): Promise<void>;
|
package/dist/new/newModule.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import getProjectInfo from '../getProjectInfo/index.mjs';
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
4
3
|
import render from './render.mjs';
|
|
4
|
+
import addClassToSegmentCode from './addClassToSegmentCode.mjs';
|
|
5
|
+
import getProjectInfo from '../getProjectInfo/index.mjs';
|
|
6
|
+
import locateSegments from '../locateSegments.mjs';
|
|
5
7
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
6
8
|
import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
|
|
7
|
-
import locateSegments from '../locateSegments.mjs';
|
|
8
|
-
import addClassToSegmentCode from './addClassToSegmentCode.mjs';
|
|
9
9
|
import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
|
|
10
10
|
import prettify from '../utils/prettify.mjs';
|
|
11
11
|
function splitByLast(str, delimiter = '/') {
|
|
@@ -18,9 +18,9 @@ function splitByLast(str, delimiter = '/') {
|
|
|
18
18
|
const after = str.substring(index + delimiter.length);
|
|
19
19
|
return [before, after];
|
|
20
20
|
}
|
|
21
|
-
export default async function newModule({ what, moduleNameWithOptionalSegment, dryRun, }) {
|
|
21
|
+
export default async function newModule({ what, moduleNameWithOptionalSegment, dryRun, dir: dirFlag, templates: templatesFlag, noSegmentUpdate, overwrite, }) {
|
|
22
22
|
const { config, log, apiDir, cwd } = await getProjectInfo();
|
|
23
|
-
|
|
23
|
+
let templates = config.templates;
|
|
24
24
|
const [segmentName, moduleName] = splitByLast(moduleNameWithOptionalSegment);
|
|
25
25
|
// replace c by controller, s by service, w by worker, everything else keeps the same
|
|
26
26
|
what = what.map((s) => {
|
|
@@ -35,16 +35,24 @@ export default async function newModule({ what, moduleNameWithOptionalSegment, d
|
|
|
35
35
|
return s;
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
|
-
|
|
38
|
+
if (templatesFlag) {
|
|
39
|
+
if (templatesFlag.length > what.length) {
|
|
40
|
+
throw new Error('Too many templates provided');
|
|
41
|
+
}
|
|
42
|
+
templates = templatesFlag.reduce((acc, templatePath, index) => ({
|
|
43
|
+
...acc,
|
|
44
|
+
[what[index]]: templatePath,
|
|
45
|
+
}), templates);
|
|
46
|
+
}
|
|
39
47
|
for (const type of what) {
|
|
40
48
|
if (!templates[type]) {
|
|
41
|
-
throw new Error(`Template for ${type} not found
|
|
49
|
+
throw new Error(`Template for "${type}" not found`);
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
52
|
const segments = await locateSegments(apiDir);
|
|
45
53
|
const segment = segments.find((s) => s.segmentName === segmentName);
|
|
46
54
|
if (!segment) {
|
|
47
|
-
throw new Error(`Segment ${segmentName} not found`);
|
|
55
|
+
throw new Error(`Unable to create module. Segment "${segmentName}" not found. Run "vovk new segment ${segmentName}" to create it`);
|
|
48
56
|
}
|
|
49
57
|
for (const type of what) {
|
|
50
58
|
const templatePath = templates[type];
|
|
@@ -52,39 +60,55 @@ export default async function newModule({ what, moduleNameWithOptionalSegment, d
|
|
|
52
60
|
? path.resolve(cwd, templatePath)
|
|
53
61
|
: path.resolve(cwd, './node_modules', templatePath);
|
|
54
62
|
const templateCode = await fs.readFile(templateAbsolutePath, 'utf-8');
|
|
55
|
-
const {
|
|
63
|
+
const { dir: renderedDir, fileName, sourceName, compiledName, code, } = await render(templateCode, {
|
|
64
|
+
cwd,
|
|
56
65
|
config,
|
|
57
66
|
withService: what.includes('service'),
|
|
58
67
|
segmentName,
|
|
59
68
|
moduleName,
|
|
60
69
|
});
|
|
61
|
-
const
|
|
62
|
-
|
|
70
|
+
const dir = dirFlag || renderedDir;
|
|
71
|
+
if (!dir) {
|
|
72
|
+
throw new Error(`The template for "${type}" does not provide a dir`);
|
|
73
|
+
}
|
|
74
|
+
if (!fileName) {
|
|
75
|
+
throw new Error(`The template for "${type}" does not provide a fileName`);
|
|
76
|
+
}
|
|
77
|
+
const absoluteModuleDir = path.join(cwd, dir);
|
|
78
|
+
const absoluteModulePath = path.join(absoluteModuleDir, fileName);
|
|
63
79
|
const prettiedCode = await prettify(code, absoluteModulePath);
|
|
64
80
|
if (!dryRun) {
|
|
65
|
-
if (await getFileSystemEntryType(absoluteModulePath)) {
|
|
81
|
+
if (!overwrite && (await getFileSystemEntryType(absoluteModulePath))) {
|
|
66
82
|
log.warn(`File ${chalkHighlightThing(absoluteModulePath)} already exists, skipping this "${type}"`);
|
|
67
83
|
}
|
|
68
84
|
else {
|
|
69
|
-
await fs.mkdir(
|
|
85
|
+
await fs.mkdir(absoluteModuleDir, { recursive: true });
|
|
70
86
|
await fs.writeFile(absoluteModulePath, prettiedCode);
|
|
87
|
+
log.info(`Created ${chalkHighlightThing(fileName)} using ${chalkHighlightThing(`"${type}"`)} template for ${formatLoggedSegmentName(segmentName)}`);
|
|
71
88
|
}
|
|
72
89
|
}
|
|
73
90
|
if (type === 'controller' || type === 'worker') {
|
|
91
|
+
if (!sourceName) {
|
|
92
|
+
throw new Error(`The template for "${type}" does not provide a sourceName`);
|
|
93
|
+
}
|
|
94
|
+
if (!compiledName) {
|
|
95
|
+
throw new Error('The template for "${type}" does not provide a compiledName');
|
|
96
|
+
}
|
|
74
97
|
const { routeFilePath } = segment;
|
|
75
98
|
const segmentSourceCode = await fs.readFile(routeFilePath, 'utf-8');
|
|
76
|
-
const importPath = path.relative(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
99
|
+
const importPath = path.relative(path.dirname(routeFilePath), absoluteModulePath).replace(/\.(ts|tsx)$/, '');
|
|
100
|
+
if (!noSegmentUpdate) {
|
|
101
|
+
const newSegmentCode = await prettify(addClassToSegmentCode(segmentSourceCode, {
|
|
102
|
+
sourceName,
|
|
103
|
+
compiledName,
|
|
104
|
+
type,
|
|
105
|
+
importPath,
|
|
106
|
+
}), routeFilePath);
|
|
107
|
+
if (!dryRun) {
|
|
108
|
+
await fs.writeFile(routeFilePath, newSegmentCode);
|
|
109
|
+
}
|
|
85
110
|
}
|
|
86
|
-
log.info(`Added ${chalkHighlightThing(sourceName)} ${type}
|
|
111
|
+
log.info(`Added ${chalkHighlightThing(sourceName)} ${type} as ${chalkHighlightThing(compiledName)} to ${formatLoggedSegmentName(segmentName)}`);
|
|
87
112
|
}
|
|
88
|
-
log.info(`Created ${chalkHighlightThing(sourceName)} with ${chalkHighlightThing(type)} template for ${formatLoggedSegmentName(segmentName)}`);
|
|
89
113
|
}
|
|
90
114
|
}
|