vovk-cli 0.0.1-draft.352 → 0.0.1-draft.353
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/cjs/index.cjs.ejs +0 -1
- package/client-templates/mixins/mixins.d.ts.ejs +4 -4
- package/client-templates/readme/README.md.ejs +2 -2
- package/client-templates/schemaCjs/schema.cjs.ejs +6 -5
- package/client-templates/schemaTs/schema.ts.ejs +8 -11
- package/dist/generate/generate.mjs +27 -17
- package/dist/generate/getProjectFullSchema.mjs +2 -8
- package/dist/generate/getTemplateClientImports.mjs +2 -2
- package/dist/generate/index.mjs +1 -5
- package/dist/generate/writeOneClientFile.d.mts +4 -3
- package/dist/generate/writeOneClientFile.mjs +8 -5
- package/dist/getProjectInfo/getConfig/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/utils/deepExtend.d.mts +54 -0
- package/dist/utils/deepExtend.mjs +129 -0
- package/dist/utils/normalizeOpenAPIMixin.d.mts +1 -1
- package/package.json +15 -14
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
const { createRPC } = require('<%= t.commonImports.createRPC %>');
|
|
3
3
|
const { schema } = require('./schema.cjs');
|
|
4
4
|
const { openapi } = require('./openapi.cjs');
|
|
5
|
-
const { validateOnClient = null } = <%- t.imports.validateOnClient ? `require('${t.imports.validateOnClient}')` : '{}'%>;
|
|
6
5
|
<% Object.entries(t.reExports).forEach(([reExportWhatCommaDivisible, reExportFrom]) => {
|
|
7
6
|
reExportWhatCommaDivisible.split(/\s*,\s*/).forEach((reExportWhat) => { %>
|
|
8
7
|
exports['<%= reExportWhat.split(/\s+as\s+/)[1] ?? reExportWhat %>'] = require('<%= reExportFrom %>')['<%= reExportWhat.split(/\s+as\s+/)[0] %>'];
|
|
@@ -5,10 +5,10 @@ import type { VovkRequest, VovkStreamAsyncIterable, KnownAny } from 'vovk';
|
|
|
5
5
|
|
|
6
6
|
export namespace Mixins {
|
|
7
7
|
<% for (const segment of mixins) { %>
|
|
8
|
-
<% if(segment.meta?.components?.schemas) { %>
|
|
8
|
+
<% if(segment.meta?.openAPIObject?.components?.schemas) { %>
|
|
9
9
|
export namespace <%= t._.upperFirst(t._.camelCase(segment.segmentName)) %> {
|
|
10
|
-
<% for (const [componentName, componentSchema] of Object.entries(segment.meta.components.schemas)) { %>
|
|
11
|
-
<%- t.compileJSONSchemaToTypeScriptType(componentSchema, componentName, segment.meta.components, { dontCreateRefTypes: true }) %>
|
|
10
|
+
<% for (const [componentName, componentSchema] of Object.entries(segment.meta.openAPIObject.components.schemas)) { %>
|
|
11
|
+
<%- t.compileJSONSchemaToTypeScriptType(componentSchema, componentName, segment.meta.openAPIObject.components, { dontCreateRefTypes: true }) %>
|
|
12
12
|
<% } %>
|
|
13
13
|
}
|
|
14
14
|
<% } %>
|
|
@@ -56,7 +56,7 @@ export type Controllers = {
|
|
|
56
56
|
<%- getType(segment, controllerSchema, handlerName, 'body') %>,
|
|
57
57
|
<%- getType(segment, controllerSchema, handlerName, 'query') %>,
|
|
58
58
|
<%- getType(segment, controllerSchema, handlerName, 'params') %>
|
|
59
|
-
>) => <%- handlerSchema.validation?.output ? `Promise<${getType(segment, controllerSchema, handlerName, 'output')}>` : handlerSchema.validation?.iteration ? `Promise<VovkStreamAsyncIterable<${getType(segment, controllerSchema, handlerName, 'iteration')}
|
|
59
|
+
>) => <%- handlerSchema.validation?.output ? `Promise<${getType(segment, controllerSchema, handlerName, 'output')}>` : handlerSchema.validation?.iteration ? `Promise<VovkStreamAsyncIterable<${getType(segment, controllerSchema, handlerName, 'iteration')}>>` : 'Promise<KnownAny>' %>,
|
|
60
60
|
<% } %>
|
|
61
61
|
};
|
|
62
62
|
<% } %>
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
`<%= handlerSchema.httpMethod %> <%= [...(forceApiRoot ? [forceApiRoot] : [t.apiRoot, segmentName]), controllerSchema.prefix, handlerSchema.path].map((part, i) => i > 0 ? t._.trim(part, '/') : part).filter(Boolean).join('/') %>`
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
|
-
<%- t.
|
|
29
|
+
<%- t.createCodeSamples({
|
|
30
30
|
handlerSchema,
|
|
31
31
|
handlerName,
|
|
32
32
|
controllerSchema,
|
|
33
33
|
package: t.package,
|
|
34
|
-
config: t.
|
|
34
|
+
config: t.samples,
|
|
35
35
|
}).ts %>
|
|
36
36
|
```
|
|
37
37
|
<% }) %>
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
<%- t.getFirstLineBanner() %>
|
|
2
2
|
<% if(t.isVovkProject) { %>
|
|
3
3
|
const meta = require('./<%= t.schemaOutDir %>/_meta.json');
|
|
4
|
+
<% } else { %>
|
|
5
|
+
const meta = <%- JSON.stringify(t.publicMeta, null, 2) %>;
|
|
4
6
|
<% } %>
|
|
7
|
+
|
|
5
8
|
<% if(t.hasMixins) { %>
|
|
6
9
|
const mixins = require('./mixins.json');
|
|
7
10
|
<% } %>
|
|
8
|
-
const segments = {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema
|
|
11
|
+
const segments = {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment) => { %>
|
|
9
12
|
'<%= segment.segmentName %>': require('./<%= t.schemaOutDir %>/<%= segment.segmentName || t.ROOT_SEGMENT_FILE_NAME %>.json'),
|
|
10
|
-
<% }
|
|
13
|
+
<% }) %>
|
|
11
14
|
<% if(t.hasMixins) { %>
|
|
12
15
|
...mixins,
|
|
13
16
|
<% } %>
|
|
@@ -15,9 +18,7 @@ const segments = {<% Object.values(t.schema.segments).filter((segment) => segmen
|
|
|
15
18
|
const schema = {
|
|
16
19
|
$schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>',
|
|
17
20
|
segments,
|
|
18
|
-
meta
|
|
19
|
-
<% if(t.isVovkProject) { %>...meta<% } %>
|
|
20
|
-
}
|
|
21
|
+
meta,
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
module.exports.schema = schema;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<%- t.getFirstLineBanner() %>
|
|
2
|
-
<% if(t.isVovkProject) { %>
|
|
3
|
-
import meta from './<%= t.schemaOutDir %>/_meta.json' with { type: "json" };
|
|
4
|
-
<% } %>
|
|
5
2
|
<% if(t.hasMixins) { %>
|
|
6
3
|
import mixins from './mixins.json' with { type: "json" };
|
|
7
4
|
import type { Mixins } from './mixins.d.ts';
|
|
8
5
|
<% } %>
|
|
9
|
-
<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => {
|
|
6
|
+
<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment, i) => { %>
|
|
10
7
|
import segment<%= i %> from './<%= t.schemaOutDir %>/<%= segment.segmentName || t.ROOT_SEGMENT_FILE_NAME %>.json' with { type: "json" };
|
|
8
|
+
<% }); %>
|
|
9
|
+
<% if(t.isVovkProject) { %>
|
|
10
|
+
import meta from './<%= t.schemaOutDir %>/_meta.json' with { type: "json" };
|
|
11
11
|
<% } else { %>
|
|
12
|
-
|
|
13
|
-
<% }
|
|
14
|
-
const segments = {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => { %>
|
|
12
|
+
const meta = <%- JSON.stringify(t.publicMeta, null, 2) %>;
|
|
13
|
+
<% } %>
|
|
14
|
+
const segments = {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment, i) => { %>
|
|
15
15
|
'<%= segment.segmentName %>': segment<%= i %>,<% }) %>
|
|
16
16
|
<% if(t.hasMixins) { %>
|
|
17
17
|
...mixins,
|
|
@@ -21,11 +21,8 @@ const segments = {<% Object.values(t.schema.segments).filter((segment) => segmen
|
|
|
21
21
|
export const schema = {
|
|
22
22
|
$schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>',
|
|
23
23
|
segments,
|
|
24
|
-
meta
|
|
25
|
-
<% if(t.isVovkProject) { %>...meta,<% } %>
|
|
26
|
-
}
|
|
24
|
+
meta,
|
|
27
25
|
};
|
|
28
|
-
|
|
29
26
|
<% if (t.hasMixins) { %>
|
|
30
27
|
export { Mixins };
|
|
31
28
|
<% } %>
|
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import matter from 'gray-matter';
|
|
4
4
|
import _ from 'lodash';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveGeneratorConfigValues, openAPIToVovkSchema, vovkSchemaToOpenAPI, } from 'vovk';
|
|
6
6
|
import getClientTemplateFiles from './getClientTemplateFiles.mjs';
|
|
7
7
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
8
8
|
import pickSegmentFullSchema from '../utils/pickSegmentFullSchema.mjs';
|
|
@@ -68,10 +68,10 @@ const cliOptionsToOpenAPIMixins = ({ openapiGetMethodName, openapiGetModuleName,
|
|
|
68
68
|
source: spec.startsWith('http://') || spec.startsWith('https://')
|
|
69
69
|
? { url: spec, fallback: openapiFallback?.[i] }
|
|
70
70
|
: { file: spec },
|
|
71
|
-
apiRoot: openapiRootUrl?.[i] ?? '
|
|
72
|
-
getModuleName: openapiGetModuleName?.[i] ??
|
|
71
|
+
apiRoot: openapiRootUrl?.[i] ?? '',
|
|
72
|
+
getModuleName: openapiGetModuleName?.[i] ?? 'api',
|
|
73
73
|
getMethodName: openapiGetMethodName?.[i] ?? 'auto',
|
|
74
|
-
mixinName: openapiMixinName?.[i],
|
|
74
|
+
mixinName: openapiMixinName?.[i] ?? 'mixin' + (i > 0 ? i + 1 : ''),
|
|
75
75
|
};
|
|
76
76
|
}) || []).map(({ source, apiRoot, getModuleName, getMethodName, mixinName }) => [
|
|
77
77
|
mixinName,
|
|
@@ -103,13 +103,20 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
103
103
|
};
|
|
104
104
|
});
|
|
105
105
|
const cliMixins = cliOptionsToOpenAPIMixins(cliGenerateOptions ?? {});
|
|
106
|
-
|
|
107
|
-
fullSchema.segments
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
fullSchema.segments = {
|
|
107
|
+
...fullSchema.segments,
|
|
108
|
+
...Object.fromEntries(await Promise.all(Object.entries(cliMixins).map(async ([mixinName, mixinModule]) => {
|
|
109
|
+
return [
|
|
110
|
+
mixinName,
|
|
111
|
+
openAPIToVovkSchema({
|
|
112
|
+
segmentName: mixinName,
|
|
113
|
+
...(await normalizeOpenAPIMixin({ mixinModule, log })),
|
|
114
|
+
}).segments[mixinName],
|
|
115
|
+
];
|
|
116
|
+
}))),
|
|
117
|
+
};
|
|
118
|
+
const moduleResolution = await getTsconfig(cwd)?.config?.compilerOptions?.moduleResolution?.toLowerCase();
|
|
119
|
+
const isNodeNextResolution = !moduleResolution || ['node16', 'nodenext'].includes(moduleResolution ?? '');
|
|
113
120
|
const isVovkProject = !!srcRoot;
|
|
114
121
|
const isComposedEnabled = cliGenerateOptions?.composedOnly ||
|
|
115
122
|
!!cliGenerateOptions?.composedFrom ||
|
|
@@ -135,13 +142,14 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
135
142
|
const matterResult = templateFilePath.endsWith('.ejs')
|
|
136
143
|
? matter(templateContent)
|
|
137
144
|
: { data: { imports: [] }, content: templateContent };
|
|
138
|
-
const { package: packageJson, readme, origin,
|
|
145
|
+
const { package: packageJson, readme, origin, samples, reExports, } = resolveGeneratorConfigValues({
|
|
139
146
|
schema: fullSchema,
|
|
140
147
|
configs: [templateDef.generatorConfig ?? {}],
|
|
141
148
|
projectPackageJson,
|
|
142
149
|
isBundle,
|
|
143
150
|
segmentName: null,
|
|
144
151
|
});
|
|
152
|
+
// console.log('reExports', fullSchema.meta)
|
|
145
153
|
const openapi = vovkSchemaToOpenAPI({
|
|
146
154
|
schema: fullSchema,
|
|
147
155
|
rootEntry: config.rootEntry,
|
|
@@ -156,14 +164,14 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
156
164
|
projectInfo,
|
|
157
165
|
clientTemplateFile,
|
|
158
166
|
fullSchema: composedFullSchema,
|
|
159
|
-
prettifyClient: config.composedClient.prettifyClient,
|
|
167
|
+
prettifyClient: cliGenerateOptions?.prettify ?? config.composedClient.prettifyClient,
|
|
160
168
|
segmentName: null,
|
|
161
169
|
templateContent,
|
|
162
170
|
matterResult,
|
|
163
171
|
openapi,
|
|
164
172
|
package: packageJson,
|
|
165
173
|
readme,
|
|
166
|
-
|
|
174
|
+
samples,
|
|
167
175
|
reExports,
|
|
168
176
|
isEnsuringClient,
|
|
169
177
|
outCwdRelativeDir,
|
|
@@ -177,6 +185,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
177
185
|
origin: cliGenerateOptions?.origin ?? origin,
|
|
178
186
|
configKey: 'composedClient',
|
|
179
187
|
cliSchemaPath: cliGenerateOptions?.schemaPath ?? null,
|
|
188
|
+
projectConfig: config,
|
|
180
189
|
});
|
|
181
190
|
const outAbsoluteDir = path.resolve(cwd, outCwdRelativeDir);
|
|
182
191
|
return {
|
|
@@ -218,7 +227,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
218
227
|
? matter(templateContent)
|
|
219
228
|
: { data: { imports: [] }, content: templateContent };
|
|
220
229
|
const results = await Promise.all(segmentNames.map(async (segmentName) => {
|
|
221
|
-
const { package: packageJson, readme, origin,
|
|
230
|
+
const { package: packageJson, readme, origin, samples, reExports, } = resolveGeneratorConfigValues({
|
|
222
231
|
schema: fullSchema,
|
|
223
232
|
configs: [templateDef.generatorConfig ?? {}],
|
|
224
233
|
projectPackageJson,
|
|
@@ -240,14 +249,14 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
240
249
|
projectInfo,
|
|
241
250
|
clientTemplateFile,
|
|
242
251
|
fullSchema: segmentedFullSchema,
|
|
243
|
-
prettifyClient: config.segmentedClient.prettifyClient,
|
|
252
|
+
prettifyClient: cliGenerateOptions?.prettify ?? config.segmentedClient.prettifyClient,
|
|
244
253
|
segmentName,
|
|
245
254
|
templateContent,
|
|
246
255
|
matterResult,
|
|
247
256
|
openapi,
|
|
248
257
|
package: packageJson,
|
|
249
258
|
readme,
|
|
250
|
-
|
|
259
|
+
samples,
|
|
251
260
|
reExports,
|
|
252
261
|
isEnsuringClient,
|
|
253
262
|
outCwdRelativeDir,
|
|
@@ -261,6 +270,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
|
|
|
261
270
|
origin: cliGenerateOptions?.origin ?? origin,
|
|
262
271
|
configKey: 'segmentedClient',
|
|
263
272
|
cliSchemaPath: cliGenerateOptions?.schemaPath ?? null,
|
|
273
|
+
projectConfig: config,
|
|
264
274
|
});
|
|
265
275
|
return {
|
|
266
276
|
written,
|
|
@@ -4,6 +4,7 @@ import { glob } from 'glob';
|
|
|
4
4
|
import { VovkSchemaIdEnum } from 'vovk';
|
|
5
5
|
import { META_FILE_NAME, ROOT_SEGMENT_FILE_NAME } from '../dev/writeOneSegmentSchemaFile.mjs';
|
|
6
6
|
import getMetaSchema from '../getProjectInfo/getMetaSchema.mjs';
|
|
7
|
+
import deepExtend from '../utils/deepExtend.mjs';
|
|
7
8
|
export async function getProjectFullSchema({ schemaOutAbsolutePath, isNextInstalled, log, config, }) {
|
|
8
9
|
const result = {
|
|
9
10
|
$schema: VovkSchemaIdEnum.SCHEMA,
|
|
@@ -19,14 +20,7 @@ export async function getProjectFullSchema({ schemaOutAbsolutePath, isNextInstal
|
|
|
19
20
|
try {
|
|
20
21
|
const metaContent = await readFile(metaPath, 'utf-8');
|
|
21
22
|
const fromFileMeta = JSON.parse(metaContent);
|
|
22
|
-
result.meta = {
|
|
23
|
-
...result.meta,
|
|
24
|
-
...fromFileMeta,
|
|
25
|
-
config: {
|
|
26
|
-
...result.meta?.config,
|
|
27
|
-
...fromFileMeta?.config,
|
|
28
|
-
},
|
|
29
|
-
};
|
|
23
|
+
result.meta = deepExtend({}, result.meta, fromFileMeta);
|
|
30
24
|
}
|
|
31
25
|
catch {
|
|
32
26
|
isEmptyLogOrWarn(`${META_FILE_NAME}.json not found at ${metaPath}. Using empty meta as fallback.`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { resolveGeneratorConfigValues } from 'vovk';
|
|
3
3
|
import { ROOT_SEGMENT_FILE_NAME } from '../dev/writeOneSegmentSchemaFile.mjs';
|
|
4
4
|
export default function getTemplateClientImports({ fullSchema, outCwdRelativeDir, segmentName, isBundle, }) {
|
|
5
|
-
const { imports: configImports } =
|
|
5
|
+
const { imports: configImports } = resolveGeneratorConfigValues({ schema: fullSchema, segmentName, isBundle });
|
|
6
6
|
const validateOnClientImport = configImports?.validateOnClient ?? null;
|
|
7
7
|
const fetcherImport = configImports?.fetcher ?? 'vovk';
|
|
8
8
|
const createRPCImport = configImports?.createRPC ?? 'vovk';
|
package/dist/generate/index.mjs
CHANGED
|
@@ -115,7 +115,7 @@ export class VovkGenerate {
|
|
|
115
115
|
.watch(openApiSpecPaths, {
|
|
116
116
|
cwd,
|
|
117
117
|
persistent: true,
|
|
118
|
-
ignoreInitial:
|
|
118
|
+
ignoreInitial: false,
|
|
119
119
|
})
|
|
120
120
|
.on('all', (event, path) => {
|
|
121
121
|
if (event === 'change' || event === 'add' || event === 'ready' || event === 'unlink') {
|
|
@@ -159,10 +159,6 @@ export class VovkGenerate {
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
const content = await response.text();
|
|
162
|
-
if (lastContent === null) {
|
|
163
|
-
lastContent = content;
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
162
|
if (content !== lastContent) {
|
|
167
163
|
log.info(`Remote OpenAPI spec changed at ${chalkHighlightThing(openApiSpecUrl)}`);
|
|
168
164
|
lastContent = content;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { VovkReadmeConfig,
|
|
1
|
+
import { VovkReadmeConfig, VovkSamplesConfig, type VovkSchema, type VovkStrictConfig } from 'vovk';
|
|
2
2
|
import type { PackageJson } from 'type-fest';
|
|
3
3
|
import type { ProjectInfo } from '../getProjectInfo/index.mjs';
|
|
4
4
|
import type { ClientTemplateFile } from './getClientTemplateFiles.mjs';
|
|
5
5
|
import type { Segment } from '../locateSegments.mjs';
|
|
6
6
|
import { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
7
7
|
export declare function normalizeOutTemplatePath(out: string, packageJson: PackageJson): string;
|
|
8
|
-
export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName, templateContent, matterResult: { data, content }, openapi, package: packageJson, readme,
|
|
8
|
+
export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName, templateContent, matterResult: { data, content }, openapi, package: packageJson, readme, samples, reExports, isEnsuringClient, outCwdRelativeDir, locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, configKey, cliSchemaPath, projectConfig, }: {
|
|
9
9
|
cwd: string;
|
|
10
10
|
projectInfo: ProjectInfo;
|
|
11
11
|
clientTemplateFile: ClientTemplateFile;
|
|
@@ -22,7 +22,7 @@ export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFil
|
|
|
22
22
|
openapi: OpenAPIObject;
|
|
23
23
|
package: PackageJson;
|
|
24
24
|
readme: VovkReadmeConfig;
|
|
25
|
-
|
|
25
|
+
samples: VovkSamplesConfig;
|
|
26
26
|
reExports: VovkStrictConfig['generatorConfig']['reExports'];
|
|
27
27
|
isEnsuringClient: boolean;
|
|
28
28
|
outCwdRelativeDir: string;
|
|
@@ -36,6 +36,7 @@ export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFil
|
|
|
36
36
|
origin: string | null;
|
|
37
37
|
configKey: 'composedClient' | 'segmentedClient';
|
|
38
38
|
cliSchemaPath: string | null;
|
|
39
|
+
projectConfig: VovkStrictConfig;
|
|
39
40
|
}): Promise<{
|
|
40
41
|
written: boolean;
|
|
41
42
|
}>;
|
|
@@ -2,21 +2,22 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import ejs from 'ejs';
|
|
4
4
|
import _ from 'lodash';
|
|
5
|
-
import {
|
|
5
|
+
import { createCodeSamples, VovkSchemaIdEnum, } from 'vovk';
|
|
6
6
|
import * as YAML from 'yaml';
|
|
7
7
|
import TOML from '@iarna/toml';
|
|
8
8
|
import prettify from '../utils/prettify.mjs';
|
|
9
9
|
import { ROOT_SEGMENT_FILE_NAME } from '../dev/writeOneSegmentSchemaFile.mjs';
|
|
10
10
|
import { compileJSONSchemaToTypeScriptType } from '../utils/compileJSONSchemaToTypeScriptType.mjs';
|
|
11
11
|
import getTemplateClientImports from './getTemplateClientImports.mjs';
|
|
12
|
+
import getMetaSchema from '../getProjectInfo/getMetaSchema.mjs';
|
|
12
13
|
export function normalizeOutTemplatePath(out, packageJson) {
|
|
13
14
|
return out.replace('[package_name]', packageJson.name?.replace(/-/g, '_') ?? 'my_package_name');
|
|
14
15
|
}
|
|
15
16
|
export default async function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName,
|
|
16
17
|
// imports,
|
|
17
|
-
templateContent, matterResult: { data, content }, openapi, package: packageJson, readme,
|
|
18
|
+
templateContent, matterResult: { data, content }, openapi, package: packageJson, readme, samples, reExports, isEnsuringClient, outCwdRelativeDir,
|
|
18
19
|
// templateDef,
|
|
19
|
-
locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, configKey, cliSchemaPath, }) {
|
|
20
|
+
locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, configKey, cliSchemaPath, projectConfig, }) {
|
|
20
21
|
const { config, apiRoot } = projectInfo;
|
|
21
22
|
const { templateFilePath, relativeDir } = clientTemplateFile;
|
|
22
23
|
const locatedSegmentsByName = _.keyBy(locatedSegments, 'segmentName');
|
|
@@ -48,19 +49,21 @@ locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage,
|
|
|
48
49
|
isVovkProject,
|
|
49
50
|
package: packageJson,
|
|
50
51
|
readme,
|
|
51
|
-
|
|
52
|
+
samples,
|
|
52
53
|
reExports,
|
|
53
54
|
openapi,
|
|
54
55
|
ROOT_SEGMENT_FILE_NAME,
|
|
55
56
|
apiRoot: origin ? `${origin}/${config.rootEntry}` : apiRoot,
|
|
56
57
|
imports: {},
|
|
57
58
|
schema: fullSchema,
|
|
59
|
+
config: projectConfig,
|
|
58
60
|
VovkSchemaIdEnum,
|
|
59
|
-
|
|
61
|
+
createCodeSamples,
|
|
60
62
|
compileJSONSchemaToTypeScriptType,
|
|
61
63
|
YAML,
|
|
62
64
|
TOML,
|
|
63
65
|
getFirstLineBanner,
|
|
66
|
+
publicMeta: getMetaSchema({ config: projectConfig, useEmitConfig: true }),
|
|
64
67
|
nodeNextResolutionExt: {
|
|
65
68
|
ts: isNodeNextResolution ? '.ts' : '',
|
|
66
69
|
js: isNodeNextResolution ? '.js' : '',
|
|
@@ -48,7 +48,7 @@ export default function getConfig({ configPath, cwd, logLevel, }: {
|
|
|
48
48
|
requires?: Record<string, string>;
|
|
49
49
|
prebundleOutDir?: string;
|
|
50
50
|
keepPrebundleDir?: boolean;
|
|
51
|
-
tsdownBuildOptions?: Parameters<typeof import("tsdown/
|
|
51
|
+
tsdownBuildOptions?: Parameters<typeof import("tsdown/index.mjs").build>[0];
|
|
52
52
|
generatorConfig?: import("vovk").VovkGeneratorConfigCommon;
|
|
53
53
|
} & ({
|
|
54
54
|
excludeSegments?: never;
|
package/dist/index.mjs
CHANGED
|
@@ -96,8 +96,8 @@ program
|
|
|
96
96
|
.option('--origin <url>', 'set the origin URL for the generated client')
|
|
97
97
|
.option('--watch <s>', 'watch for changes in schema or openapi spec and regenerate client; accepts a number in seconds to throttle the watcher or make an HTTP request to the OpenAPI spec URL')
|
|
98
98
|
.option('--openapi, --openapi-spec <openapi_path_or_urls...>', 'use OpenAPI schema for client generation')
|
|
99
|
-
.option('--openapi-get-module-name <names...>', 'module names corresponding to the index of --openapi option')
|
|
100
|
-
.option('--openapi-get-method-name <names...>', 'method names corresponding to the index of --openapi option')
|
|
99
|
+
.option('--openapi-module-name, --openapi-get-module-name <names...>', 'module names corresponding to the index of --openapi option')
|
|
100
|
+
.option('--openapi-method-name, --openapi-get-method-name <names...>', 'method names corresponding to the index of --openapi option')
|
|
101
101
|
.option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
|
|
102
102
|
.option('--openapi-mixin-name <names...>', 'mixin names corresponding to the index of --openapi option')
|
|
103
103
|
.option('--openapi-fallback <paths...>', 'save OpenAPI spec and use it as a fallback if URL is not available')
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @description Recursive object extending
|
|
3
|
+
* @author Viacheslav Lotsmanov <lotsmanov89@gmail.com>
|
|
4
|
+
* @license MIT
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2013-2018 Viacheslav Lotsmanov
|
|
9
|
+
*
|
|
10
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
11
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
12
|
+
* the Software without restriction, including without limitation the rights to
|
|
13
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
14
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
15
|
+
* subject to the following conditions:
|
|
16
|
+
*
|
|
17
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
* copies or substantial portions of the Software.
|
|
19
|
+
*
|
|
20
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
22
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
23
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
24
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
25
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
26
|
+
*/
|
|
27
|
+
type DeepPartial<T> = {
|
|
28
|
+
[P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
29
|
+
};
|
|
30
|
+
type SpecificValue = Buffer | Date | RegExp;
|
|
31
|
+
declare function isSpecificValue(val: any): val is SpecificValue;
|
|
32
|
+
declare function cloneSpecificValue(val: SpecificValue): SpecificValue;
|
|
33
|
+
/**
|
|
34
|
+
* Recursive cloning array.
|
|
35
|
+
*/
|
|
36
|
+
declare function deepCloneArray<T = any>(arr: T[]): T[];
|
|
37
|
+
declare function safeGetProperty<T extends object>(object: T, property: PropertyKey): any;
|
|
38
|
+
/**
|
|
39
|
+
* Extending object that entered in first argument.
|
|
40
|
+
*
|
|
41
|
+
* Returns extended object or false if have no target object or incorrect type.
|
|
42
|
+
*
|
|
43
|
+
* If you wish to clone source object (without modify it), just use empty new
|
|
44
|
+
* object as first argument, like this:
|
|
45
|
+
* deepExtend({}, yourObj_1, [yourObj_N]);
|
|
46
|
+
*/
|
|
47
|
+
declare function deepExtend<T extends object>(...args: [T, ...Partial<T>[]]): T;
|
|
48
|
+
declare function deepExtend<T extends object, U extends object>(target: T, source: U): T & U;
|
|
49
|
+
declare function deepExtend<T extends object, U extends object, V extends object>(target: T, source1: U, source2: V): T & U & V;
|
|
50
|
+
declare function deepExtend<T extends object, U extends object, V extends object, W extends object>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
|
|
51
|
+
declare function deepExtend<T extends object>(target: T, ...sources: any[]): T;
|
|
52
|
+
export default deepExtend;
|
|
53
|
+
export { deepExtend, deepCloneArray, isSpecificValue, cloneSpecificValue, safeGetProperty };
|
|
54
|
+
export type { DeepPartial, SpecificValue };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/*!
|
|
3
|
+
* @description Recursive object extending
|
|
4
|
+
* @author Viacheslav Lotsmanov <lotsmanov89@gmail.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* The MIT License (MIT)
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) 2013-2018 Viacheslav Lotsmanov
|
|
10
|
+
*
|
|
11
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
12
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
13
|
+
* the Software without restriction, including without limitation the rights to
|
|
14
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
15
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
16
|
+
* subject to the following conditions:
|
|
17
|
+
*
|
|
18
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
* copies or substantial portions of the Software.
|
|
20
|
+
*
|
|
21
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
23
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
24
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
25
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
26
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
27
|
+
*/
|
|
28
|
+
'use strict';
|
|
29
|
+
function isSpecificValue(val) {
|
|
30
|
+
return val instanceof Buffer || val instanceof Date || val instanceof RegExp;
|
|
31
|
+
}
|
|
32
|
+
function cloneSpecificValue(val) {
|
|
33
|
+
if (val instanceof Buffer) {
|
|
34
|
+
const x = Buffer.alloc ? Buffer.alloc(val.length) : Buffer.from(val);
|
|
35
|
+
val.copy(x);
|
|
36
|
+
return x;
|
|
37
|
+
}
|
|
38
|
+
else if (val instanceof Date) {
|
|
39
|
+
return new Date(val.getTime());
|
|
40
|
+
}
|
|
41
|
+
else if (val instanceof RegExp) {
|
|
42
|
+
return new RegExp(val);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
throw new Error('Unexpected situation');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Recursive cloning array.
|
|
50
|
+
*/
|
|
51
|
+
function deepCloneArray(arr) {
|
|
52
|
+
const clone = [];
|
|
53
|
+
arr.forEach((item, index) => {
|
|
54
|
+
if (typeof item === 'object' && item !== null) {
|
|
55
|
+
if (Array.isArray(item)) {
|
|
56
|
+
clone[index] = deepCloneArray(item);
|
|
57
|
+
}
|
|
58
|
+
else if (isSpecificValue(item)) {
|
|
59
|
+
clone[index] = cloneSpecificValue(item);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
clone[index] = deepExtend({}, item);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
clone[index] = item;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return clone;
|
|
70
|
+
}
|
|
71
|
+
function safeGetProperty(object, property) {
|
|
72
|
+
return property === '__proto__' ? undefined : object[property];
|
|
73
|
+
}
|
|
74
|
+
function deepExtend(...args) {
|
|
75
|
+
if (args.length < 1 || typeof args[0] !== 'object') {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (args.length < 2) {
|
|
79
|
+
return args[0];
|
|
80
|
+
}
|
|
81
|
+
const target = args[0];
|
|
82
|
+
// convert arguments to array and cut off target object
|
|
83
|
+
const sources = args.slice(1);
|
|
84
|
+
sources.forEach((obj) => {
|
|
85
|
+
// skip argument if isn't an object, is null, or is an array
|
|
86
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
Object.keys(obj).forEach((key) => {
|
|
90
|
+
const src = safeGetProperty(target, key); // source value
|
|
91
|
+
const val = safeGetProperty(obj, key); // new value
|
|
92
|
+
// recursion prevention
|
|
93
|
+
if (val === target) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
else if (typeof val !== 'object' || val === null) {
|
|
97
|
+
/**
|
|
98
|
+
* if new value isn't object then just overwrite by new value
|
|
99
|
+
* instead of extending.
|
|
100
|
+
*/
|
|
101
|
+
target[key] = val;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// just clone arrays (and recursive clone objects inside)
|
|
105
|
+
else if (Array.isArray(val)) {
|
|
106
|
+
target[key] = deepCloneArray(val);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// custom cloning and overwrite for specific objects
|
|
110
|
+
else if (isSpecificValue(val)) {
|
|
111
|
+
target[key] = cloneSpecificValue(val);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// overwrite by new value if source isn't object or array
|
|
115
|
+
else if (typeof src !== 'object' || src === null || Array.isArray(src)) {
|
|
116
|
+
target[key] = deepExtend({}, val);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// source value and new value is objects both, extending...
|
|
120
|
+
else {
|
|
121
|
+
target[key] = deepExtend(src, val);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
return target;
|
|
127
|
+
}
|
|
128
|
+
export default deepExtend;
|
|
129
|
+
export { deepExtend, deepCloneArray, isSpecificValue, cloneSpecificValue, safeGetProperty };
|
|
@@ -11,4 +11,4 @@ export declare function normalizeOpenAPIMixin({ mixinModule, log, cwd, }: {
|
|
|
11
11
|
mixinModule: NonNullable<NonNullable<NonNullable<NonNullable<VovkConfig['generatorConfig']>['segments']>[string]>['openAPIMixin']>;
|
|
12
12
|
log: ProjectInfo['log'];
|
|
13
13
|
cwd?: string;
|
|
14
|
-
}): Promise<NonNullable<NonNullable<NonNullable<VovkStrictConfig['generatorConfig']>['segments']>[string]>['openAPIMixin']
|
|
14
|
+
}): Promise<NonNullable<NonNullable<NonNullable<NonNullable<VovkStrictConfig['generatorConfig']>['segments']>[string]>['openAPIMixin']>>;
|
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.353",
|
|
4
4
|
"bin": {
|
|
5
5
|
"vovk": "./dist/index.mjs"
|
|
6
6
|
},
|
|
@@ -35,22 +35,22 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://vovk.dev",
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"vovk": "^3.0.0-draft.
|
|
38
|
+
"vovk": "^3.0.0-draft.415"
|
|
39
39
|
},
|
|
40
40
|
"optionalDependencies": {
|
|
41
|
-
"@rolldown/binding-linux-x64-gnu": "1.0.0-beta.
|
|
41
|
+
"@rolldown/binding-linux-x64-gnu": "1.0.0-beta.36"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@iarna/toml": "^2.2.5",
|
|
45
|
-
"@inquirer/prompts": "^7.
|
|
46
|
-
"@npmcli/package-json": "^
|
|
45
|
+
"@inquirer/prompts": "^7.8.4",
|
|
46
|
+
"@npmcli/package-json": "^7.0.0",
|
|
47
47
|
"@types/json-schema": "^7.0.15",
|
|
48
|
-
"chalk": "^5.
|
|
48
|
+
"chalk": "^5.6.2",
|
|
49
49
|
"chokidar": "^4.0.3",
|
|
50
50
|
"clone-deep": "^4.0.1",
|
|
51
51
|
"commander": "^13.1.0",
|
|
52
|
-
"concurrently": "^9.2.
|
|
53
|
-
"dotenv": "^17.2.
|
|
52
|
+
"concurrently": "^9.2.1",
|
|
53
|
+
"dotenv": "^17.2.2",
|
|
54
54
|
"ejs": "^3.1.10",
|
|
55
55
|
"get-tsconfig": "^4.10.1",
|
|
56
56
|
"glob": "^11.0.3",
|
|
@@ -63,12 +63,12 @@
|
|
|
63
63
|
"pluralize": "^8.0.0",
|
|
64
64
|
"prettier": "^3.6.2",
|
|
65
65
|
"tar-stream": "^3.1.7",
|
|
66
|
-
"ts-morph": "^
|
|
67
|
-
"tsdown": "^0.
|
|
66
|
+
"ts-morph": "^27.0.0",
|
|
67
|
+
"tsdown": "^0.15.0",
|
|
68
68
|
"type-fest": "^4.41.0",
|
|
69
|
-
"undici": "^7.
|
|
69
|
+
"undici": "^7.15.0",
|
|
70
70
|
"vovk-openapi": "^0.0.1-draft.112",
|
|
71
|
-
"yaml": "^2.8.
|
|
71
|
+
"yaml": "^2.8.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@types/concat-stream": "^2.0.3",
|
|
@@ -78,8 +78,9 @@
|
|
|
78
78
|
"@types/pluralize": "^0.0.33",
|
|
79
79
|
"@types/tar-stream": "^3.1.4",
|
|
80
80
|
"concat-stream": "^2.0.0",
|
|
81
|
-
"create-next-app": "^15.
|
|
81
|
+
"create-next-app": "^15.5.2",
|
|
82
|
+
"http-server": "^14.1.1",
|
|
82
83
|
"node-pty": "^1.0.0",
|
|
83
|
-
"zod": "^4.
|
|
84
|
+
"zod": "^4.1.5"
|
|
84
85
|
}
|
|
85
86
|
}
|