@penkov/swagger-code-gen 1.15.0 → 1.16.0
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 +15 -0
- package/dist/cli.mjs +4 -1
- package/dist/components-parse.js +45 -1
- package/dist/index.js +4 -3
- package/dist/parameter.js +15 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Usage:
|
|
|
11
11
|
```shell
|
|
12
12
|
generate-client --url <URI> output_filename.ts
|
|
13
13
|
generate-client --url <URI> --includeTags tag1 tag2 -- output_filename.ts
|
|
14
|
+
generate-client --url <URI> --includeTags tag1 tag2 --onlyUsedSchemas -- output_filename.ts
|
|
14
15
|
```
|
|
15
16
|
|
|
16
17
|
Cli parameters:
|
|
@@ -21,6 +22,8 @@ Cli parameters:
|
|
|
21
22
|
* `--excludeTags <tags...>` - Space-separated list of tags of paths to be excluded.
|
|
22
23
|
Path is excluded if exclusion list is non-empty and path contains any of the tags from exclusion list.
|
|
23
24
|
If the tag is both in inclusion and exclusion lists, it gets excluded.
|
|
25
|
+
* `--onlyUsedSchemas` - generate only schemas that are reachable from filtered methods
|
|
26
|
+
(useful with `--includeTags`/`--excludeTags`). By default all schemas are generated.
|
|
24
27
|
* `--referencedObjectsNullableByDefault` - then specified, the generated code will assume that
|
|
25
28
|
any object's field, that references another object, can be null, unless it is explicitly specified to be not nullable
|
|
26
29
|
(which is default in .net world: asp generates wrong spec)
|
|
@@ -28,6 +31,18 @@ Cli parameters:
|
|
|
28
31
|
style for all objects and create a service with methods for each endpoint.
|
|
29
32
|
* `--targetNode` - adds imports for `node-fetch` package in generated code.
|
|
30
33
|
|
|
34
|
+
## Tag filtering and schema pruning
|
|
35
|
+
|
|
36
|
+
By default, tag filters affect only methods and all schemas are still generated:
|
|
37
|
+
```shell
|
|
38
|
+
generate-client --url <URI> --includeTags public -- output_filename.ts
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To generate only schemas that are reachable from filtered methods, add `--onlyUsedSchemas`:
|
|
42
|
+
```shell
|
|
43
|
+
generate-client --url <URI> --includeTags public --onlyUsedSchemas -- output_filename.ts
|
|
44
|
+
```
|
|
45
|
+
|
|
31
46
|
|
|
32
47
|
|
|
33
48
|
# Example of generated code:
|
package/dist/cli.mjs
CHANGED
|
@@ -11,6 +11,7 @@ program
|
|
|
11
11
|
.option('--referencedObjectsNullableByDefault', 'Assume that referenced objects can be null (say hello to .net assholes)', false)
|
|
12
12
|
.option('--includeTags <tags...>', 'Space-separated list of tags of paths to be included. Path is included if it contains any of specified tag')
|
|
13
13
|
.option('--excludeTags <tags...>', 'Space-separated list of tags of paths to be excluded. Path is excluded if it contains any of specified tag')
|
|
14
|
+
.option('--onlyUsedSchemas', 'Generate only schemas reachable from filtered methods', false)
|
|
14
15
|
.option('--enableScats', 'Generate scats', false)
|
|
15
16
|
.option('--targetNode', 'Add imports for node-fetch into generated code', false)
|
|
16
17
|
.option('--user <username>', 'If swagger requires authorisation')
|
|
@@ -28,12 +29,14 @@ const targetNode = program.opts().targetNode;
|
|
|
28
29
|
const outputFile = program.args[0];
|
|
29
30
|
const includeTags = HashSet.from(program.opts().includeTags || []);
|
|
30
31
|
const excludeTags = HashSet.from(program.opts().excludeTags || []);
|
|
32
|
+
const onlyUsedSchemas = program.opts().onlyUsedSchemas;
|
|
31
33
|
main(url, enableScats, targetNode, outputFile, ignoreSSLErrors, option(user).flatMap(u => option(password).map(p => ({
|
|
32
34
|
user: u,
|
|
33
35
|
password: p
|
|
34
36
|
}))), {
|
|
35
37
|
referencedObjectsNullableByDefault: referencedObjectsNullableByDefault,
|
|
36
38
|
includeTags: includeTags,
|
|
37
|
-
excludeTags: excludeTags
|
|
39
|
+
excludeTags: excludeTags,
|
|
40
|
+
onlyUsedSchemas: onlyUsedSchemas
|
|
38
41
|
}).then(() => {
|
|
39
42
|
});
|
package/dist/components-parse.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Collection, mutable, Nil, option } from 'scats';
|
|
2
2
|
import { SchemaFactory, SchemaObject } from './schemas.js';
|
|
3
|
-
import { SCHEMA_PREFIX } from './property.js';
|
|
3
|
+
import { Property, SCHEMA_PREFIX } from './property.js';
|
|
4
4
|
import { Method, supportedBodyMimeTypes } from './method.js';
|
|
5
5
|
export function resolveSchemasTypes(json) {
|
|
6
6
|
const jsonSchemas = json.components.schemas;
|
|
@@ -88,6 +88,50 @@ export function resolvePaths(json, schemasTypes, options, pool) {
|
|
|
88
88
|
return included && !excluded;
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
+
function collectSchemaRefsFromType(type, schemas, add) {
|
|
92
|
+
Collection.from(type.split(/[|&]/))
|
|
93
|
+
.map(t => t.trim())
|
|
94
|
+
.filter(t => t.length > 0)
|
|
95
|
+
.filter(t => schemas.containsKey(t))
|
|
96
|
+
.foreach(t => add(t));
|
|
97
|
+
}
|
|
98
|
+
export function filterUsedSchemas(paths, schemas) {
|
|
99
|
+
const used = new Set();
|
|
100
|
+
const pending = [];
|
|
101
|
+
const add = (name) => {
|
|
102
|
+
if (!used.has(name) && schemas.containsKey(name)) {
|
|
103
|
+
used.add(name);
|
|
104
|
+
pending.push(name);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const collectFromProperty = (p) => {
|
|
108
|
+
collectSchemaRefsFromType(p.type, schemas, add);
|
|
109
|
+
collectSchemaRefsFromType(p.items, schemas, add);
|
|
110
|
+
};
|
|
111
|
+
paths.foreach(m => {
|
|
112
|
+
m.parameters.foreach(p => p.referencedSchemas.foreach(t => add(t)));
|
|
113
|
+
collectFromProperty(m.response.asProperty);
|
|
114
|
+
m.body.foreach(b => {
|
|
115
|
+
if (b.body instanceof Property) {
|
|
116
|
+
collectFromProperty(b.body);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
while (pending.length > 0) {
|
|
121
|
+
const schemaName = pending.shift();
|
|
122
|
+
const schema = schemas.get(schemaName).getOrElseThrow(() => new Error(`No schema for ${schemaName}`));
|
|
123
|
+
if (schema instanceof SchemaObject) {
|
|
124
|
+
schema.parents.keySet.foreach(parentName => add(parentName));
|
|
125
|
+
schema.properties.foreach(p => collectFromProperty(p));
|
|
126
|
+
}
|
|
127
|
+
else if (schema instanceof Property) {
|
|
128
|
+
collectFromProperty(schema);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return schemas.keySet
|
|
132
|
+
.filter(name => used.has(name))
|
|
133
|
+
.toMap(name => [name, schemas.get(name).getOrElseThrow(() => new Error(`No schema for ${name}`))]);
|
|
134
|
+
}
|
|
91
135
|
export function generateInPlace(paths, schemasTypes, options, pool) {
|
|
92
136
|
const collectInplaceFromProperty = (p) => {
|
|
93
137
|
if (p.inPlace.isDefined) {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import log4js from 'log4js';
|
|
2
2
|
import fetch from 'node-fetch';
|
|
3
3
|
import { Renderer } from './renderer.js';
|
|
4
|
-
import { generateInPlace, resolvePaths, resolveSchemas, resolveSchemasTypes } from './components-parse.js';
|
|
4
|
+
import { filterUsedSchemas, generateInPlace, resolvePaths, resolveSchemas, resolveSchemasTypes } from './components-parse.js';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { dirname } from 'path';
|
|
7
7
|
import https from 'https';
|
|
@@ -26,8 +26,9 @@ export async function main(url, enableScats, targetNode, outputFile, ignoreSSLEr
|
|
|
26
26
|
.then(res => res.json())
|
|
27
27
|
.then(async (json) => {
|
|
28
28
|
const schemasTypes = resolveSchemasTypes(json);
|
|
29
|
-
const
|
|
30
|
-
const paths = resolvePaths(json, schemasTypes, options,
|
|
29
|
+
const allSchemas = resolveSchemas(json, schemasTypes, options);
|
|
30
|
+
const paths = resolvePaths(json, schemasTypes, options, allSchemas);
|
|
31
|
+
const schemas = options.onlyUsedSchemas ? filterUsedSchemas(paths, allSchemas) : allSchemas;
|
|
31
32
|
const inplace = generateInPlace(paths, schemasTypes, options, schemas);
|
|
32
33
|
logger.debug(`Downloaded swagger: ${schemas.size} schemas, ${paths.size} paths`);
|
|
33
34
|
await renderer.renderToFile(schemas.appendedAll(inplace.toMap(s => [s.name, s])).values, paths, enableScats, targetNode, outputFile);
|
package/dist/parameter.js
CHANGED
|
@@ -3,12 +3,13 @@ import { Collection, identity, none, option } from 'scats';
|
|
|
3
3
|
import { Method } from './method.js';
|
|
4
4
|
import { Property } from './property.js';
|
|
5
5
|
export class Parameter {
|
|
6
|
-
constructor(name, rawName, uniqueName, inValue, jsType, required, isArray, defaultValue, description) {
|
|
6
|
+
constructor(name, rawName, uniqueName, inValue, jsType, referencedSchemas, required, isArray, defaultValue, description) {
|
|
7
7
|
this.name = name;
|
|
8
8
|
this.rawName = rawName;
|
|
9
9
|
this.uniqueName = uniqueName;
|
|
10
10
|
this.inValue = inValue;
|
|
11
11
|
this.jsType = jsType;
|
|
12
|
+
this.referencedSchemas = referencedSchemas;
|
|
12
13
|
this.required = required;
|
|
13
14
|
this.isArray = isArray;
|
|
14
15
|
this.defaultValue = defaultValue;
|
|
@@ -21,6 +22,7 @@ export class Parameter {
|
|
|
21
22
|
const inValue = def.in;
|
|
22
23
|
const desc = option(def.description);
|
|
23
24
|
let defaultValue = none;
|
|
25
|
+
const references = new Set();
|
|
24
26
|
const schema = def.schema ?
|
|
25
27
|
SchemaFactory.build(def.name, def.schema, schemas, options) :
|
|
26
28
|
Property.fromDefinition('', name, {
|
|
@@ -35,10 +37,14 @@ export class Parameter {
|
|
|
35
37
|
if (schema.type === 'integer') {
|
|
36
38
|
jsType = 'number';
|
|
37
39
|
}
|
|
40
|
+
if (schemas.containsKey(schema.name)) {
|
|
41
|
+
references.add(schema.name);
|
|
42
|
+
}
|
|
38
43
|
}
|
|
39
44
|
else if (schema instanceof SchemaEnum) {
|
|
40
45
|
if (schemas.containsKey(schema.name)) {
|
|
41
46
|
jsType = schema.name;
|
|
47
|
+
references.add(schema.name);
|
|
42
48
|
}
|
|
43
49
|
else if (schema.type === 'string') {
|
|
44
50
|
jsType = `${schema.values.map(x => `'${x}'`).mkString(' | ')}`;
|
|
@@ -60,13 +66,19 @@ export class Parameter {
|
|
|
60
66
|
}
|
|
61
67
|
else if (schema instanceof Property) {
|
|
62
68
|
jsType = schema.jsType;
|
|
69
|
+
if (schemas.containsKey(schema.type)) {
|
|
70
|
+
references.add(schema.type);
|
|
71
|
+
}
|
|
72
|
+
if (schema.isArray && schemas.containsKey(schema.items)) {
|
|
73
|
+
references.add(schema.items);
|
|
74
|
+
}
|
|
63
75
|
}
|
|
64
76
|
else {
|
|
65
77
|
throw new Error('Unknown schema type');
|
|
66
78
|
}
|
|
67
79
|
const required = option(def.required).exists(identity) || defaultValue.nonEmpty;
|
|
68
80
|
const isArray = def?.schema?.type === 'array';
|
|
69
|
-
return new Parameter(name, rawName, name, inValue, jsType, required, isArray, defaultValue, desc);
|
|
81
|
+
return new Parameter(name, rawName, name, inValue, jsType, Collection.from(Array.from(references)), required, isArray, defaultValue, desc);
|
|
70
82
|
}
|
|
71
83
|
static toJSName(path) {
|
|
72
84
|
const tokens = Collection.from(path.split(/\W/)).filter(t => t.length > 0);
|
|
@@ -75,6 +87,6 @@ export class Parameter {
|
|
|
75
87
|
}).mkString();
|
|
76
88
|
}
|
|
77
89
|
copy(p) {
|
|
78
|
-
return new Parameter(option(p.name).getOrElseValue(this.name), option(p.rawName).getOrElseValue(this.rawName), option(p.uniqueName).getOrElseValue(this.uniqueName), option(p.in).getOrElseValue(this.in), option(p.jsType).getOrElseValue(this.jsType), option(p.required).getOrElseValue(this.required), option(p.isArray).getOrElseValue(this.isArray), option(p.defaultValue).getOrElseValue(this.defaultValue), option(p.description).getOrElseValue(this.description));
|
|
90
|
+
return new Parameter(option(p.name).getOrElseValue(this.name), option(p.rawName).getOrElseValue(this.rawName), option(p.uniqueName).getOrElseValue(this.uniqueName), option(p.in).getOrElseValue(this.in), option(p.jsType).getOrElseValue(this.jsType), option(p.referencedSchemas).getOrElseValue(this.referencedSchemas), option(p.required).getOrElseValue(this.required), option(p.isArray).getOrElseValue(this.isArray), option(p.defaultValue).getOrElseValue(this.defaultValue), option(p.description).getOrElseValue(this.description));
|
|
79
91
|
}
|
|
80
92
|
}
|