dtsgenerator 3.13.0 → 3.15.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/.eslintrc.json +1 -5
- package/.prettierignore +1 -0
- package/README.md +20 -0
- package/SupportedFeatures.md +2 -0
- package/dist/core/astBuilder.d.ts +1 -0
- package/dist/core/astBuilder.js +9 -4
- package/dist/core/dtsGenerator.d.ts +4 -2
- package/dist/core/dtsGenerator.js +72 -66
- package/dist/core/jsonSchema.js +3 -3
- package/dist/core/referenceResolver.d.ts +1 -1
- package/dist/core/type.d.ts +1 -1
- package/dist/core/typeTree.d.ts +6 -0
- package/dist/core/typeTree.js +34 -0
- package/dist/core/utils.d.ts +1 -1
- package/dist/core/utils.js +6 -7
- package/package.json +19 -19
- package/src/commandOptions.ts +1 -1
- package/src/core/astBuilder.ts +12 -4
- package/src/core/dtsGenerator.ts +123 -101
- package/src/core/jsonSchema.ts +3 -3
- package/src/core/referenceResolver.ts +1 -1
- package/src/core/type.ts +1 -1
- package/src/core/typeTree.ts +39 -0
- package/src/core/utils.ts +7 -9
package/.eslintrc.json
CHANGED
|
@@ -4,17 +4,13 @@
|
|
|
4
4
|
"@dtsgenerator"
|
|
5
5
|
],
|
|
6
6
|
"rules": {
|
|
7
|
-
"@typescript-eslint/no-explicit-any": 0
|
|
8
|
-
"import/order": ["error", { "alphabetize": { "order": "asc" } }]
|
|
7
|
+
"@typescript-eslint/no-explicit-any": 0
|
|
9
8
|
},
|
|
10
9
|
"overrides": [
|
|
11
10
|
{
|
|
12
11
|
"files": [
|
|
13
12
|
"**/*_test.ts"
|
|
14
13
|
],
|
|
15
|
-
"env": {
|
|
16
|
-
"mocha": true
|
|
17
|
-
},
|
|
18
14
|
"rules": {
|
|
19
15
|
"@typescript-eslint/ban-ts-comment": 0,
|
|
20
16
|
"@typescript-eslint/no-empty-interface": 0,
|
package/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/test/snapshots
|
package/README.md
CHANGED
|
@@ -143,6 +143,26 @@ Output debug message by [debug](https://www.npmjs.com/package/debug) library.
|
|
|
143
143
|
|
|
144
144
|
## ChangeLog
|
|
145
145
|
|
|
146
|
+
### [v3.15.0](https://github.com/horiuchi/dtsgenerator/releases/tag/v3.15.0) (2022-02-06)
|
|
147
|
+
|
|
148
|
+
- features:
|
|
149
|
+
- Support mobile wallet media types(`application/jwt` and `application/vnd.apple.pkpass`) for #530. Thank you @eostrom :+1:
|
|
150
|
+
|
|
151
|
+
### [v3.14.0](https://github.com/horiuchi/dtsgenerator/releases/tag/v3.14.0) (2022-01-27)
|
|
152
|
+
|
|
153
|
+
- features:
|
|
154
|
+
- Support the nested `allOf` and `oneOf` schema for #513. Thank you for your report @Cry0nicS :+1:
|
|
155
|
+
|
|
156
|
+
### [v3.13.2](https://github.com/horiuchi/dtsgenerator/releases/tag/v3.13.2) (2021-10-08)
|
|
157
|
+
|
|
158
|
+
- features:
|
|
159
|
+
- Fix the type generation malformed objects with number-like keys for #523. Thank you for your report @DamianOsipiuk :+1:
|
|
160
|
+
|
|
161
|
+
### [v3.13.1](https://github.com/horiuchi/dtsgenerator/releases/tag/v3.13.1) (2021-09-29)
|
|
162
|
+
|
|
163
|
+
- features:
|
|
164
|
+
- Change the plug-in interface, the PluginContext::inputSchemas to IterableIterator for #521. Thank you @djrollins :+1:
|
|
165
|
+
|
|
146
166
|
### [v3.13.0](https://github.com/horiuchi/dtsgenerator/releases/tag/v3.13.0) (2021-08-31)
|
|
147
167
|
|
|
148
168
|
- features:
|
package/SupportedFeatures.md
CHANGED
|
@@ -21,6 +21,7 @@ export declare function buildIndexSignatureNode(name: string, indexType: ts.Type
|
|
|
21
21
|
export declare function buildTypeLiteralNode(elements: ts.TypeElement[]): ts.TypeNode;
|
|
22
22
|
export declare function buildFreeFormObjectTypeLiteralNode(): ts.TypeNode;
|
|
23
23
|
export declare function buildUnionTypeNode<T>(types: T[], builder: (t: T, index: number) => ts.TypeNode, terminate: boolean): ts.TypeNode;
|
|
24
|
+
export declare function buildIntersectionTypeNode(types: readonly ts.TypeNode[], terminate: boolean): ts.TypeNode;
|
|
24
25
|
export declare function buildTupleTypeNode(types: ts.TypeNode | ts.TypeNode[], minItems?: number, maxItems?: number, additionalItems?: ts.TypeNode | false): ts.TypeNode;
|
|
25
26
|
export declare function buildTypeReferenceNode(schema: NormalizedSchema, currentSchema: Schema): ts.TypeReferenceNode;
|
|
26
27
|
export declare function addComment<T extends ts.Node>(node: T, schema: NormalizedSchema, terminate: boolean): T;
|
package/dist/core/astBuilder.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.addOptionalInformation = exports.addComment = exports.buildTypeReferenceNode = exports.buildTupleTypeNode = exports.buildUnionTypeNode = exports.buildFreeFormObjectTypeLiteralNode = exports.buildTypeLiteralNode = exports.buildIndexSignatureNode = exports.buildPropertySignature = exports.buildTypeAliasNode = exports.buildInterfaceNode = exports.buildNamespaceNode = exports.buildBooleanLiteralTypeNode = exports.buildNumericLiteralTypeNode = exports.buildStringLiteralTypeNode = exports.buildNullKeyword = exports.buildSimpleArrayNode = exports.buildStringKeyword = exports.buildVoidKeyword = exports.buildUnknownKeyword = exports.buildNeverKeyword = exports.buildAnyKeyword = exports.buildKeyword = void 0;
|
|
3
|
+
exports.addOptionalInformation = exports.addComment = exports.buildTypeReferenceNode = exports.buildTupleTypeNode = exports.buildIntersectionTypeNode = exports.buildUnionTypeNode = exports.buildFreeFormObjectTypeLiteralNode = exports.buildTypeLiteralNode = exports.buildIndexSignatureNode = exports.buildPropertySignature = exports.buildTypeAliasNode = exports.buildInterfaceNode = exports.buildNamespaceNode = exports.buildBooleanLiteralTypeNode = exports.buildNumericLiteralTypeNode = exports.buildStringLiteralTypeNode = exports.buildNullKeyword = exports.buildSimpleArrayNode = exports.buildStringKeyword = exports.buildVoidKeyword = exports.buildUnknownKeyword = exports.buildNeverKeyword = exports.buildAnyKeyword = exports.buildKeyword = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const ts = (0, tslib_1.__importStar)(require("typescript"));
|
|
6
6
|
const config_1 = (0, tslib_1.__importDefault)(require("./config"));
|
|
@@ -9,9 +9,6 @@ function buildTypeNameIdentifier(name) {
|
|
|
9
9
|
return ts.factory.createIdentifier((0, validateIdentifier_1.toValidIdentifier)(name, config_1.default.target));
|
|
10
10
|
}
|
|
11
11
|
function buildPropertyNameIdentifier(name) {
|
|
12
|
-
if (/^\d/.test(name)) {
|
|
13
|
-
name = '$' + name;
|
|
14
|
-
}
|
|
15
12
|
if ((0, validateIdentifier_1.checkInvalidCharacter)(name, config_1.default.target)) {
|
|
16
13
|
return ts.factory.createIdentifier(name);
|
|
17
14
|
}
|
|
@@ -125,6 +122,14 @@ function buildUnionTypeNode(types, builder, terminate) {
|
|
|
125
122
|
return ts.factory.createParenthesizedType(node);
|
|
126
123
|
}
|
|
127
124
|
exports.buildUnionTypeNode = buildUnionTypeNode;
|
|
125
|
+
function buildIntersectionTypeNode(types, terminate) {
|
|
126
|
+
const node = ts.factory.createIntersectionTypeNode(types);
|
|
127
|
+
if (terminate) {
|
|
128
|
+
return node;
|
|
129
|
+
}
|
|
130
|
+
return ts.factory.createParenthesizedType(node);
|
|
131
|
+
}
|
|
132
|
+
exports.buildIntersectionTypeNode = buildIntersectionTypeNode;
|
|
128
133
|
function buildTupleTypeNode(types, minItems, maxItems, additionalItems) {
|
|
129
134
|
function typesIsArray(types) {
|
|
130
135
|
return Array.isArray(types);
|
|
@@ -5,12 +5,12 @@ export default class DtsGenerator {
|
|
|
5
5
|
private contents;
|
|
6
6
|
constructor(contents: Schema[]);
|
|
7
7
|
generate(): Promise<string>;
|
|
8
|
-
private buildSchemaMergedMap;
|
|
9
8
|
private getPlugins;
|
|
10
9
|
private getPreProcess;
|
|
11
10
|
private getPostProcess;
|
|
12
11
|
private walk;
|
|
13
12
|
private walkSchema;
|
|
13
|
+
private parseSchema;
|
|
14
14
|
private normalizeContent;
|
|
15
15
|
private normalizeSchemaContent;
|
|
16
16
|
private generateDeclareType;
|
|
@@ -18,8 +18,10 @@ export default class DtsGenerator {
|
|
|
18
18
|
private generateTypeCollection;
|
|
19
19
|
private generateProperties;
|
|
20
20
|
private generateTypeProperty;
|
|
21
|
+
private generateLiteralTypeProperty;
|
|
22
|
+
private checkExistOtherType;
|
|
21
23
|
private generateLiteralTypeNode;
|
|
22
|
-
private
|
|
24
|
+
private generateUnionType;
|
|
23
25
|
private generateArrayTypeProperty;
|
|
24
26
|
private generateType;
|
|
25
27
|
private generateTypeName;
|
|
@@ -9,9 +9,9 @@ const config_1 = (0, tslib_1.__importDefault)(require("./config"));
|
|
|
9
9
|
const jsonSchema_1 = require("./jsonSchema");
|
|
10
10
|
const referenceResolver_1 = (0, tslib_1.__importDefault)(require("./referenceResolver"));
|
|
11
11
|
const type_1 = require("./type");
|
|
12
|
+
const typeTree_1 = require("./typeTree");
|
|
12
13
|
const utils = (0, tslib_1.__importStar)(require("./utils"));
|
|
13
14
|
const debug = (0, debug_1.default)('dtsgen');
|
|
14
|
-
const typeMarker = Symbol();
|
|
15
15
|
class DtsGenerator {
|
|
16
16
|
constructor(contents) {
|
|
17
17
|
this.resolver = new referenceResolver_1.default();
|
|
@@ -26,8 +26,8 @@ class DtsGenerator {
|
|
|
26
26
|
debug('generate type definition files.');
|
|
27
27
|
this.contents.forEach((schema) => this.resolver.registerSchema(schema));
|
|
28
28
|
await this.resolver.resolve();
|
|
29
|
-
const
|
|
30
|
-
const root = this.walk(
|
|
29
|
+
const tree = (0, typeTree_1.buildTypeTree)(this.resolver.getAllRegisteredSchema());
|
|
30
|
+
const root = this.walk(tree);
|
|
31
31
|
const file = ts.createSourceFile('_.d.ts', '', config_1.default.target, false, ts.ScriptKind.TS);
|
|
32
32
|
Object.assign(file, {
|
|
33
33
|
statements: ts.factory.createNodeArray(root),
|
|
@@ -44,28 +44,6 @@ class DtsGenerator {
|
|
|
44
44
|
result.dispose();
|
|
45
45
|
return transformedContent;
|
|
46
46
|
}
|
|
47
|
-
buildSchemaMergedMap(schemas) {
|
|
48
|
-
const map = {};
|
|
49
|
-
const paths = [];
|
|
50
|
-
for (const type of schemas) {
|
|
51
|
-
const path = type.id.toNames();
|
|
52
|
-
paths.push({ path, type });
|
|
53
|
-
}
|
|
54
|
-
for (const item of paths) {
|
|
55
|
-
const path = item.path;
|
|
56
|
-
const parent = (0, jsonPointer_1.get)(map, path, true);
|
|
57
|
-
if (parent == null) {
|
|
58
|
-
(0, jsonPointer_1.set)(map, path, { [typeMarker]: item.type });
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
Object.assign(parent, { [typeMarker]: item.type });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (Object.keys(map).length === 0) {
|
|
65
|
-
throw new Error('There is no schema in the input contents.');
|
|
66
|
-
}
|
|
67
|
-
return map;
|
|
68
|
-
}
|
|
69
47
|
async getPlugins() {
|
|
70
48
|
const pre = [];
|
|
71
49
|
const post = [];
|
|
@@ -117,18 +95,20 @@ class DtsGenerator {
|
|
|
117
95
|
}
|
|
118
96
|
return result;
|
|
119
97
|
}
|
|
120
|
-
walk(
|
|
98
|
+
walk(tree, root = true) {
|
|
121
99
|
const result = [];
|
|
122
|
-
const keys =
|
|
100
|
+
const keys = [...tree.children.keys()].sort();
|
|
123
101
|
for (const key of keys) {
|
|
124
|
-
const value =
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
102
|
+
const value = tree.children.get(key);
|
|
103
|
+
if (value === undefined) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (value.schema !== undefined) {
|
|
107
|
+
const schema = value.schema;
|
|
128
108
|
debug(` walk doProcess: key=${key} schemaId=${schema.id.getAbsoluteId()}`);
|
|
129
109
|
result.push(this.walkSchema(schema, root));
|
|
130
110
|
}
|
|
131
|
-
if (
|
|
111
|
+
if (value.children.size > 0) {
|
|
132
112
|
result.push(ast.buildNamespaceNode(key, this.walk(value, false), root));
|
|
133
113
|
}
|
|
134
114
|
}
|
|
@@ -137,19 +117,19 @@ class DtsGenerator {
|
|
|
137
117
|
walkSchema(schema, root) {
|
|
138
118
|
const normalized = this.normalizeContent(schema);
|
|
139
119
|
this.currentSchema = normalized;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
120
|
+
return ast.addOptionalInformation(ast.addComment(this.parseSchema(normalized, root), normalized, true), normalized, true);
|
|
121
|
+
}
|
|
122
|
+
parseSchema(schema, root = false) {
|
|
123
|
+
const type = schema.content.type;
|
|
124
|
+
switch (type) {
|
|
125
|
+
case 'any':
|
|
126
|
+
return this.generateAnyTypeModel(schema, root);
|
|
127
|
+
case 'array':
|
|
128
|
+
return this.generateTypeCollection(schema, root);
|
|
129
|
+
case 'object':
|
|
130
|
+
default:
|
|
131
|
+
return this.generateDeclareType(schema, root);
|
|
132
|
+
}
|
|
153
133
|
}
|
|
154
134
|
normalizeContent(schema, pointer) {
|
|
155
135
|
if (pointer != null) {
|
|
@@ -253,13 +233,9 @@ class DtsGenerator {
|
|
|
253
233
|
}
|
|
254
234
|
}
|
|
255
235
|
if (content.patternProperties) {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
schemasTypes.push(this.generateTypeProperty(schema));
|
|
260
|
-
}
|
|
261
|
-
const node = ast.buildPropertySignature({ content: { readOnly: false } }, 'pattern', ts.createUnionTypeNode(schemasTypes), baseSchema.content.required, true);
|
|
262
|
-
result.push(ts.addSyntheticTrailingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, ` Patterns: ${Object.keys(content.patternProperties).join(' | ')} `));
|
|
236
|
+
const properties = Object.keys(content.patternProperties);
|
|
237
|
+
const node = ast.buildPropertySignature({ content: { readOnly: false } }, 'pattern', ast.buildUnionTypeNode(properties, (propertyName) => this.generateTypeProperty(this.normalizeContent(baseSchema, '/patternProperties/' + (0, jsonPointer_1.tilde)(propertyName))), true), baseSchema.content.required, true);
|
|
238
|
+
result.push(ts.addSyntheticTrailingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, ` Patterns: ${properties.join(' | ')} `));
|
|
263
239
|
}
|
|
264
240
|
return result;
|
|
265
241
|
}
|
|
@@ -271,19 +247,23 @@ class DtsGenerator {
|
|
|
271
247
|
throw new Error('target referenced id is nothing: ' + content.$ref);
|
|
272
248
|
}
|
|
273
249
|
const refSchema = this.normalizeContent(ref);
|
|
274
|
-
const node = ast.buildTypeReferenceNode(refSchema, this.currentSchema);
|
|
275
|
-
return
|
|
250
|
+
const node = ast.addOptionalInformation(ast.addComment(ast.buildTypeReferenceNode(refSchema, this.currentSchema), refSchema, false), refSchema, false);
|
|
251
|
+
return node;
|
|
276
252
|
}
|
|
277
253
|
if (content.anyOf) {
|
|
278
254
|
const mergeContent = Object.assign({}, content);
|
|
279
255
|
delete mergeContent.anyOf;
|
|
280
|
-
return this.
|
|
256
|
+
return this.generateUnionType(schema, content.anyOf, mergeContent, '/anyOf/', terminate);
|
|
281
257
|
}
|
|
282
258
|
if (content.oneOf) {
|
|
283
259
|
const mergeContent = Object.assign({}, content);
|
|
284
260
|
delete mergeContent.oneOf;
|
|
285
|
-
return this.
|
|
261
|
+
return this.generateUnionType(schema, content.oneOf, mergeContent, '/oneOf/', terminate);
|
|
286
262
|
}
|
|
263
|
+
return this.generateLiteralTypeProperty(schema, terminate);
|
|
264
|
+
}
|
|
265
|
+
generateLiteralTypeProperty(schema, terminate = true) {
|
|
266
|
+
const content = schema.content;
|
|
287
267
|
if (content.enum) {
|
|
288
268
|
return ast.buildUnionTypeNode(content.enum, (value) => {
|
|
289
269
|
return this.generateLiteralTypeNode(content, value);
|
|
@@ -299,17 +279,32 @@ class DtsGenerator {
|
|
|
299
279
|
return this.generateType(schema, terminate);
|
|
300
280
|
}
|
|
301
281
|
}
|
|
282
|
+
checkExistOtherType(content, base) {
|
|
283
|
+
const schema = Object.assign({}, base, { content });
|
|
284
|
+
const result = this.generateLiteralTypeProperty(schema, false);
|
|
285
|
+
if (result.kind === ts.SyntaxKind.AnyKeyword) {
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
else if (result.kind === ts.SyntaxKind.TypeLiteral) {
|
|
289
|
+
const node = result;
|
|
290
|
+
if (node.members.length === 1 &&
|
|
291
|
+
node.members[0].kind === ts.SyntaxKind.IndexSignature) {
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
302
297
|
generateLiteralTypeNode(content, value) {
|
|
303
298
|
switch (content.type) {
|
|
304
299
|
case 'integer':
|
|
305
300
|
case 'number':
|
|
306
301
|
return ast.buildNumericLiteralTypeNode(String(value));
|
|
307
302
|
case 'boolean':
|
|
308
|
-
return ast.buildBooleanLiteralTypeNode(value);
|
|
303
|
+
return ast.buildBooleanLiteralTypeNode(Boolean(value));
|
|
309
304
|
case 'null':
|
|
310
305
|
return ast.buildNullKeyword();
|
|
311
306
|
case 'string':
|
|
312
|
-
return ast.buildStringLiteralTypeNode(value);
|
|
307
|
+
return ast.buildStringLiteralTypeNode(String(value));
|
|
313
308
|
}
|
|
314
309
|
if (value === null) {
|
|
315
310
|
return ast.buildNullKeyword();
|
|
@@ -324,17 +319,28 @@ class DtsGenerator {
|
|
|
324
319
|
}
|
|
325
320
|
return ast.buildStringLiteralTypeNode(String(value));
|
|
326
321
|
}
|
|
327
|
-
|
|
328
|
-
|
|
322
|
+
generateUnionType(baseSchema, contents, mergeContent, path, terminate) {
|
|
323
|
+
const merged = [];
|
|
324
|
+
const children = contents.map((_, index) => {
|
|
329
325
|
const schema = this.normalizeContent(baseSchema, path + index.toString());
|
|
330
|
-
utils.mergeSchema(schema.content, mergeContent);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
326
|
+
merged.push(utils.mergeSchema(schema.content, mergeContent));
|
|
327
|
+
return schema;
|
|
328
|
+
});
|
|
329
|
+
const allRef = merged.every((b) => !b);
|
|
330
|
+
const baseType = this.checkExistOtherType(mergeContent, baseSchema);
|
|
331
|
+
const result = ast.addOptionalInformation(ast.addComment(ast.buildUnionTypeNode(children, (schema, index) => {
|
|
332
|
+
const node = schema.id.isEmpty()
|
|
333
|
+
? ast.addOptionalInformation(this.generateTypeProperty(schema, false), schema, false)
|
|
334
|
+
: ast.addOptionalInformation(ast.buildTypeReferenceNode(schema, this.currentSchema), schema, false);
|
|
335
|
+
if (baseType != null && !allRef && !merged[index]) {
|
|
336
|
+
return ast.buildIntersectionTypeNode([baseType, node], false);
|
|
336
337
|
}
|
|
338
|
+
return node;
|
|
337
339
|
}, terminate), baseSchema, false), baseSchema, terminate);
|
|
340
|
+
if (baseType != null && allRef) {
|
|
341
|
+
return ast.buildIntersectionTypeNode([baseType, result], terminate);
|
|
342
|
+
}
|
|
343
|
+
return result;
|
|
338
344
|
}
|
|
339
345
|
generateArrayTypeProperty(schema, terminate = true) {
|
|
340
346
|
const items = schema.content.items;
|
package/dist/core/jsonSchema.js
CHANGED
|
@@ -256,7 +256,7 @@ function searchAllSubSchema(schema, onFoundSchema, onFoundReference) {
|
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
258
258
|
for (const mime of Object.keys(types)) {
|
|
259
|
-
if (/^text\/|^(?:application\/x-www-form-urlencoded$|^application\/([a-z0-9-_.]+\+)?json)$|^application\/octet-stream$|^multipart\/form-data$/.test(mime)) {
|
|
259
|
+
if (/^text\/|^(?:application\/x-www-form-urlencoded$|^application\/([a-z0-9-_.]+\+)?json)$|^application\/octet-stream$|^application\/jwt$|^application\/vnd.apple.pkpass$|^multipart\/form-data$/.test(mime)) {
|
|
260
260
|
const mt = types[mime];
|
|
261
261
|
setSubId(mt.schema, keys);
|
|
262
262
|
}
|
|
@@ -391,10 +391,10 @@ function selectSchemaType(content) {
|
|
|
391
391
|
}
|
|
392
392
|
if ('$schema' in content) {
|
|
393
393
|
const schema = (_a = content['$schema']) !== null && _a !== void 0 ? _a : '';
|
|
394
|
-
if (
|
|
394
|
+
if (/^https?:\/\/json-schema.org\/schema#?$/.test(schema)) {
|
|
395
395
|
return { type: 'Latest' };
|
|
396
396
|
}
|
|
397
|
-
const match =
|
|
397
|
+
const match = /^https?:\/\/json-schema\.org\/(?:draft\/(\d{4}-\d{2})|draft-(\d+))\/schema#?$/.exec(schema);
|
|
398
398
|
if (match) {
|
|
399
399
|
if (match[1] != null) {
|
|
400
400
|
switch (match[1]) {
|
|
@@ -5,7 +5,7 @@ export default class ReferenceResolver {
|
|
|
5
5
|
private readonly referenceCache;
|
|
6
6
|
dereference(refId: string): Schema;
|
|
7
7
|
getAllRegisteredSchema(): IterableIterator<Schema>;
|
|
8
|
-
getAllRegisteredIdAndSchema():
|
|
8
|
+
getAllRegisteredIdAndSchema(): IterableIterator<[string, Schema]>;
|
|
9
9
|
resolve(): Promise<void>;
|
|
10
10
|
private searchParentSchema;
|
|
11
11
|
registerSchema(schema: Schema): void;
|
package/dist/core/type.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare function readSchemaFromUrl(url: string): Promise<Schema>;
|
|
|
24
24
|
export declare function parseFileContent(content: string, filename?: string): JsonSchema;
|
|
25
25
|
export interface PluginContext {
|
|
26
26
|
option: boolean | Record<string, unknown>;
|
|
27
|
-
inputSchemas:
|
|
27
|
+
inputSchemas: IterableIterator<[string, Schema]>;
|
|
28
28
|
}
|
|
29
29
|
export declare type PreProcessHandler = (contents: Schema[]) => Schema[];
|
|
30
30
|
export declare type Plugin = {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildTypeTree = void 0;
|
|
4
|
+
function buildTypeTree(schemas) {
|
|
5
|
+
const tree = buildTree();
|
|
6
|
+
for (const type of schemas) {
|
|
7
|
+
setTypeToTree(tree, type.id.toNames(), type);
|
|
8
|
+
}
|
|
9
|
+
if (tree.children.size === 0) {
|
|
10
|
+
throw new Error('There is no schema in the input contents.');
|
|
11
|
+
}
|
|
12
|
+
return tree;
|
|
13
|
+
}
|
|
14
|
+
exports.buildTypeTree = buildTypeTree;
|
|
15
|
+
function setTypeToTree(tree, paths, type) {
|
|
16
|
+
if (paths.length === 0) {
|
|
17
|
+
throw new Error('The paths is nothing for set the type to TypeTree.');
|
|
18
|
+
}
|
|
19
|
+
let t = tree;
|
|
20
|
+
for (const key of paths) {
|
|
21
|
+
let next = t.children.get(key);
|
|
22
|
+
if (next === undefined) {
|
|
23
|
+
next = buildTree();
|
|
24
|
+
t.children.set(key, next);
|
|
25
|
+
}
|
|
26
|
+
t = next;
|
|
27
|
+
}
|
|
28
|
+
t.schema = type;
|
|
29
|
+
}
|
|
30
|
+
function buildTree() {
|
|
31
|
+
return {
|
|
32
|
+
children: new Map(),
|
|
33
|
+
};
|
|
34
|
+
}
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ import { JsonSchemaObject } from './type';
|
|
|
4
4
|
import SimpleTypes = JsonSchemaDraft04.Schema.Definitions.SimpleTypes;
|
|
5
5
|
export declare function toTSType(type: string, debugSource?: JsonSchemaObject): ts.KeywordTypeSyntaxKind | ts.SyntaxKind.NullKeyword | undefined;
|
|
6
6
|
export declare function reduceTypes(types: SimpleTypes[]): SimpleTypes[];
|
|
7
|
-
export declare function mergeSchema(a: any, b: any):
|
|
7
|
+
export declare function mergeSchema(a: any, b: any): boolean;
|
package/dist/core/utils.js
CHANGED
|
@@ -39,18 +39,16 @@ function reduceTypes(types) {
|
|
|
39
39
|
return types;
|
|
40
40
|
}
|
|
41
41
|
const set = new Set(types);
|
|
42
|
-
if (set.delete('integer')) {
|
|
43
|
-
set.add('number');
|
|
44
|
-
}
|
|
45
42
|
return Array.from(set.values());
|
|
46
43
|
}
|
|
47
44
|
exports.reduceTypes = reduceTypes;
|
|
48
45
|
function mergeSchema(a, b) {
|
|
49
46
|
if ('$ref' in a || '$ref' in b) {
|
|
50
|
-
|
|
47
|
+
a.$ref = b.$ref || a.$ref;
|
|
48
|
+
return false;
|
|
51
49
|
}
|
|
52
50
|
Object.keys(b).forEach((key) => {
|
|
53
|
-
var _a;
|
|
51
|
+
var _a, _b;
|
|
54
52
|
const value = b[key];
|
|
55
53
|
if (a[key] != null && typeof value !== typeof a[key]) {
|
|
56
54
|
debug(`mergeSchema warning: type is mismatched, key=${key}`);
|
|
@@ -59,12 +57,13 @@ function mergeSchema(a, b) {
|
|
|
59
57
|
a[key] = ((_a = a[key]) !== null && _a !== void 0 ? _a : []).concat(value);
|
|
60
58
|
}
|
|
61
59
|
else if (value != null && typeof value === 'object') {
|
|
62
|
-
a[key]
|
|
60
|
+
(_b = a[key]) !== null && _b !== void 0 ? _b : (a[key] = {});
|
|
61
|
+
mergeSchema(a[key], value);
|
|
63
62
|
}
|
|
64
63
|
else {
|
|
65
64
|
a[key] = value;
|
|
66
65
|
}
|
|
67
66
|
});
|
|
68
|
-
return
|
|
67
|
+
return true;
|
|
69
68
|
}
|
|
70
69
|
exports.mergeSchema = mergeSchema;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dtsgenerator",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.0",
|
|
4
4
|
"description": "TypeScript d.ts file generator for JSON Schema file",
|
|
5
5
|
"bin": {
|
|
6
6
|
"dtsgen": "bin/dtsgen"
|
|
@@ -44,37 +44,37 @@
|
|
|
44
44
|
"node": ">= 10.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"commander": "^
|
|
48
|
-
"cross-fetch": "^3.1.
|
|
49
|
-
"debug": "^4.3.
|
|
50
|
-
"glob": "^7.
|
|
47
|
+
"commander": "^9.0.0",
|
|
48
|
+
"cross-fetch": "^3.1.5",
|
|
49
|
+
"debug": "^4.3.3",
|
|
50
|
+
"glob": "^7.2.0",
|
|
51
51
|
"https-proxy-agent": "^5.0.0",
|
|
52
52
|
"js-yaml": "^4.1.0",
|
|
53
53
|
"tslib": "^2.3.1",
|
|
54
|
-
"typescript": "^4.
|
|
54
|
+
"typescript": "^4.5.5"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@dtsgenerator/do-nothing": "^2.5.1",
|
|
58
|
-
"@dtsgenerator/eslint-config": "^0.
|
|
58
|
+
"@dtsgenerator/eslint-config": "^0.5.0",
|
|
59
59
|
"@dtsgenerator/replace-namespace": "^1.5.1",
|
|
60
60
|
"@dtsgenerator/single-quote": "^1.6.1",
|
|
61
|
-
"@istanbuljs/nyc-config-typescript": "^1.0.
|
|
61
|
+
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
62
62
|
"@types/debug": "^4.1.7",
|
|
63
|
-
"@types/glob": "^7.
|
|
64
|
-
"@types/js-yaml": "^4.0.
|
|
63
|
+
"@types/glob": "^7.2.0",
|
|
64
|
+
"@types/js-yaml": "^4.0.5",
|
|
65
65
|
"@types/mkdirp": "^1.0.2",
|
|
66
|
-
"@types/mocha": "^9.
|
|
67
|
-
"@types/node": "^16.
|
|
66
|
+
"@types/mocha": "^9.1.0",
|
|
67
|
+
"@types/node": "^16.11.22",
|
|
68
68
|
"cross-env": "^7.0.3",
|
|
69
|
-
"eslint": "^
|
|
70
|
-
"husky": "^7.0.
|
|
71
|
-
"lint-staged": "^
|
|
72
|
-
"mocha": "^9.
|
|
69
|
+
"eslint": "^8.8.0",
|
|
70
|
+
"husky": "^7.0.4",
|
|
71
|
+
"lint-staged": "^12.3.3",
|
|
72
|
+
"mocha": "^9.2.0",
|
|
73
73
|
"nyc": "^15.1.0",
|
|
74
|
-
"prettier": "^2.
|
|
74
|
+
"prettier": "^2.5.1",
|
|
75
75
|
"rimraf": "^3.0.2",
|
|
76
|
-
"source-map-support": "^0.5.
|
|
77
|
-
"ts-node": "^10.
|
|
76
|
+
"source-map-support": "^0.5.21",
|
|
77
|
+
"ts-node": "^10.4.0"
|
|
78
78
|
},
|
|
79
79
|
"lint-staged": {
|
|
80
80
|
"**/*.ts": [
|
package/src/commandOptions.ts
CHANGED
|
@@ -47,7 +47,7 @@ function parse(options: CommandOptions, argv: string[]): commander.Command {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-assignment
|
|
50
|
-
const pkg: Record<string,
|
|
50
|
+
const pkg: Record<string, string> = require('../package.json');
|
|
51
51
|
|
|
52
52
|
// <hoge> is required, [hoge] is optional
|
|
53
53
|
program
|
package/src/core/astBuilder.ts
CHANGED
|
@@ -9,9 +9,6 @@ function buildTypeNameIdentifier(name: string): ts.Identifier {
|
|
|
9
9
|
return ts.factory.createIdentifier(toValidIdentifier(name, config.target));
|
|
10
10
|
}
|
|
11
11
|
function buildPropertyNameIdentifier(name: string): ts.PropertyName {
|
|
12
|
-
if (/^\d/.test(name)) {
|
|
13
|
-
name = '$' + name;
|
|
14
|
-
}
|
|
15
12
|
if (checkInvalidCharacter(name, config.target)) {
|
|
16
13
|
return ts.factory.createIdentifier(name);
|
|
17
14
|
} else {
|
|
@@ -198,6 +195,17 @@ export function buildUnionTypeNode<T>(
|
|
|
198
195
|
return ts.factory.createParenthesizedType(node);
|
|
199
196
|
}
|
|
200
197
|
|
|
198
|
+
export function buildIntersectionTypeNode(
|
|
199
|
+
types: readonly ts.TypeNode[],
|
|
200
|
+
terminate: boolean
|
|
201
|
+
): ts.TypeNode {
|
|
202
|
+
const node = ts.factory.createIntersectionTypeNode(types);
|
|
203
|
+
if (terminate) {
|
|
204
|
+
return node;
|
|
205
|
+
}
|
|
206
|
+
return ts.factory.createParenthesizedType(node);
|
|
207
|
+
}
|
|
208
|
+
|
|
201
209
|
export function buildTupleTypeNode(
|
|
202
210
|
types: ts.TypeNode | ts.TypeNode[],
|
|
203
211
|
minItems?: number,
|
|
@@ -325,7 +333,7 @@ function getComment(schema: NormalizedSchema): string[] {
|
|
|
325
333
|
function protectComment(str: string): string {
|
|
326
334
|
return str.replace(/\*\//g, '*\u200B/'); // Unicode [ZERO WIDTH SPACE]
|
|
327
335
|
}
|
|
328
|
-
function appendComment(value?:
|
|
336
|
+
function appendComment(value?: any): void {
|
|
329
337
|
if (value == null) {
|
|
330
338
|
return;
|
|
331
339
|
}
|
package/src/core/dtsGenerator.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Debug from 'debug';
|
|
2
2
|
import * as ts from 'typescript';
|
|
3
|
-
import {
|
|
3
|
+
import { tilde } from '../jsonPointer';
|
|
4
4
|
import * as ast from './astBuilder';
|
|
5
5
|
import config from './config';
|
|
6
6
|
import { getSubSchema, NormalizedSchema } from './jsonSchema';
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
PreProcessHandler,
|
|
14
14
|
loadPlugin,
|
|
15
15
|
} from './type';
|
|
16
|
+
import { buildTypeTree, TypeTree } from './typeTree';
|
|
16
17
|
import * as utils from './utils';
|
|
17
18
|
|
|
18
19
|
const debug = Debug('dtsgen');
|
|
19
|
-
const typeMarker = Symbol();
|
|
20
20
|
|
|
21
21
|
interface PluginConfig {
|
|
22
22
|
plugin: Plugin;
|
|
@@ -42,11 +42,8 @@ export default class DtsGenerator {
|
|
|
42
42
|
this.contents.forEach((schema) => this.resolver.registerSchema(schema));
|
|
43
43
|
await this.resolver.resolve();
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
this.resolver.getAllRegisteredSchema()
|
|
48
|
-
);
|
|
49
|
-
const root = this.walk(map, true);
|
|
45
|
+
const tree = buildTypeTree(this.resolver.getAllRegisteredSchema());
|
|
46
|
+
const root = this.walk(tree);
|
|
50
47
|
const file = ts.createSourceFile(
|
|
51
48
|
'_.d.ts',
|
|
52
49
|
'',
|
|
@@ -77,31 +74,6 @@ export default class DtsGenerator {
|
|
|
77
74
|
return transformedContent;
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
private buildSchemaMergedMap(schemas: IterableIterator<Schema>): any {
|
|
81
|
-
const map: any = {};
|
|
82
|
-
const paths: { path: string[]; type: Schema }[] = [];
|
|
83
|
-
for (const type of schemas) {
|
|
84
|
-
const path = type.id.toNames();
|
|
85
|
-
paths.push({ path, type });
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
for (const item of paths) {
|
|
89
|
-
const path = item.path;
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
91
|
-
const parent = get(map, path, true);
|
|
92
|
-
if (parent == null) {
|
|
93
|
-
set(map, path, { [typeMarker]: item.type });
|
|
94
|
-
} else {
|
|
95
|
-
Object.assign(parent, { [typeMarker]: item.type });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (Object.keys(map).length === 0) {
|
|
99
|
-
throw new Error('There is no schema in the input contents.');
|
|
100
|
-
}
|
|
101
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
102
|
-
return map;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
77
|
private async getPlugins(): Promise<{
|
|
106
78
|
pre: PluginConfig[];
|
|
107
79
|
post: PluginConfig[];
|
|
@@ -169,24 +141,22 @@ export default class DtsGenerator {
|
|
|
169
141
|
return result;
|
|
170
142
|
}
|
|
171
143
|
|
|
172
|
-
private walk(
|
|
144
|
+
private walk(tree: TypeTree, root = true): ts.Statement[] {
|
|
173
145
|
const result: ts.Statement[] = [];
|
|
174
|
-
const keys =
|
|
146
|
+
const keys = [...tree.children.keys()].sort();
|
|
175
147
|
for (const key of keys) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
183
|
-
const schema = value[typeMarker] as Schema;
|
|
148
|
+
const value = tree.children.get(key);
|
|
149
|
+
if (value === undefined) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (value.schema !== undefined) {
|
|
153
|
+
const schema = value.schema;
|
|
184
154
|
debug(
|
|
185
155
|
` walk doProcess: key=${key} schemaId=${schema.id.getAbsoluteId()}`
|
|
186
156
|
);
|
|
187
157
|
result.push(this.walkSchema(schema, root));
|
|
188
158
|
}
|
|
189
|
-
if (
|
|
159
|
+
if (value.children.size > 0) {
|
|
190
160
|
result.push(
|
|
191
161
|
ast.buildNamespaceNode(key, this.walk(value, false), root)
|
|
192
162
|
);
|
|
@@ -199,25 +169,33 @@ export default class DtsGenerator {
|
|
|
199
169
|
const normalized = this.normalizeContent(schema);
|
|
200
170
|
this.currentSchema = normalized;
|
|
201
171
|
|
|
202
|
-
const getNode = () => {
|
|
203
|
-
const type = normalized.content.type;
|
|
204
|
-
switch (type) {
|
|
205
|
-
case 'any':
|
|
206
|
-
return this.generateAnyTypeModel(normalized, root);
|
|
207
|
-
case 'array':
|
|
208
|
-
return this.generateTypeCollection(normalized, root);
|
|
209
|
-
case 'object':
|
|
210
|
-
default:
|
|
211
|
-
return this.generateDeclareType(normalized, root);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
172
|
return ast.addOptionalInformation(
|
|
215
|
-
ast.addComment(
|
|
173
|
+
ast.addComment(
|
|
174
|
+
this.parseSchema(normalized, root),
|
|
175
|
+
normalized,
|
|
176
|
+
true
|
|
177
|
+
),
|
|
216
178
|
normalized,
|
|
217
179
|
true
|
|
218
180
|
);
|
|
219
181
|
}
|
|
220
182
|
|
|
183
|
+
private parseSchema(
|
|
184
|
+
schema: NormalizedSchema,
|
|
185
|
+
root = false
|
|
186
|
+
): ts.DeclarationStatement {
|
|
187
|
+
const type = schema.content.type;
|
|
188
|
+
switch (type) {
|
|
189
|
+
case 'any':
|
|
190
|
+
return this.generateAnyTypeModel(schema, root);
|
|
191
|
+
case 'array':
|
|
192
|
+
return this.generateTypeCollection(schema, root);
|
|
193
|
+
case 'object':
|
|
194
|
+
default:
|
|
195
|
+
return this.generateDeclareType(schema, root);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
221
199
|
private normalizeContent(
|
|
222
200
|
schema: Schema,
|
|
223
201
|
pointer?: string
|
|
@@ -361,18 +339,21 @@ export default class DtsGenerator {
|
|
|
361
339
|
}
|
|
362
340
|
}
|
|
363
341
|
if (content.patternProperties) {
|
|
364
|
-
const
|
|
365
|
-
for (const propertyName of Object.keys(content.patternProperties)) {
|
|
366
|
-
const schema = this.normalizeContent(
|
|
367
|
-
baseSchema,
|
|
368
|
-
'/patternProperties/' + tilde(propertyName)
|
|
369
|
-
);
|
|
370
|
-
schemasTypes.push(this.generateTypeProperty(schema));
|
|
371
|
-
}
|
|
342
|
+
const properties = Object.keys(content.patternProperties);
|
|
372
343
|
const node = ast.buildPropertySignature(
|
|
373
344
|
{ content: { readOnly: false } } as NormalizedSchema,
|
|
374
345
|
'pattern',
|
|
375
|
-
|
|
346
|
+
ast.buildUnionTypeNode(
|
|
347
|
+
properties,
|
|
348
|
+
(propertyName) =>
|
|
349
|
+
this.generateTypeProperty(
|
|
350
|
+
this.normalizeContent(
|
|
351
|
+
baseSchema,
|
|
352
|
+
'/patternProperties/' + tilde(propertyName)
|
|
353
|
+
)
|
|
354
|
+
),
|
|
355
|
+
true
|
|
356
|
+
),
|
|
376
357
|
baseSchema.content.required,
|
|
377
358
|
true
|
|
378
359
|
);
|
|
@@ -380,9 +361,7 @@ export default class DtsGenerator {
|
|
|
380
361
|
ts.addSyntheticTrailingComment(
|
|
381
362
|
node,
|
|
382
363
|
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
383
|
-
` Patterns: ${
|
|
384
|
-
' | '
|
|
385
|
-
)} `
|
|
364
|
+
` Patterns: ${properties.join(' | ')} `
|
|
386
365
|
)
|
|
387
366
|
);
|
|
388
367
|
}
|
|
@@ -401,20 +380,21 @@ export default class DtsGenerator {
|
|
|
401
380
|
);
|
|
402
381
|
}
|
|
403
382
|
const refSchema = this.normalizeContent(ref);
|
|
404
|
-
const node = ast.
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
383
|
+
const node = ast.addOptionalInformation(
|
|
384
|
+
ast.addComment(
|
|
385
|
+
ast.buildTypeReferenceNode(refSchema, this.currentSchema),
|
|
386
|
+
refSchema,
|
|
387
|
+
false
|
|
388
|
+
),
|
|
410
389
|
refSchema,
|
|
411
390
|
false
|
|
412
391
|
);
|
|
392
|
+
return node;
|
|
413
393
|
}
|
|
414
394
|
if (content.anyOf) {
|
|
415
395
|
const mergeContent = Object.assign({}, content);
|
|
416
396
|
delete mergeContent.anyOf;
|
|
417
|
-
return this.
|
|
397
|
+
return this.generateUnionType(
|
|
418
398
|
schema,
|
|
419
399
|
content.anyOf,
|
|
420
400
|
mergeContent,
|
|
@@ -425,7 +405,7 @@ export default class DtsGenerator {
|
|
|
425
405
|
if (content.oneOf) {
|
|
426
406
|
const mergeContent = Object.assign({}, content);
|
|
427
407
|
delete mergeContent.oneOf;
|
|
428
|
-
return this.
|
|
408
|
+
return this.generateUnionType(
|
|
429
409
|
schema,
|
|
430
410
|
content.oneOf,
|
|
431
411
|
mergeContent,
|
|
@@ -433,6 +413,13 @@ export default class DtsGenerator {
|
|
|
433
413
|
terminate
|
|
434
414
|
);
|
|
435
415
|
}
|
|
416
|
+
return this.generateLiteralTypeProperty(schema, terminate);
|
|
417
|
+
}
|
|
418
|
+
private generateLiteralTypeProperty(
|
|
419
|
+
schema: NormalizedSchema,
|
|
420
|
+
terminate = true
|
|
421
|
+
): ts.TypeNode {
|
|
422
|
+
const content = schema.content;
|
|
436
423
|
if (content.enum) {
|
|
437
424
|
return ast.buildUnionTypeNode(
|
|
438
425
|
content.enum,
|
|
@@ -449,6 +436,25 @@ export default class DtsGenerator {
|
|
|
449
436
|
return this.generateType(schema, terminate);
|
|
450
437
|
}
|
|
451
438
|
}
|
|
439
|
+
private checkExistOtherType(
|
|
440
|
+
content: JsonSchemaObject,
|
|
441
|
+
base: NormalizedSchema
|
|
442
|
+
): ts.TypeNode | undefined {
|
|
443
|
+
const schema = Object.assign({}, base, { content });
|
|
444
|
+
const result = this.generateLiteralTypeProperty(schema, false);
|
|
445
|
+
if (result.kind === ts.SyntaxKind.AnyKeyword) {
|
|
446
|
+
return undefined;
|
|
447
|
+
} else if (result.kind === ts.SyntaxKind.TypeLiteral) {
|
|
448
|
+
const node = result as ts.TypeLiteralNode;
|
|
449
|
+
if (
|
|
450
|
+
node.members.length === 1 &&
|
|
451
|
+
node.members[0].kind === ts.SyntaxKind.IndexSignature
|
|
452
|
+
) {
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return result;
|
|
457
|
+
}
|
|
452
458
|
private generateLiteralTypeNode(
|
|
453
459
|
content: JsonSchemaObject,
|
|
454
460
|
value: any
|
|
@@ -458,11 +464,11 @@ export default class DtsGenerator {
|
|
|
458
464
|
case 'number':
|
|
459
465
|
return ast.buildNumericLiteralTypeNode(String(value));
|
|
460
466
|
case 'boolean':
|
|
461
|
-
return ast.buildBooleanLiteralTypeNode(value);
|
|
467
|
+
return ast.buildBooleanLiteralTypeNode(Boolean(value));
|
|
462
468
|
case 'null':
|
|
463
469
|
return ast.buildNullKeyword();
|
|
464
470
|
case 'string':
|
|
465
|
-
return ast.buildStringLiteralTypeNode(value);
|
|
471
|
+
return ast.buildStringLiteralTypeNode(String(value));
|
|
466
472
|
}
|
|
467
473
|
if (value === null) {
|
|
468
474
|
return ast.buildNullKeyword();
|
|
@@ -478,39 +484,51 @@ export default class DtsGenerator {
|
|
|
478
484
|
return ast.buildStringLiteralTypeNode(String(value));
|
|
479
485
|
}
|
|
480
486
|
|
|
481
|
-
private
|
|
487
|
+
private generateUnionType(
|
|
482
488
|
baseSchema: NormalizedSchema,
|
|
483
489
|
contents: JsonSchema[],
|
|
484
|
-
mergeContent:
|
|
490
|
+
mergeContent: JsonSchemaObject,
|
|
485
491
|
path: string,
|
|
486
492
|
terminate: boolean
|
|
487
493
|
): ts.TypeNode {
|
|
488
|
-
|
|
494
|
+
const merged: boolean[] = [];
|
|
495
|
+
const children = contents.map((_, index) => {
|
|
496
|
+
const schema = this.normalizeContent(
|
|
497
|
+
baseSchema,
|
|
498
|
+
path + index.toString()
|
|
499
|
+
);
|
|
500
|
+
merged.push(utils.mergeSchema(schema.content, mergeContent));
|
|
501
|
+
return schema;
|
|
502
|
+
});
|
|
503
|
+
const allRef = merged.every((b) => !b);
|
|
504
|
+
const baseType = this.checkExistOtherType(mergeContent, baseSchema);
|
|
505
|
+
|
|
506
|
+
const result = ast.addOptionalInformation(
|
|
489
507
|
ast.addComment(
|
|
490
508
|
ast.buildUnionTypeNode(
|
|
491
|
-
|
|
492
|
-
(
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
schema,
|
|
509
|
+
children,
|
|
510
|
+
(schema, index) => {
|
|
511
|
+
const node = schema.id.isEmpty()
|
|
512
|
+
? ast.addOptionalInformation(
|
|
513
|
+
this.generateTypeProperty(schema, false),
|
|
514
|
+
schema,
|
|
515
|
+
false
|
|
516
|
+
)
|
|
517
|
+
: ast.addOptionalInformation(
|
|
518
|
+
ast.buildTypeReferenceNode(
|
|
519
|
+
schema,
|
|
520
|
+
this.currentSchema
|
|
521
|
+
),
|
|
522
|
+
schema,
|
|
523
|
+
false
|
|
524
|
+
);
|
|
525
|
+
if (baseType != null && !allRef && !merged[index]) {
|
|
526
|
+
return ast.buildIntersectionTypeNode(
|
|
527
|
+
[baseType, node],
|
|
511
528
|
false
|
|
512
529
|
);
|
|
513
530
|
}
|
|
531
|
+
return node;
|
|
514
532
|
},
|
|
515
533
|
terminate
|
|
516
534
|
),
|
|
@@ -520,6 +538,10 @@ export default class DtsGenerator {
|
|
|
520
538
|
baseSchema,
|
|
521
539
|
terminate
|
|
522
540
|
);
|
|
541
|
+
if (baseType != null && allRef) {
|
|
542
|
+
return ast.buildIntersectionTypeNode([baseType, result], terminate);
|
|
543
|
+
}
|
|
544
|
+
return result;
|
|
523
545
|
}
|
|
524
546
|
|
|
525
547
|
private generateArrayTypeProperty(
|
package/src/core/jsonSchema.ts
CHANGED
|
@@ -379,7 +379,7 @@ export function searchAllSubSchema(
|
|
|
379
379
|
}
|
|
380
380
|
for (const mime of Object.keys(types)) {
|
|
381
381
|
if (
|
|
382
|
-
/^text\/|^(?:application\/x-www-form-urlencoded$|^application\/([a-z0-9-_.]+\+)?json)$|^application\/octet-stream$|^multipart\/form-data$/.test(
|
|
382
|
+
/^text\/|^(?:application\/x-www-form-urlencoded$|^application\/([a-z0-9-_.]+\+)?json)$|^application\/octet-stream$|^application\/jwt$|^application\/vnd.apple.pkpass$|^multipart\/form-data$/.test(
|
|
383
383
|
mime
|
|
384
384
|
)
|
|
385
385
|
) {
|
|
@@ -555,11 +555,11 @@ export function selectSchemaType(content: JsonSchema | OpenApiSchema): {
|
|
|
555
555
|
}
|
|
556
556
|
if ('$schema' in content) {
|
|
557
557
|
const schema = content['$schema'] ?? '';
|
|
558
|
-
if (
|
|
558
|
+
if (/^https?:\/\/json-schema.org\/schema#?$/.test(schema)) {
|
|
559
559
|
return { type: 'Latest' };
|
|
560
560
|
}
|
|
561
561
|
const match =
|
|
562
|
-
|
|
562
|
+
/^https?:\/\/json-schema\.org\/(?:draft\/(\d{4}-\d{2})|draft-(\d+))\/schema#?$/.exec(
|
|
563
563
|
schema
|
|
564
564
|
);
|
|
565
565
|
if (match) {
|
|
@@ -21,7 +21,7 @@ export default class ReferenceResolver {
|
|
|
21
21
|
public getAllRegisteredSchema(): IterableIterator<Schema> {
|
|
22
22
|
return this.schemaCache.values();
|
|
23
23
|
}
|
|
24
|
-
public getAllRegisteredIdAndSchema():
|
|
24
|
+
public getAllRegisteredIdAndSchema(): IterableIterator<[string, Schema]> {
|
|
25
25
|
return this.schemaCache.entries();
|
|
26
26
|
}
|
|
27
27
|
|
package/src/core/type.ts
CHANGED
|
@@ -114,7 +114,7 @@ function deepCopy(obj: any): any {
|
|
|
114
114
|
|
|
115
115
|
export interface PluginContext {
|
|
116
116
|
option: boolean | Record<string, unknown>;
|
|
117
|
-
inputSchemas:
|
|
117
|
+
inputSchemas: IterableIterator<[string, Schema]>;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
export type PreProcessHandler = (contents: Schema[]) => Schema[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Schema } from './type';
|
|
2
|
+
|
|
3
|
+
export interface TypeTree {
|
|
4
|
+
children: Map<string, TypeTree>;
|
|
5
|
+
schema?: Schema;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function buildTypeTree(schemas: IterableIterator<Schema>): TypeTree {
|
|
9
|
+
const tree: TypeTree = buildTree();
|
|
10
|
+
for (const type of schemas) {
|
|
11
|
+
setTypeToTree(tree, type.id.toNames(), type);
|
|
12
|
+
}
|
|
13
|
+
if (tree.children.size === 0) {
|
|
14
|
+
throw new Error('There is no schema in the input contents.');
|
|
15
|
+
}
|
|
16
|
+
return tree;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function setTypeToTree(tree: TypeTree, paths: string[], type: Schema): void {
|
|
20
|
+
if (paths.length === 0) {
|
|
21
|
+
throw new Error('The paths is nothing for set the type to TypeTree.');
|
|
22
|
+
}
|
|
23
|
+
let t: TypeTree = tree;
|
|
24
|
+
for (const key of paths) {
|
|
25
|
+
let next = t.children.get(key);
|
|
26
|
+
if (next === undefined) {
|
|
27
|
+
next = buildTree();
|
|
28
|
+
t.children.set(key, next);
|
|
29
|
+
}
|
|
30
|
+
t = next;
|
|
31
|
+
}
|
|
32
|
+
t.schema = type;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildTree(): TypeTree {
|
|
36
|
+
return {
|
|
37
|
+
children: new Map(),
|
|
38
|
+
};
|
|
39
|
+
}
|
package/src/core/utils.ts
CHANGED
|
@@ -52,18 +52,16 @@ export function reduceTypes(types: SimpleTypes[]): SimpleTypes[] {
|
|
|
52
52
|
return types;
|
|
53
53
|
}
|
|
54
54
|
const set = new Set<SimpleTypes>(types);
|
|
55
|
-
if (set.delete('integer')) {
|
|
56
|
-
set.add('number');
|
|
57
|
-
}
|
|
58
55
|
return Array.from(set.values());
|
|
59
56
|
}
|
|
60
57
|
|
|
61
58
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
62
|
-
export function mergeSchema(a: any, b: any):
|
|
59
|
+
export function mergeSchema(a: any, b: any): boolean {
|
|
63
60
|
if ('$ref' in a || '$ref' in b) {
|
|
64
|
-
|
|
61
|
+
a.$ref = b.$ref || a.$ref;
|
|
62
|
+
return false;
|
|
65
63
|
}
|
|
66
|
-
Object.keys(b).forEach((key: string) => {
|
|
64
|
+
Object.keys(b as object).forEach((key: string) => {
|
|
67
65
|
const value = b[key];
|
|
68
66
|
if (a[key] != null && typeof value !== typeof a[key]) {
|
|
69
67
|
debug(`mergeSchema warning: type is mismatched, key=${key}`);
|
|
@@ -72,11 +70,11 @@ export function mergeSchema(a: any, b: any): any {
|
|
|
72
70
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
73
71
|
a[key] = (a[key] ?? []).concat(value);
|
|
74
72
|
} else if (value != null && typeof value === 'object') {
|
|
75
|
-
a[key]
|
|
73
|
+
a[key] ??= {};
|
|
74
|
+
mergeSchema(a[key], value);
|
|
76
75
|
} else {
|
|
77
76
|
a[key] = value;
|
|
78
77
|
}
|
|
79
78
|
});
|
|
80
|
-
|
|
81
|
-
return a;
|
|
79
|
+
return true;
|
|
82
80
|
}
|