vovk-cli 0.0.1-draft.66 → 0.0.1-draft.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client-templates/main/main.cjs.ejs +7 -7
- package/client-templates/main/main.d.cts.ejs +5 -5
- package/client-templates/module/module.d.mts.ejs +5 -5
- package/client-templates/module/module.mjs.ejs +8 -8
- package/client-templates/ts/index.ts.ejs +9 -9
- package/dist/dev/ensureSchemaFiles.mjs +5 -6
- package/dist/dev/index.mjs +2 -1
- package/dist/dev/logDiffResult.mjs +5 -5
- package/dist/generate/index.mjs +9 -8
- package/dist/getProjectInfo/getConfig.d.mts +3 -3
- package/dist/getProjectInfo/getConfig.mjs +6 -3
- package/dist/getProjectInfo/index.d.mts +13 -5
- package/dist/getProjectInfo/index.mjs +17 -14
- package/dist/index.mjs +5 -5
- package/dist/init/createConfig.d.mts +2 -2
- package/dist/init/createConfig.mjs +5 -2
- package/dist/init/index.d.mts +1 -1
- package/dist/init/index.mjs +18 -7
- package/dist/initProgram.mjs +16 -15
- package/dist/new/newSegment.mjs +3 -1
- package/dist/types.d.mts +9 -3
- package/package.json +3 -3
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
2
|
-
const { default: fetcher } = require('<%=
|
|
3
|
-
const { default: createRPC } = require('<%=
|
|
4
|
-
const schema = require('<%=
|
|
5
|
-
const { default: validateOnClient = null } = <%-
|
|
6
|
-
const apiRoot = '<%= apiRoot %>';
|
|
7
|
-
<% segments.forEach((segment) => {
|
|
8
|
-
Object.keys(
|
|
2
|
+
const { default: fetcher } = require('<%= template.imports.fetcher %>');
|
|
3
|
+
const { default: createRPC } = require('<%= template.imports.createRPC %>');
|
|
4
|
+
const schema = require('<%= template.imports.schema %>');
|
|
5
|
+
const { default: validateOnClient = null } = <%- template.imports.validateOnClient ? `require('${template.imports.validateOnClient}')` : '{}'%>;
|
|
6
|
+
const apiRoot = '<%= template.apiRoot %>';
|
|
7
|
+
<% template.segments.forEach((segment) => {
|
|
8
|
+
Object.keys(template.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
9
9
|
exports.<%= key %> = createRPC(
|
|
10
10
|
schema['<%= segment.segmentName %>'].controllers.<%= key %>,
|
|
11
11
|
'<%= segment.segmentName %>',
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
3
3
|
import type { VovkClientFetcher } from 'vovk';
|
|
4
|
-
import type fetcher from '<%=
|
|
5
|
-
import type createRPC from '<%=
|
|
6
|
-
<% segments.forEach((segment, i) => { if(Object.keys(
|
|
4
|
+
import type fetcher from '<%= template.imports.fetcher %>';
|
|
5
|
+
import type createRPC from '<%= template.imports.createRPC %>';
|
|
6
|
+
<% template.segments.forEach((segment, i) => { if(Object.keys(template.fullSchema[segment.segmentName].controllers).length) { %>
|
|
7
7
|
import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
|
|
8
8
|
<% }}) %>
|
|
9
9
|
type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
|
|
10
|
-
<% segments.forEach((segment, i) => {
|
|
11
|
-
Object.keys(
|
|
10
|
+
<% template.segments.forEach((segment, i) => {
|
|
11
|
+
Object.keys(template.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
12
12
|
export const <%= key %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= key %>"], Options>>;
|
|
13
13
|
<% })
|
|
14
14
|
}) %>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
3
3
|
import type { VovkClientFetcher } from 'vovk';
|
|
4
|
-
import type fetcher from '<%=
|
|
5
|
-
import type createRPC from '<%=
|
|
6
|
-
<% segments.forEach((segment, i) => { if(Object.keys(
|
|
4
|
+
import type fetcher from '<%= template.imports.module.fetcher %>';
|
|
5
|
+
import type createRPC from '<%= template.imports.module.createRPC %>';
|
|
6
|
+
<% template.segments.forEach((segment, i) => { if(Object.keys(template.fullSchema[segment.segmentName].controllers).length) { %>
|
|
7
7
|
import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
|
|
8
8
|
<% }}) %>
|
|
9
9
|
type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
|
|
10
|
-
<% segments.forEach((segment, i) => {
|
|
11
|
-
Object.keys(
|
|
10
|
+
<% template.segments.forEach((segment, i) => {
|
|
11
|
+
Object.keys(template.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
12
12
|
export const <%= key %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= key %>"], Options>>;
|
|
13
13
|
<% })
|
|
14
14
|
}) %>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
2
|
-
import fetcherImport from '<%=
|
|
3
|
-
import createRPCImport from '<%=
|
|
4
|
-
import schema from '<%=
|
|
5
|
-
<% if (
|
|
6
|
-
import validateOnClientImport from '<%=
|
|
2
|
+
import fetcherImport from '<%= template.imports.module.fetcher %>';
|
|
3
|
+
import createRPCImport from '<%= template.imports.module.createRPC %>';
|
|
4
|
+
import schema from '<%= template.imports.module.schema %>';
|
|
5
|
+
<% if (template.imports.module.validateOnClient) { %>
|
|
6
|
+
import validateOnClientImport from '<%= template.imports.module.validateOnClient %>';
|
|
7
7
|
const validateOnClient = validateOnClientImport.default || validateOnClientImport;
|
|
8
8
|
<% } else { %>
|
|
9
9
|
const validateOnClient = undefined;
|
|
10
10
|
<% } %>
|
|
11
|
-
const apiRoot = '<%= apiRoot %>';
|
|
11
|
+
const apiRoot = '<%= template.apiRoot %>';
|
|
12
12
|
const fetcher = fetcherImport.default || fetcherImport;
|
|
13
13
|
const createRPC = createRPCImport.default || createRPCImport;
|
|
14
|
-
<% segments.forEach((segment, i) => {
|
|
15
|
-
Object.keys(
|
|
14
|
+
<% template.segments.forEach((segment, i) => {
|
|
15
|
+
Object.keys(template.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
16
16
|
export const <%= key %> = createRPC(
|
|
17
17
|
schema['<%= segment.segmentName %>'].controllers.<%= key %>,
|
|
18
18
|
'<%= segment.segmentName %>',
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
2
2
|
import type { VovkClientFetcher } from 'vovk';
|
|
3
|
-
import fetcher from '<%=
|
|
4
|
-
import createRPC from '<%=
|
|
5
|
-
import schema from '<%=
|
|
6
|
-
<% segments.forEach((segment, i) => { if(Object.keys(
|
|
3
|
+
import fetcher from '<%= template.imports.fetcher %>';
|
|
4
|
+
import createRPC from '<%= template.imports.createRPC %>';
|
|
5
|
+
import schema from '<%= template.imports.schema %>';
|
|
6
|
+
<% template.segments.forEach((segment, i) => { if(Object.keys(template.fullSchema[segment.segmentName].controllers).length) { %>
|
|
7
7
|
import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
|
|
8
8
|
<% }}) %>
|
|
9
|
-
<% if (
|
|
10
|
-
import validateOnClient from '<%=
|
|
9
|
+
<% if (template.imports.validateOnClient) { %>
|
|
10
|
+
import validateOnClient from '<%= template.imports.validateOnClient %>';
|
|
11
11
|
<% } else { %>
|
|
12
12
|
const validateOnClient = undefined;
|
|
13
13
|
<% } %>
|
|
14
14
|
type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
|
|
15
|
-
const apiRoot = '<%= apiRoot %>';
|
|
15
|
+
const apiRoot = '<%= template.apiRoot %>';
|
|
16
16
|
|
|
17
|
-
<% segments.forEach((segment, i) => { %>
|
|
18
|
-
<% Object.keys(
|
|
17
|
+
<% template.segments.forEach((segment, i) => { %>
|
|
18
|
+
<% Object.keys(template.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
19
19
|
export const <%= key %> = createRPC<Controllers<%= i %>["<%= key %>"], Options>(
|
|
20
20
|
schema['<%= segment.segmentName %>'].controllers.<%= key %>,
|
|
21
21
|
'<%= segment.segmentName %>',
|
|
@@ -9,7 +9,6 @@ import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
|
|
|
9
9
|
export default async function ensureSchemaFiles(projectInfo, schemaOutAbsolutePath, segmentNames) {
|
|
10
10
|
const now = Date.now();
|
|
11
11
|
let hasChanged = false;
|
|
12
|
-
// Create index.js file
|
|
13
12
|
const indexContent = `// auto-generated
|
|
14
13
|
${segmentNames
|
|
15
14
|
.map((segmentName) => {
|
|
@@ -18,12 +17,12 @@ ${segmentNames
|
|
|
18
17
|
.join('\n')}`;
|
|
19
18
|
const dTsContent = `// auto-generated
|
|
20
19
|
import type { VovkSchema } from 'vovk';
|
|
21
|
-
declare const
|
|
22
|
-
${segmentNames.map((segmentName) => ` '${segmentName}':
|
|
20
|
+
declare const fullSchema: {
|
|
21
|
+
${segmentNames.map((segmentName) => ` '${segmentName}': typeof import('./${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json');`).join('\n')}
|
|
23
22
|
};
|
|
24
|
-
export default
|
|
25
|
-
const jsAbsolutePath = path.join(schemaOutAbsolutePath, 'index.
|
|
26
|
-
const dTsAbsolutePath = path.join(schemaOutAbsolutePath, 'index.d.
|
|
23
|
+
export default fullSchema;`;
|
|
24
|
+
const jsAbsolutePath = path.join(schemaOutAbsolutePath, 'index.cjs');
|
|
25
|
+
const dTsAbsolutePath = path.join(schemaOutAbsolutePath, 'index.d.cts');
|
|
27
26
|
const existingJs = await fs.readFile(jsAbsolutePath, 'utf-8').catch(() => null);
|
|
28
27
|
const existingDTs = await fs.readFile(dTsAbsolutePath, 'utf-8').catch(() => null);
|
|
29
28
|
await fs.mkdir(schemaOutAbsolutePath, { recursive: true });
|
package/dist/dev/index.mjs
CHANGED
|
@@ -150,6 +150,7 @@ export class VovkDev {
|
|
|
150
150
|
}
|
|
151
151
|
else {
|
|
152
152
|
log.info('Config file has been updated');
|
|
153
|
+
this.#generate();
|
|
153
154
|
}
|
|
154
155
|
isInitial = false;
|
|
155
156
|
}, 1000);
|
|
@@ -347,7 +348,7 @@ export class VovkDev {
|
|
|
347
348
|
});
|
|
348
349
|
}
|
|
349
350
|
else {
|
|
350
|
-
log.info(`Ready in ${Date.now() - now}ms. Making
|
|
351
|
+
log.info(`Ready in ${Date.now() - now}ms. Making requests for schemas in a moment...`);
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
}
|
|
@@ -29,23 +29,23 @@ export default function logDiffResult(segmentName, diffResult, projectInfo) {
|
|
|
29
29
|
case 'controller':
|
|
30
30
|
switch (diffNormalizedItem.type) {
|
|
31
31
|
case 'added':
|
|
32
|
-
projectInfo.log.info(`Schema
|
|
32
|
+
projectInfo.log.info(`Schema for RPC ${chalkHighlightThing(diffNormalizedItem.name)} has been ${addedText} at ${formatLoggedSegmentName(segmentName)}`);
|
|
33
33
|
break;
|
|
34
34
|
case 'removed':
|
|
35
|
-
projectInfo.log.info(`Schema
|
|
35
|
+
projectInfo.log.info(`Schema for RPC ${chalkHighlightThing(diffNormalizedItem.name)} has been ${removedText} from ${formatLoggedSegmentName(segmentName)}`);
|
|
36
36
|
break;
|
|
37
37
|
}
|
|
38
38
|
break;
|
|
39
39
|
case 'controllerHandler':
|
|
40
40
|
switch (diffNormalizedItem.type) {
|
|
41
41
|
case 'added':
|
|
42
|
-
projectInfo.log.info(`Schema
|
|
42
|
+
projectInfo.log.info(`Schema for RPC method ${chalkHighlightThing(diffNormalizedItem.name)} has been ${addedText} at ${formatLoggedSegmentName(segmentName)}`);
|
|
43
43
|
break;
|
|
44
44
|
case 'removed':
|
|
45
|
-
projectInfo.log.info(`Schema
|
|
45
|
+
projectInfo.log.info(`Schema for RPC method ${chalkHighlightThing(diffNormalizedItem.name)} has been ${removedText} from ${formatLoggedSegmentName(segmentName)}`);
|
|
46
46
|
break;
|
|
47
47
|
case 'changed':
|
|
48
|
-
projectInfo.log.info(`Schema
|
|
48
|
+
projectInfo.log.info(`Schema for RPC method ${chalkHighlightThing(diffNormalizedItem.name)} has been ${changedText} at ${formatLoggedSegmentName(segmentName)}`);
|
|
49
49
|
break;
|
|
50
50
|
}
|
|
51
51
|
break;
|
package/dist/generate/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import getClientTemplates from './getClientTemplates.mjs';
|
|
|
7
7
|
export default async function generate({ projectInfo, segments, segmentsSchema, forceNothingWrittenLog, templates, prettify: prettifyClient, fullSchema, }) {
|
|
8
8
|
templates = templates ?? projectInfo.config.experimental_clientGenerateTemplateNames;
|
|
9
9
|
const noClient = templates?.[0] === 'none';
|
|
10
|
-
const { config, cwd, log,
|
|
10
|
+
const { config, cwd, log, clientImports, apiRoot } = projectInfo;
|
|
11
11
|
const { clientOutDirAbsolutePath, templateFiles } = getClientTemplates({ config, cwd, templateNames: templates });
|
|
12
12
|
// Ensure that each segment has a matching schema if it needs to be emitted:
|
|
13
13
|
for (let i = 0; i < segments.length; i++) {
|
|
@@ -21,14 +21,11 @@ export default async function generate({ projectInfo, segments, segmentsSchema,
|
|
|
21
21
|
}
|
|
22
22
|
const now = Date.now();
|
|
23
23
|
// Data for the EJS templates:
|
|
24
|
-
const
|
|
24
|
+
const template = {
|
|
25
25
|
apiRoot,
|
|
26
|
-
|
|
27
|
-
schemaOutImportPath,
|
|
28
|
-
validateOnClientImportPath,
|
|
29
|
-
createRPCImportPath,
|
|
26
|
+
imports: clientImports,
|
|
30
27
|
segments,
|
|
31
|
-
segmentsSchema,
|
|
28
|
+
fullSchema: segmentsSchema,
|
|
32
29
|
};
|
|
33
30
|
// Process each template in parallel
|
|
34
31
|
const processedTemplates = noClient
|
|
@@ -37,7 +34,11 @@ export default async function generate({ projectInfo, segments, segmentsSchema,
|
|
|
37
34
|
// Read the EJS template
|
|
38
35
|
const templateContent = await fs.readFile(templatePath, 'utf-8');
|
|
39
36
|
// Render the template
|
|
40
|
-
let rendered = templatePath.endsWith('.ejs')
|
|
37
|
+
let rendered = templatePath.endsWith('.ejs')
|
|
38
|
+
? ejs.render(templateContent, { template }, {
|
|
39
|
+
filename: templatePath,
|
|
40
|
+
})
|
|
41
|
+
: templateContent;
|
|
41
42
|
// Optionally prettify
|
|
42
43
|
if (prettifyClient || config.prettifyClient) {
|
|
43
44
|
rendered = await prettify(rendered, outPath);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { VovkStrictConfig } from '../types.mjs';
|
|
2
2
|
export default function getConfig({ clientOutDir, cwd }: {
|
|
3
3
|
clientOutDir?: string;
|
|
4
4
|
cwd: string;
|
|
5
5
|
}): Promise<{
|
|
6
|
-
config:
|
|
6
|
+
config: VovkStrictConfig;
|
|
7
7
|
srcRoot: string;
|
|
8
8
|
configAbsolutePaths: string[];
|
|
9
|
-
userConfig: VovkConfig | null;
|
|
9
|
+
userConfig: import("../types.mjs").VovkConfig | null;
|
|
10
10
|
error: Error | undefined;
|
|
11
11
|
}>;
|
|
@@ -5,11 +5,14 @@ export default async function getConfig({ clientOutDir, cwd }) {
|
|
|
5
5
|
const { configAbsolutePaths, error, userConfig } = await getUserConfig({ cwd });
|
|
6
6
|
const conf = userConfig ?? {};
|
|
7
7
|
const srcRoot = await getRelativeSrcRoot({ cwd });
|
|
8
|
+
const validateOnClientImport = env.VOVK_VALIDATE_ON_CLIENT_PATH ?? conf.validateOnClientImport ?? null;
|
|
9
|
+
const fetcherImport = env.VOVK_FETCHER_PATH ?? conf.fetcherImport ?? 'vovk/dist/client/defaultFetcher.js';
|
|
10
|
+
const createRPCImport = env.VOVK_CREATE_RPC_PATH ?? conf.createRPCImport ?? 'vovk/dist/client/createRPC.js';
|
|
8
11
|
const config = {
|
|
9
12
|
modulesDir: env.VOVK_MODULES_DIR ?? conf.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/'),
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
validateOnClientImport: typeof validateOnClientImport === 'string' ? [validateOnClientImport] : validateOnClientImport,
|
|
14
|
+
fetcherImport: typeof fetcherImport === 'string' ? [fetcherImport] : fetcherImport,
|
|
15
|
+
createRPCImport: typeof createRPCImport === 'string' ? [createRPCImport] : createRPCImport,
|
|
13
16
|
schemaOutDir: env.VOVK_SCHEMA_OUT_DIR ?? conf.schemaOutDir ?? './.vovk-schema',
|
|
14
17
|
clientOutDir: clientOutDir ?? env.VOVK_CLIENT_OUT_DIR ?? conf.clientOutDir ?? './node_modules/.vovk-client',
|
|
15
18
|
origin: (env.VOVK_ORIGIN ?? conf.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
|
|
@@ -9,11 +9,19 @@ export default function getProjectInfo({ port: givenPort, clientOutDir, cwd, }?:
|
|
|
9
9
|
apiRoot: string;
|
|
10
10
|
apiDir: string;
|
|
11
11
|
srcRoot: string;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
config: import("../types.mjs").VovkStrictConfig;
|
|
13
|
+
clientImports: {
|
|
14
|
+
schema: string;
|
|
15
|
+
fetcher: string;
|
|
16
|
+
createRPC: string;
|
|
17
|
+
validateOnClient: string | null;
|
|
18
|
+
module: {
|
|
19
|
+
schema: string;
|
|
20
|
+
fetcher: string;
|
|
21
|
+
createRPC: string;
|
|
22
|
+
validateOnClient: string | null;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
17
25
|
log: {
|
|
18
26
|
info: (msg: string) => void;
|
|
19
27
|
warn: (msg: string) => void;
|
|
@@ -9,16 +9,7 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, cw
|
|
|
9
9
|
const apiRoot = `${config.origin ?? ''}/${config.rootEntry}`;
|
|
10
10
|
const apiDir = path.join(srcRoot, 'app', config.rootEntry);
|
|
11
11
|
const schemaOutImportPath = path.relative(config.clientOutDir, config.schemaOutDir).replace(/\\/g, '/') + // windows fix
|
|
12
|
-
'/index.
|
|
13
|
-
const fetcherClientImportPath = config.fetcherPath.startsWith('.')
|
|
14
|
-
? path.relative(config.clientOutDir, config.fetcherPath)
|
|
15
|
-
: config.fetcherPath;
|
|
16
|
-
const createRPCImportPath = config.createRPCPath.startsWith('.')
|
|
17
|
-
? path.relative(config.clientOutDir, config.createRPCPath)
|
|
18
|
-
: config.createRPCPath;
|
|
19
|
-
const validateOnClientImportPath = config.validateOnClientPath?.startsWith('.')
|
|
20
|
-
? path.relative(config.clientOutDir, config.validateOnClientPath)
|
|
21
|
-
: config.validateOnClientPath;
|
|
12
|
+
'/index.cjs';
|
|
22
13
|
const log = getLogger(config.logLevel);
|
|
23
14
|
if (configAbsolutePaths.length > 1) {
|
|
24
15
|
log.warn(`Multiple config files found. Using the first one: ${configAbsolutePaths[0]}`);
|
|
@@ -26,17 +17,29 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, cw
|
|
|
26
17
|
if (!userConfig && configAbsolutePaths.length > 0) {
|
|
27
18
|
log.error(`Error reading config file at ${configAbsolutePaths[0]}: ${error?.message ?? 'Unknown Error'}`);
|
|
28
19
|
}
|
|
20
|
+
const getImportPath = (p) => (p.startsWith('.') ? path.relative(config.clientOutDir, p) : p);
|
|
21
|
+
const clientImports = {
|
|
22
|
+
schema: schemaOutImportPath,
|
|
23
|
+
fetcher: getImportPath(config.fetcherImport[0]),
|
|
24
|
+
createRPC: getImportPath(config.createRPCImport[0]),
|
|
25
|
+
validateOnClient: config.validateOnClientImport ? getImportPath(config.validateOnClientImport[0]) : null,
|
|
26
|
+
module: {
|
|
27
|
+
schema: schemaOutImportPath,
|
|
28
|
+
fetcher: getImportPath(config.fetcherImport[1] ?? config.fetcherImport[0]),
|
|
29
|
+
createRPC: getImportPath(config.createRPCImport[1] ?? config.createRPCImport[0]),
|
|
30
|
+
validateOnClient: config.validateOnClientImport
|
|
31
|
+
? getImportPath(config.validateOnClientImport[1] ?? config.validateOnClientImport[0])
|
|
32
|
+
: null,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
29
35
|
return {
|
|
30
36
|
cwd,
|
|
31
37
|
port,
|
|
32
38
|
apiRoot,
|
|
33
39
|
apiDir,
|
|
34
40
|
srcRoot,
|
|
35
|
-
schemaOutImportPath,
|
|
36
|
-
fetcherClientImportPath,
|
|
37
|
-
createRPCImportPath,
|
|
38
|
-
validateOnClientImportPath,
|
|
39
41
|
config,
|
|
42
|
+
clientImports,
|
|
40
43
|
log,
|
|
41
44
|
};
|
|
42
45
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -20,10 +20,10 @@ program
|
|
|
20
20
|
.command('dev')
|
|
21
21
|
.alias('d')
|
|
22
22
|
.description('start schema watcher (optional flag --next-dev to start it with Next.js)')
|
|
23
|
+
.argument('[nextArgs...]', 'extra arguments for the dev command')
|
|
23
24
|
.option('--next-dev', 'start schema watcher and Next.js with automatic port allocation')
|
|
24
25
|
.option('--exit', 'kill the processe when schema and client is generated')
|
|
25
|
-
.
|
|
26
|
-
.action(async (options, command) => {
|
|
26
|
+
.action(async (nextArgs, options) => {
|
|
27
27
|
const { nextDev, exit = false } = options;
|
|
28
28
|
const portAttempts = 30;
|
|
29
29
|
const PORT = !nextDev
|
|
@@ -40,7 +40,7 @@ program
|
|
|
40
40
|
if (nextDev) {
|
|
41
41
|
const { result } = concurrently([
|
|
42
42
|
{
|
|
43
|
-
command: `npx next dev ${
|
|
43
|
+
command: `npx next dev ${nextArgs.join(' ')}`,
|
|
44
44
|
name: 'Next.js Development Server',
|
|
45
45
|
env: { PORT },
|
|
46
46
|
},
|
|
@@ -72,7 +72,7 @@ program
|
|
|
72
72
|
program
|
|
73
73
|
.command('generate')
|
|
74
74
|
.alias('g')
|
|
75
|
-
.description('Generate client')
|
|
75
|
+
.description('Generate RPC client from schema')
|
|
76
76
|
.option('--out, --client-out-dir <path>', 'path to output directory')
|
|
77
77
|
.option('--template, --templates <templates...>', 'client code templates ("ts", "compiled", "python", "none", a custom path)')
|
|
78
78
|
.option('--full-schema [fileName]', 'generate client with full schema')
|
|
@@ -83,7 +83,7 @@ program
|
|
|
83
83
|
const { cwd, config, apiDir } = projectInfo;
|
|
84
84
|
const segments = await locateSegments({ dir: apiDir, config });
|
|
85
85
|
const schemaOutAbsolutePath = path.join(cwd, config.schemaOutDir);
|
|
86
|
-
const schemaImportUrl = pathToFileURL(path.join(schemaOutAbsolutePath, 'index.
|
|
86
|
+
const schemaImportUrl = pathToFileURL(path.join(schemaOutAbsolutePath, 'index.cjs')).href;
|
|
87
87
|
const { default: segmentsSchema } = (await import(schemaImportUrl));
|
|
88
88
|
await generate({
|
|
89
89
|
projectInfo,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type getLogger from '../utils/getLogger.mjs';
|
|
2
2
|
import type { InitOptions } from '../types.mjs';
|
|
3
|
-
export default function createConfig({ root, log, options: { validationLibrary, validateOnClient, channel, dryRun }, }: {
|
|
3
|
+
export default function createConfig({ root, log, options: { validationLibrary, validateOnClient, reactQuery, channel, dryRun }, }: {
|
|
4
4
|
root: string;
|
|
5
5
|
log: ReturnType<typeof getLogger>;
|
|
6
|
-
options: Pick<InitOptions, 'validationLibrary' | 'validateOnClient' | 'channel' | 'dryRun'>;
|
|
6
|
+
options: Pick<InitOptions, 'validationLibrary' | 'validateOnClient' | 'reactQuery' | 'channel' | 'dryRun'>;
|
|
7
7
|
}): Promise<{
|
|
8
8
|
configAbsolutePath: string;
|
|
9
9
|
}>;
|
|
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import getTemplateFilesFromPackage from './getTemplateFilesFromPackage.mjs';
|
|
4
4
|
import prettify from '../utils/prettify.mjs';
|
|
5
5
|
import getFileSystemEntryType, { FileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
|
|
6
|
-
export default async function createConfig({ root, log, options: { validationLibrary, validateOnClient, channel, dryRun }, }) {
|
|
6
|
+
export default async function createConfig({ root, log, options: { validationLibrary, validateOnClient, reactQuery, 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;
|
|
@@ -17,7 +17,7 @@ export default async function createConfig({ root, log, options: { validationLib
|
|
|
17
17
|
};
|
|
18
18
|
if (validationLibrary) {
|
|
19
19
|
if (validateOnClient) {
|
|
20
|
-
config.
|
|
20
|
+
config.validateOnClientImport = `${validationLibrary}/validateOnClient.js`;
|
|
21
21
|
}
|
|
22
22
|
try {
|
|
23
23
|
const validationTemplates = await getTemplateFilesFromPackage(validationLibrary, channel);
|
|
@@ -27,6 +27,9 @@ export default async function createConfig({ root, log, options: { validationLib
|
|
|
27
27
|
log.warn(`Failed to fetch validation library templates: ${error.message}`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
if (reactQuery) {
|
|
31
|
+
config.createRPCImport = 'vovk-react-query';
|
|
32
|
+
}
|
|
30
33
|
config.templates = templates;
|
|
31
34
|
const configStr = await prettify(`/** @type {import('vovk-cli').VovkConfig} */
|
|
32
35
|
const config = ${JSON.stringify(config, null, 2)};
|
package/dist/init/index.d.mts
CHANGED
|
@@ -4,5 +4,5 @@ export declare class Init {
|
|
|
4
4
|
#private;
|
|
5
5
|
root: string;
|
|
6
6
|
log: ReturnType<typeof getLogger>;
|
|
7
|
-
main(prefix: string, { yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, dryRun, channel, }: InitOptions): Promise<void>;
|
|
7
|
+
main(prefix: string, { yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, reactQuery, dryRun, channel, }: InitOptions): Promise<void>;
|
|
8
8
|
}
|
package/dist/init/index.mjs
CHANGED
|
@@ -17,10 +17,10 @@ import NPMCliPackageJson from '@npmcli/package-json';
|
|
|
17
17
|
export class Init {
|
|
18
18
|
root;
|
|
19
19
|
log;
|
|
20
|
-
async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, dryRun, channel, }) {
|
|
20
|
+
async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, reactQuery, dryRun, channel, }) {
|
|
21
21
|
const { log, root } = this;
|
|
22
22
|
const dependencies = ['vovk', 'vovk-client'];
|
|
23
|
-
const devDependencies = ['vovk-cli'];
|
|
23
|
+
const devDependencies = ['vovk-cli', 'openapi3-ts'];
|
|
24
24
|
// delete older config files
|
|
25
25
|
if (configPaths.length) {
|
|
26
26
|
await Promise.all(configPaths.map((configPath) => fs.rm(configPath)));
|
|
@@ -34,6 +34,10 @@ export class Init {
|
|
|
34
34
|
'vovk-dto': ['class-validator', 'class-transformer', 'vovk-mapped-types', 'reflect-metadata'],
|
|
35
35
|
}[validationLibrary] ?? []));
|
|
36
36
|
}
|
|
37
|
+
if (reactQuery) {
|
|
38
|
+
dependencies.push('vovk-react-query');
|
|
39
|
+
dependencies.push('@tanstack/react-query');
|
|
40
|
+
}
|
|
37
41
|
if (updateScripts) {
|
|
38
42
|
try {
|
|
39
43
|
if (!dryRun)
|
|
@@ -102,7 +106,7 @@ export class Init {
|
|
|
102
106
|
const { configAbsolutePath } = await createConfig({
|
|
103
107
|
root,
|
|
104
108
|
log,
|
|
105
|
-
options: { validationLibrary, validateOnClient, channel, dryRun },
|
|
109
|
+
options: { validationLibrary, validateOnClient, reactQuery, channel, dryRun },
|
|
106
110
|
});
|
|
107
111
|
log.info('Config created successfully at ' + configAbsolutePath);
|
|
108
112
|
}
|
|
@@ -110,7 +114,7 @@ export class Init {
|
|
|
110
114
|
log.error(`Failed to create config: ${error.message}`);
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
|
-
async main(prefix, { yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, dryRun, channel, }) {
|
|
117
|
+
async main(prefix, { yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, reactQuery, dryRun, channel, }) {
|
|
114
118
|
const cwd = process.cwd();
|
|
115
119
|
const root = path.resolve(cwd, prefix);
|
|
116
120
|
const log = getLogger(logLevel);
|
|
@@ -129,6 +133,7 @@ export class Init {
|
|
|
129
133
|
updateScripts: updateScripts ?? 'implicit',
|
|
130
134
|
validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'vovk-zod'),
|
|
131
135
|
validateOnClient: validateOnClient ?? true,
|
|
136
|
+
reactQuery: reactQuery ?? true,
|
|
132
137
|
dryRun: dryRun ?? false,
|
|
133
138
|
channel: channel ?? 'latest',
|
|
134
139
|
});
|
|
@@ -181,7 +186,7 @@ export class Init {
|
|
|
181
186
|
updateScripts =
|
|
182
187
|
updateScripts ??
|
|
183
188
|
(await select({
|
|
184
|
-
message: 'Do you want to update package.json by adding "generate" and "dev" NPM scripts?',
|
|
189
|
+
message: 'Do you want to update package.json by adding "generate" and updating "dev" NPM scripts?',
|
|
185
190
|
default: 'implicit',
|
|
186
191
|
choices: [
|
|
187
192
|
{
|
|
@@ -201,17 +206,22 @@ export class Init {
|
|
|
201
206
|
},
|
|
202
207
|
],
|
|
203
208
|
}));
|
|
209
|
+
reactQuery =
|
|
210
|
+
reactQuery ??
|
|
211
|
+
(await confirm({
|
|
212
|
+
message: 'Do you want to use @tanstack/react-query for data fetching at React components?',
|
|
213
|
+
}));
|
|
204
214
|
if (typeof updateTsConfig === 'undefined') {
|
|
205
215
|
let shouldAsk = false;
|
|
206
216
|
try {
|
|
207
217
|
shouldAsk = !(await checkTSConfigForExperimentalDecorators(root));
|
|
208
218
|
}
|
|
209
219
|
catch (error) {
|
|
210
|
-
log.error(`Failed to check tsconfig.json for experimentalDecorators: ${error.message}`);
|
|
220
|
+
log.error(`Failed to check tsconfig.json for "experimentalDecorators": ${error.message}`);
|
|
211
221
|
}
|
|
212
222
|
if (shouldAsk) {
|
|
213
223
|
updateTsConfig = await confirm({
|
|
214
|
-
message: 'Do you want to add experimentalDecorators to tsconfig.json?',
|
|
224
|
+
message: 'Do you want to add "experimentalDecorators" option to tsconfig.json?',
|
|
215
225
|
});
|
|
216
226
|
}
|
|
217
227
|
}
|
|
@@ -225,6 +235,7 @@ export class Init {
|
|
|
225
235
|
updateScripts,
|
|
226
236
|
validationLibrary,
|
|
227
237
|
validateOnClient,
|
|
238
|
+
reactQuery,
|
|
228
239
|
dryRun,
|
|
229
240
|
channel,
|
|
230
241
|
});
|
package/dist/initProgram.mjs
CHANGED
|
@@ -2,20 +2,21 @@ import { Init } from './init/index.mjs';
|
|
|
2
2
|
// reused at vovk-init
|
|
3
3
|
export default function initProgram(program) {
|
|
4
4
|
return program
|
|
5
|
-
.argument('[prefix]', '
|
|
6
|
-
.description('Initialize Vovk project')
|
|
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('--validation-library <library>', '
|
|
17
|
-
.option('--validate-on-client', '
|
|
18
|
-
.option('--
|
|
19
|
-
.option('--
|
|
5
|
+
.argument('[prefix]', 'directory to initialize project in', '.')
|
|
6
|
+
.description('Initialize Vovk.ts 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')
|
|
17
|
+
.option('--validate-on-client', 'path to validateOnClient file')
|
|
18
|
+
.option('--react-query', 'use @tanstack/react-query for data fetching inside components')
|
|
19
|
+
.option('--channel <channel>', 'channel to use for fetching packages', 'latest')
|
|
20
|
+
.option('--dry-run', 'do not write files to disk')
|
|
20
21
|
.action((prefix = '.', options) => new Init().main(prefix, options));
|
|
21
22
|
}
|
package/dist/new/newSegment.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
|
|
|
5
5
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
6
6
|
import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
|
|
7
7
|
import prettify from '../utils/prettify.mjs';
|
|
8
|
+
import chalk from 'chalk';
|
|
8
9
|
export default async function newSegment({ segmentName, overwrite, dryRun, }) {
|
|
9
10
|
const { apiDir, cwd, log } = await getProjectInfo();
|
|
10
11
|
const absoluteSegmentRoutePath = path.join(cwd, apiDir, segmentName, '[[...vovk]]/route.ts');
|
|
@@ -29,5 +30,6 @@ ${segmentName ? ` segmentName: '${segmentName}',\n` : ''} emitSchema: true,
|
|
|
29
30
|
await fs.writeFile(absoluteSegmentRoutePath, code);
|
|
30
31
|
}
|
|
31
32
|
log.info(`${formatLoggedSegmentName(segmentName, { upperFirst: true })} created at ${absoluteSegmentRoutePath}.`);
|
|
32
|
-
|
|
33
|
+
const dir = chalk.cyanBright([segmentName, 'thing'].filter(Boolean).join('/'));
|
|
34
|
+
log.info(`Run ${chalkHighlightThing(`npx vovk new service controller ${dir}`)} to create a new controller with a service at modules/${dir} folder for this segment`);
|
|
33
35
|
}
|
package/dist/types.d.mts
CHANGED
|
@@ -21,9 +21,9 @@ export type VovkEnv = {
|
|
|
21
21
|
export type VovkConfig = {
|
|
22
22
|
clientOutDir?: string;
|
|
23
23
|
schemaOutDir?: string;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
fetcherImport?: string | string[];
|
|
25
|
+
validateOnClientImport?: string | string[] | null;
|
|
26
|
+
createRPCImport?: string | string[];
|
|
27
27
|
modulesDir?: string;
|
|
28
28
|
rootEntry?: string;
|
|
29
29
|
origin?: string;
|
|
@@ -38,6 +38,11 @@ export type VovkConfig = {
|
|
|
38
38
|
[key: string]: string | undefined;
|
|
39
39
|
};
|
|
40
40
|
};
|
|
41
|
+
export type VovkStrictConfig = Required<Omit<VovkConfig, 'validateOnClientImport' | 'fetcherImport' | 'createRPCImport'>> & {
|
|
42
|
+
validateOnClientImport: string[] | null;
|
|
43
|
+
fetcherImport: string[];
|
|
44
|
+
createRPCImport: string[];
|
|
45
|
+
};
|
|
41
46
|
export type VovkModuleRenderResult = {
|
|
42
47
|
fileName: string;
|
|
43
48
|
dir: string;
|
|
@@ -66,6 +71,7 @@ export interface InitOptions {
|
|
|
66
71
|
updateTsConfig?: boolean;
|
|
67
72
|
updateScripts?: 'implicit' | 'explicit';
|
|
68
73
|
validationLibrary?: string | null;
|
|
74
|
+
reactQuery?: boolean;
|
|
69
75
|
validateOnClient?: boolean;
|
|
70
76
|
dryRun?: boolean;
|
|
71
77
|
channel?: 'latest' | 'beta' | 'draft';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vovk-cli",
|
|
3
|
-
"version": "0.0.1-draft.
|
|
3
|
+
"version": "0.0.1-draft.68",
|
|
4
4
|
"bin": {
|
|
5
5
|
"vovk": "./dist/index.mjs"
|
|
6
6
|
},
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://vovk.dev",
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"vovk": "^3.0.0-draft.
|
|
39
|
+
"vovk": "^3.0.0-draft.67"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@inquirer/prompts": "^7.3.1",
|
|
43
43
|
"@npmcli/package-json": "^6.1.1",
|
|
44
44
|
"chalk": "^5.4.1",
|
|
45
45
|
"chokidar": "^4.0.3",
|
|
46
|
-
"commander": "^
|
|
46
|
+
"commander": "^13.1.0",
|
|
47
47
|
"concurrently": "^9.1.2",
|
|
48
48
|
"dotenv": "^16.4.7",
|
|
49
49
|
"ejs": "^3.1.10",
|