vovk-cli 0.0.1-draft.6 → 0.0.1-draft.61
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 +29 -1
- package/client-templates/main/main.cjs.ejs +16 -0
- package/client-templates/main/main.d.cts.ejs +15 -0
- package/client-templates/module/module.d.mts.ejs +15 -0
- package/client-templates/module/module.mjs.ejs +21 -0
- package/client-templates/python/__init__.py +276 -0
- package/client-templates/ts/index.ts.ejs +25 -0
- package/dist/dev/diffSchema.d.mts +36 -0
- package/dist/{watcher → dev}/diffSchema.mjs +3 -11
- package/dist/{watcher → dev}/ensureSchemaFiles.d.mts +3 -0
- package/dist/{watcher → dev}/ensureSchemaFiles.mjs +6 -4
- package/dist/dev/index.d.mts +6 -0
- package/dist/{watcher → dev}/index.mjs +128 -62
- package/dist/{watcher → dev}/isMetadataEmpty.mjs +1 -1
- package/dist/{watcher → dev}/logDiffResult.d.mts +2 -2
- package/dist/dev/logDiffResult.mjs +57 -0
- package/dist/{watcher → dev}/writeOneSchemaFile.d.mts +1 -1
- package/dist/{watcher → dev}/writeOneSchemaFile.mjs +2 -2
- package/dist/generate/ensureClient.d.mts +5 -0
- package/dist/generate/ensureClient.mjs +27 -0
- package/dist/generate/getClientTemplates.d.mts +14 -0
- package/dist/generate/getClientTemplates.mjs +28 -0
- package/dist/generate/index.d.mts +12 -0
- package/dist/generate/index.mjs +78 -0
- package/dist/getProjectInfo/getConfig.mjs +5 -5
- package/dist/getProjectInfo/getConfigAbsolutePaths.mjs +2 -2
- package/dist/getProjectInfo/getRelativeSrcRoot.mjs +1 -1
- package/dist/getProjectInfo/getUserConfig.mjs +3 -1
- package/dist/getProjectInfo/importUncachedModule.mjs +0 -1
- package/dist/getProjectInfo/importUncachedModuleWorker.mjs +0 -1
- package/dist/getProjectInfo/index.d.mts +2 -1
- package/dist/getProjectInfo/index.mjs +15 -10
- package/dist/index.d.mts +1 -27
- package/dist/index.mjs +47 -61
- package/dist/init/checkTSConfigForExperimentalDecorators.mjs +2 -2
- package/dist/init/createConfig.d.mts +3 -4
- package/dist/init/createConfig.mjs +6 -8
- package/dist/init/getTemplateFilesFromPackage.d.mts +2 -1
- package/dist/init/getTemplateFilesFromPackage.mjs +4 -5
- package/dist/init/index.d.mts +1 -2
- package/dist/init/index.mjs +46 -93
- 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 +13 -8
- package/dist/init/updateNPMScripts.d.mts +3 -1
- package/dist/init/updateNPMScripts.mjs +10 -6
- package/dist/init/updateTypeScriptConfig.mjs +2 -2
- package/dist/initProgram.d.mts +2 -0
- package/dist/initProgram.mjs +21 -0
- package/dist/locateSegments.d.mts +7 -1
- package/dist/locateSegments.mjs +9 -6
- package/dist/new/addClassToSegmentCode.d.mts +1 -2
- package/dist/new/addClassToSegmentCode.mjs +9 -5
- package/dist/new/addCommonTerms.mjs +1 -0
- package/dist/new/index.d.mts +2 -2
- package/dist/new/index.mjs +3 -3
- package/dist/new/newModule.d.mts +3 -3
- package/dist/new/newModule.mjs +38 -27
- package/dist/new/newSegment.mjs +6 -6
- package/dist/new/render.mjs +2 -5
- package/dist/postinstall.mjs +16 -19
- package/dist/types.d.mts +42 -9
- package/dist/utils/debounceWithArgs.d.mts +1 -1
- package/dist/utils/debounceWithArgs.mjs +24 -9
- package/dist/utils/formatLoggedSegmentName.mjs +1 -1
- package/dist/utils/getAvailablePort.mjs +3 -2
- package/dist/utils/getFileSystemEntryType.mjs +1 -1
- package/package.json +20 -17
- package/templates/controller.ejs +12 -11
- package/templates/service.ejs +6 -6
- package/dist/generateClient.d.mts +0 -7
- package/dist/generateClient.mjs +0 -97
- package/dist/watcher/diffSchema.d.mts +0 -43
- package/dist/watcher/index.d.mts +0 -6
- package/dist/watcher/logDiffResult.mjs +0 -90
- package/templates/worker.ejs +0 -1
- /package/dist/{watcher → dev}/isMetadataEmpty.d.mts +0 -0
|
@@ -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
|
-
const isVovk = packageName.startsWith('vovk');
|
|
10
|
-
const latestVersion = metadata['dist-tags'][isVovk ? channel : 'latest'];
|
|
8
|
+
const isVovk = packageName.startsWith('vovk') && packageName !== 'vovk-mapped-types';
|
|
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
|
}
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
import NPMCliPackageJson from '@npmcli/package-json';
|
|
2
|
+
export declare function getDevScript(pkgJson: NPMCliPackageJson, updateScriptsMode: 'implicit' | 'explicit'): string;
|
|
3
|
+
export default function updateNPMScripts(pkgJson: NPMCliPackageJson, root: string, updateScriptsMode: 'implicit' | 'explicit'): Promise<void>;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
1
|
+
export function getDevScript(pkgJson, updateScriptsMode) {
|
|
2
|
+
const nextDev = pkgJson.content.scripts?.dev ?? 'next dev';
|
|
3
|
+
const nextDevFlags = nextDev.replace('next dev', '').trim();
|
|
4
|
+
return updateScriptsMode === 'explicit'
|
|
5
|
+
? `PORT=3000 concurrently '${nextDev}' 'vovk dev' --kill-others`
|
|
6
|
+
: `vovk dev --next-dev${nextDevFlags ? ` -- ${nextDevFlags}` : ''}`;
|
|
7
|
+
}
|
|
8
|
+
export default async function updateNPMScripts(pkgJson, root, updateScriptsMode) {
|
|
4
9
|
pkgJson.update({
|
|
5
10
|
scripts: {
|
|
11
|
+
...pkgJson.content.scripts,
|
|
6
12
|
generate: 'vovk generate',
|
|
7
|
-
dev: updateScriptsMode
|
|
8
|
-
? "PORT=3000 concurrently 'vovk dev' 'next dev' --kill-others"
|
|
9
|
-
: 'vovk dev --next-dev',
|
|
13
|
+
dev: getDevScript(pkgJson, updateScriptsMode),
|
|
10
14
|
},
|
|
11
15
|
});
|
|
12
16
|
await pkgJson.save();
|
|
@@ -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', 'Path to validateOnClient file')
|
|
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
|
+
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import type { VovkConfig } from './types.mjs';
|
|
1
2
|
export type Segment = {
|
|
2
3
|
routeFilePath: string;
|
|
3
4
|
segmentName: string;
|
|
5
|
+
segmentImportPath: string;
|
|
4
6
|
};
|
|
5
|
-
export default function locateSegments(dir
|
|
7
|
+
export default function locateSegments({ dir, rootDir, config, }: {
|
|
8
|
+
dir: string;
|
|
9
|
+
rootDir?: string;
|
|
10
|
+
config: Required<VovkConfig> | null;
|
|
11
|
+
}): Promise<Segment[]>;
|
package/dist/locateSegments.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
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
|
+
// config: null is used for testing
|
|
5
|
+
export default async function locateSegments({ dir, rootDir, config, }) {
|
|
5
6
|
let results = [];
|
|
7
|
+
rootDir = rootDir ?? dir;
|
|
6
8
|
// Read the contents of the directory
|
|
7
9
|
const list = await fs.readdir(dir);
|
|
8
10
|
// Iterate through each item in the directory
|
|
@@ -16,12 +18,13 @@ export default async function locateSegments(dir, rootDir = dir) {
|
|
|
16
18
|
const routeFilePath = path.join(filePath, 'route.ts');
|
|
17
19
|
if (await getFileSystemEntryType(routeFilePath)) {
|
|
18
20
|
// Calculate the basePath relative to the root directory
|
|
19
|
-
const segmentName = path.relative(rootDir, dir);
|
|
20
|
-
|
|
21
|
+
const segmentName = path.relative(rootDir, dir).replace(/\\/g, '/'); // windows fix
|
|
22
|
+
const segmentImportPath = path.relative(config?.clientOutDir ?? '.__', routeFilePath);
|
|
23
|
+
results.push({ routeFilePath, segmentName, segmentImportPath });
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
// Recursively search inside subdirectories
|
|
24
|
-
const subDirResults = await locateSegments(filePath, rootDir);
|
|
27
|
+
const subDirResults = await locateSegments({ dir: filePath, rootDir, config });
|
|
25
28
|
results = results.concat(subDirResults);
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export default function addClassToSegmentCode(segmentSourceCode: string, { sourceName, compiledName,
|
|
1
|
+
export default function addClassToSegmentCode(segmentSourceCode: string, { sourceName, compiledName, importPath, }: {
|
|
2
2
|
sourceName: string;
|
|
3
3
|
compiledName: string;
|
|
4
|
-
type: 'worker' | 'controller';
|
|
5
4
|
importPath: string;
|
|
6
5
|
}): string;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { Project, SyntaxKind } from 'ts-morph';
|
|
2
|
-
export default function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName,
|
|
3
|
-
const project = new Project(
|
|
1
|
+
import { Project, QuoteKind, SyntaxKind } from 'ts-morph';
|
|
2
|
+
export default function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName, importPath, }) {
|
|
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) => {
|
|
@@ -12,8 +16,8 @@ export default function addClassToSegmentCode(segmentSourceCode, { sourceName, c
|
|
|
12
16
|
moduleSpecifier: importPath,
|
|
13
17
|
});
|
|
14
18
|
}
|
|
15
|
-
// Get the variable declaration for controllers
|
|
16
|
-
const variableDeclaration = sourceFile.getVariableDeclaration(
|
|
19
|
+
// Get the variable declaration for controllers
|
|
20
|
+
const variableDeclaration = sourceFile.getVariableDeclaration('controllers');
|
|
17
21
|
if (variableDeclaration) {
|
|
18
22
|
const initializer = variableDeclaration.getInitializer();
|
|
19
23
|
if (initializer && initializer.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
package/dist/new/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { NewOptions } from '../
|
|
2
|
-
export default function newComponents(components: string[], { dryRun,
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import newModule from './newModule.mjs';
|
|
2
2
|
import newSegment from './newSegment.mjs';
|
|
3
|
-
export default async function newComponents(components, { dryRun,
|
|
3
|
+
export default async function newComponents(components, { dryRun, dir, templates, overwrite, noSegmentUpdate }) {
|
|
4
4
|
if (components[0] === 'segment' || components[0] === 'segments') {
|
|
5
5
|
// vovk new segment [segmentName]
|
|
6
6
|
let segmentNames = components
|
|
@@ -26,8 +26,8 @@ export default async function newComponents(components, { dryRun, dirName, templ
|
|
|
26
26
|
await newModule({
|
|
27
27
|
what,
|
|
28
28
|
moduleNameWithOptionalSegment,
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
dir,
|
|
30
|
+
templates,
|
|
31
31
|
overwrite,
|
|
32
32
|
noSegmentUpdate,
|
|
33
33
|
dryRun,
|
package/dist/new/newModule.d.mts
CHANGED
|
@@ -1,9 +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
4
|
dryRun?: boolean;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
dir?: string;
|
|
6
|
+
templates?: string[];
|
|
7
7
|
noSegmentUpdate?: boolean;
|
|
8
8
|
overwrite?: boolean;
|
|
9
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,49 +18,61 @@ 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
|
-
// replace c by controller, s by service,
|
|
25
|
+
// replace c by controller, s by service, everything else keeps the same
|
|
26
26
|
what = what.map((s) => {
|
|
27
27
|
switch (s) {
|
|
28
28
|
case 'c':
|
|
29
29
|
return 'controller';
|
|
30
30
|
case 's':
|
|
31
31
|
return 'service';
|
|
32
|
-
case 'w':
|
|
33
|
-
return 'worker';
|
|
34
32
|
default:
|
|
35
33
|
return s;
|
|
36
34
|
}
|
|
37
35
|
});
|
|
38
|
-
|
|
36
|
+
if (templatesFlag) {
|
|
37
|
+
if (templatesFlag.length > what.length) {
|
|
38
|
+
throw new Error('Too many templates provided');
|
|
39
|
+
}
|
|
40
|
+
templates = templatesFlag.reduce((acc, templatePath, index) => ({
|
|
41
|
+
...acc,
|
|
42
|
+
[what[index]]: templatePath,
|
|
43
|
+
}), templates);
|
|
44
|
+
}
|
|
39
45
|
for (const type of what) {
|
|
40
46
|
if (!templates[type]) {
|
|
41
|
-
throw new Error(`Template for ${type} not found
|
|
47
|
+
throw new Error(`Template for "${type}" not found`);
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
|
-
const segments = await locateSegments(apiDir);
|
|
50
|
+
const segments = await locateSegments({ dir: apiDir, config });
|
|
45
51
|
const segment = segments.find((s) => s.segmentName === segmentName);
|
|
46
52
|
if (!segment) {
|
|
47
|
-
throw new Error(`Segment ${segmentName} not found`);
|
|
53
|
+
throw new Error(`Unable to create module. Segment "${segmentName}" not found. Run "vovk new segment ${segmentName}" to create it`);
|
|
48
54
|
}
|
|
49
55
|
for (const type of what) {
|
|
50
|
-
const templatePath =
|
|
56
|
+
const templatePath = templates[type];
|
|
51
57
|
const templateAbsolutePath = templatePath.startsWith('/') || templatePath.startsWith('.')
|
|
52
58
|
? path.resolve(cwd, templatePath)
|
|
53
59
|
: path.resolve(cwd, './node_modules', templatePath);
|
|
54
60
|
const templateCode = await fs.readFile(templateAbsolutePath, 'utf-8');
|
|
55
|
-
const {
|
|
61
|
+
const { dir: renderedDir, fileName, sourceName, compiledName, code, } = await render(templateCode, {
|
|
56
62
|
cwd,
|
|
57
63
|
config,
|
|
58
64
|
withService: what.includes('service'),
|
|
59
65
|
segmentName,
|
|
60
66
|
moduleName,
|
|
61
67
|
});
|
|
62
|
-
const
|
|
63
|
-
|
|
68
|
+
const dir = dirFlag || renderedDir;
|
|
69
|
+
if (!dir) {
|
|
70
|
+
throw new Error(`The template for "${type}" does not provide a dir`);
|
|
71
|
+
}
|
|
72
|
+
if (!fileName) {
|
|
73
|
+
throw new Error(`The template for "${type}" does not provide a fileName`);
|
|
74
|
+
}
|
|
75
|
+
const absoluteModuleDir = path.join(cwd, dir);
|
|
64
76
|
const absoluteModulePath = path.join(absoluteModuleDir, fileName);
|
|
65
77
|
const prettiedCode = await prettify(code, absoluteModulePath);
|
|
66
78
|
if (!dryRun) {
|
|
@@ -70,31 +82,30 @@ export default async function newModule({ what, moduleNameWithOptionalSegment, d
|
|
|
70
82
|
else {
|
|
71
83
|
await fs.mkdir(absoluteModuleDir, { recursive: true });
|
|
72
84
|
await fs.writeFile(absoluteModulePath, prettiedCode);
|
|
85
|
+
log.info(`Created ${chalkHighlightThing(fileName)} using ${chalkHighlightThing(`"${type}"`)} template for ${formatLoggedSegmentName(segmentName)}`);
|
|
73
86
|
}
|
|
74
87
|
}
|
|
75
|
-
if (type === 'controller'
|
|
88
|
+
if (type === 'controller') {
|
|
76
89
|
if (!sourceName) {
|
|
77
|
-
throw new Error(
|
|
90
|
+
throw new Error(`The template for "${type}" does not provide a sourceName`);
|
|
78
91
|
}
|
|
79
92
|
if (!compiledName) {
|
|
80
|
-
throw new Error(
|
|
93
|
+
throw new Error(`The template for "${type}" does not provide a compiledName`);
|
|
81
94
|
}
|
|
82
95
|
const { routeFilePath } = segment;
|
|
83
96
|
const segmentSourceCode = await fs.readFile(routeFilePath, 'utf-8');
|
|
84
|
-
const importPath = path.relative(
|
|
97
|
+
const importPath = path.relative(path.dirname(routeFilePath), absoluteModulePath).replace(/\.(ts|tsx)$/, '');
|
|
85
98
|
if (!noSegmentUpdate) {
|
|
86
|
-
const newSegmentCode = addClassToSegmentCode(segmentSourceCode, {
|
|
99
|
+
const newSegmentCode = await prettify(addClassToSegmentCode(segmentSourceCode, {
|
|
87
100
|
sourceName,
|
|
88
101
|
compiledName,
|
|
89
|
-
type,
|
|
90
102
|
importPath,
|
|
91
|
-
});
|
|
103
|
+
}), routeFilePath);
|
|
92
104
|
if (!dryRun) {
|
|
93
105
|
await fs.writeFile(routeFilePath, newSegmentCode);
|
|
94
106
|
}
|
|
95
107
|
}
|
|
96
|
-
log.info(`Added ${chalkHighlightThing(sourceName)} ${type}
|
|
108
|
+
log.info(`Added ${chalkHighlightThing(sourceName)} ${type} as ${chalkHighlightThing(compiledName)} to ${formatLoggedSegmentName(segmentName)}`);
|
|
97
109
|
}
|
|
98
|
-
log.info(`Created ${chalkHighlightThing(fileName)} using "${chalkHighlightThing(type)}" template for ${formatLoggedSegmentName(segmentName)}`);
|
|
99
110
|
}
|
|
100
111
|
}
|
package/dist/new/newSegment.mjs
CHANGED
|
@@ -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 getProjectInfo from '../getProjectInfo/index.mjs';
|
|
4
4
|
import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
|
|
5
5
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
@@ -13,15 +13,14 @@ export default async function newSegment({ segmentName, overwrite, dryRun, }) {
|
|
|
13
13
|
}
|
|
14
14
|
const code = await prettify(`import { initVovk } from 'vovk';
|
|
15
15
|
|
|
16
|
+
export const runtime = 'edge';
|
|
17
|
+
|
|
16
18
|
const controllers = {};
|
|
17
|
-
const workers = {};
|
|
18
19
|
|
|
19
20
|
export type Controllers = typeof controllers;
|
|
20
|
-
export type Workers = typeof workers;
|
|
21
21
|
|
|
22
22
|
export const { GET, POST, PATCH, PUT, HEAD, OPTIONS, DELETE } = initVovk({
|
|
23
23
|
${segmentName ? ` segmentName: '${segmentName}',\n` : ''} emitSchema: true,
|
|
24
|
-
workers,
|
|
25
24
|
controllers,
|
|
26
25
|
});
|
|
27
26
|
`, absoluteSegmentRoutePath);
|
|
@@ -29,5 +28,6 @@ ${segmentName ? ` segmentName: '${segmentName}',\n` : ''} emitSchema: true,
|
|
|
29
28
|
await fs.mkdir(path.dirname(absoluteSegmentRoutePath), { recursive: true });
|
|
30
29
|
await fs.writeFile(absoluteSegmentRoutePath, code);
|
|
31
30
|
}
|
|
32
|
-
log.info(`${formatLoggedSegmentName(segmentName, { upperFirst: true })} created at ${absoluteSegmentRoutePath}
|
|
31
|
+
log.info(`${formatLoggedSegmentName(segmentName, { upperFirst: true })} created at ${absoluteSegmentRoutePath}.`);
|
|
32
|
+
log.info(`Run ${chalkHighlightThing(`npx vovk new service controller ${[segmentName, 'thing'].filter(Boolean).join('/')}`)} to create a new controller with a service at /modules/thing/ folder.`);
|
|
33
33
|
}
|
package/dist/new/render.mjs
CHANGED
|
@@ -20,14 +20,11 @@ export default async function render(codeTemplate, { config, withService, segmen
|
|
|
20
20
|
_, // lodash
|
|
21
21
|
pluralize,
|
|
22
22
|
};
|
|
23
|
-
// first, render the front matter because it can use ejs variables
|
|
24
23
|
const parsed = matter((await ejs.render(codeTemplate, templateVars, { async: true })).trim());
|
|
25
|
-
const {
|
|
24
|
+
const { dir, fileName, sourceName, compiledName } = parsed.data;
|
|
26
25
|
const code = parsed.content;
|
|
27
|
-
// const templateContent = parsed.content; TODO
|
|
28
|
-
// const code = await ejs.render(templateContent, templateVars, { async: true });
|
|
29
26
|
return {
|
|
30
|
-
|
|
27
|
+
dir,
|
|
31
28
|
fileName,
|
|
32
29
|
sourceName,
|
|
33
30
|
compiledName,
|
package/dist/postinstall.mjs
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
* Checks if a file exists at the given path.
|
|
5
|
-
* @param {string} filePath - The path to the file.
|
|
6
|
-
* @returns {Promise<boolean>} - A promise that resolves to true if the file exists, false otherwise.
|
|
7
|
-
*/
|
|
8
|
-
const getFileSystemEntryType = async (filePath) => !!(await fs.stat(filePath).catch(() => false));
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import getFileSystemEntryType from './utils/getFileSystemEntryType.mjs';
|
|
9
4
|
async function postinstall() {
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
5
|
+
// TODO: The function doesn't consider client templates, how to do that?
|
|
6
|
+
const vovk = path.join(import.meta.dirname, '../../.vovk-client');
|
|
7
|
+
const js = path.join(vovk, 'compiled.js');
|
|
8
|
+
const ts = path.join(vovk, 'compiled.d.ts');
|
|
13
9
|
const index = path.join(vovk, 'index.ts');
|
|
14
|
-
if ((await getFileSystemEntryType(js)) ||
|
|
15
|
-
(await getFileSystemEntryType(ts)) ||
|
|
16
|
-
(await getFileSystemEntryType(index))) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
10
|
await fs.mkdir(vovk, { recursive: true });
|
|
20
|
-
await
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
if (!(await getFileSystemEntryType(js))) {
|
|
12
|
+
await fs.writeFile(js, '/* postinstall */');
|
|
13
|
+
}
|
|
14
|
+
if (!(await getFileSystemEntryType(ts))) {
|
|
15
|
+
await fs.writeFile(ts, '/* postinstall */');
|
|
16
|
+
}
|
|
17
|
+
if (!(await getFileSystemEntryType(index))) {
|
|
18
|
+
await fs.writeFile(index, '/* postinstall */');
|
|
19
|
+
}
|
|
23
20
|
}
|
|
24
21
|
void postinstall();
|
package/dist/types.d.mts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { LogLevelNames } from 'loglevel';
|
|
1
|
+
import type { LogLevelNames } from 'loglevel';
|
|
2
2
|
export type KnownAny = any;
|
|
3
3
|
export type VovkEnv = {
|
|
4
4
|
PORT?: string;
|
|
5
5
|
VOVK_CLIENT_OUT_DIR?: string;
|
|
6
6
|
VOVK_SCHEMA_OUT_DIR?: string;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
VOVK_FETCHER_PATH?: string;
|
|
8
|
+
VOVK_VALIDATE_ON_CLIENT_PATH?: string;
|
|
9
|
+
VOVK_CREATE_RPC_PATH?: string;
|
|
9
10
|
VOVK_MODULES_DIR?: string;
|
|
10
|
-
VOVK_VALIDATION_LIBRARY?: string;
|
|
11
11
|
VOVK_ORIGIN?: string;
|
|
12
12
|
VOVK_ROOT_ENTRY?: string;
|
|
13
13
|
VOVK_API_ENTRY_POINT?: string;
|
|
@@ -16,31 +16,64 @@ export type VovkEnv = {
|
|
|
16
16
|
VOVK_PRETTIFY_CLIENT?: string;
|
|
17
17
|
VOVK_DEV_HTTPS?: string;
|
|
18
18
|
__VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
|
|
19
|
+
__VOVK_EXIT__?: 'true' | 'false';
|
|
19
20
|
};
|
|
20
21
|
export type VovkConfig = {
|
|
21
22
|
clientOutDir?: string;
|
|
22
23
|
schemaOutDir?: string;
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
fetcherPath?: string;
|
|
25
|
+
validateOnClientPath?: string | null;
|
|
26
|
+
createRPCPath?: string;
|
|
25
27
|
modulesDir?: string;
|
|
26
|
-
validationLibrary?: string | null;
|
|
27
28
|
rootEntry?: string;
|
|
28
29
|
origin?: string;
|
|
29
30
|
rootSegmentModulesDirName?: string;
|
|
30
31
|
logLevel?: LogLevelNames;
|
|
31
32
|
prettifyClient?: boolean;
|
|
32
33
|
devHttps?: boolean;
|
|
34
|
+
experimental_clientGenerateTemplateNames?: string[];
|
|
33
35
|
templates?: {
|
|
34
36
|
service?: string;
|
|
35
37
|
controller?: string;
|
|
36
|
-
worker?: string;
|
|
37
38
|
[key: string]: string | undefined;
|
|
38
39
|
};
|
|
39
40
|
};
|
|
40
41
|
export type VovkModuleRenderResult = {
|
|
41
42
|
fileName: string;
|
|
42
|
-
|
|
43
|
+
dir: string;
|
|
43
44
|
sourceName?: string;
|
|
44
45
|
compiledName?: string;
|
|
45
46
|
code: string;
|
|
46
47
|
};
|
|
48
|
+
export interface DevOptions {
|
|
49
|
+
nextDev?: boolean;
|
|
50
|
+
exit?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface GenerateOptions {
|
|
53
|
+
clientOutDir?: string;
|
|
54
|
+
templates?: string[];
|
|
55
|
+
prettify?: boolean;
|
|
56
|
+
fullSchema?: string | boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface InitOptions {
|
|
59
|
+
yes?: boolean;
|
|
60
|
+
logLevel: LogLevelNames;
|
|
61
|
+
useNpm?: boolean;
|
|
62
|
+
useYarn?: boolean;
|
|
63
|
+
usePnpm?: boolean;
|
|
64
|
+
useBun?: boolean;
|
|
65
|
+
skipInstall?: boolean;
|
|
66
|
+
updateTsConfig?: boolean;
|
|
67
|
+
updateScripts?: 'implicit' | 'explicit';
|
|
68
|
+
validationLibrary?: string | null;
|
|
69
|
+
validateOnClient?: boolean;
|
|
70
|
+
dryRun?: boolean;
|
|
71
|
+
channel?: 'latest' | 'beta' | 'draft';
|
|
72
|
+
}
|
|
73
|
+
export interface NewOptions {
|
|
74
|
+
dryRun?: boolean;
|
|
75
|
+
templates?: string[];
|
|
76
|
+
dir?: string;
|
|
77
|
+
overwrite?: boolean;
|
|
78
|
+
noSegmentUpdate?: boolean;
|
|
79
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { KnownAny } from '../types.mjs';
|
|
2
|
-
export default function debounceWithArgs<
|
|
2
|
+
export default function debounceWithArgs<Callback extends (...args: KnownAny[]) => KnownAny>(callback: Callback, wait: number): (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>>;
|