UNPKG

26.3 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var tslib_1 = require("tslib");
4var debug_1 = tslib_1.__importDefault(require("debug"));
5var typescript_1 = tslib_1.__importDefault(require("typescript"));
6var jsonPointer_1 = require("../jsonPointer");
7var type_1 = require("./type");
8var ast = tslib_1.__importStar(require("./astBuilder"));
9var config_1 = tslib_1.__importDefault(require("./config"));
10var jsonSchema_1 = require("./jsonSchema");
11var referenceResolver_1 = tslib_1.__importDefault(require("./referenceResolver"));
12var utils = tslib_1.__importStar(require("./utils"));
13var debug = debug_1.default('dtsgen');
14var typeMarker = Symbol();
15var DtsGenerator = (function () {
16 function DtsGenerator(contents) {
17 this.contents = contents;
18 this.resolver = new referenceResolver_1.default();
19 }
20 DtsGenerator.prototype.generate = function () {
21 return tslib_1.__awaiter(this, void 0, void 0, function () {
22 var plugins, preProcess, preProcess_1, preProcess_1_1, p, map, root, file, postProcess, result, printer;
23 var e_1, _a;
24 var _this = this;
25 return tslib_1.__generator(this, function (_b) {
26 switch (_b.label) {
27 case 0: return [4, this.getPlugins()];
28 case 1:
29 plugins = _b.sent();
30 return [4, this.getPreProcess(plugins.pre)];
31 case 2:
32 preProcess = _b.sent();
33 try {
34 for (preProcess_1 = tslib_1.__values(preProcess), preProcess_1_1 = preProcess_1.next(); !preProcess_1_1.done; preProcess_1_1 = preProcess_1.next()) {
35 p = preProcess_1_1.value;
36 this.contents = p(this.contents);
37 }
38 }
39 catch (e_1_1) { e_1 = { error: e_1_1 }; }
40 finally {
41 try {
42 if (preProcess_1_1 && !preProcess_1_1.done && (_a = preProcess_1.return)) _a.call(preProcess_1);
43 }
44 finally { if (e_1) throw e_1.error; }
45 }
46 debug('generate type definition files.');
47 this.contents.forEach(function (schema) { return _this.resolver.registerSchema(schema); });
48 return [4, this.resolver.resolve()];
49 case 3:
50 _b.sent();
51 map = this.buildSchemaMergedMap(this.resolver.getAllRegisteredSchema());
52 root = this.walk(map, true);
53 file = typescript_1.default.createSourceFile('_.d.ts', '', config_1.default.target, false, typescript_1.default.ScriptKind.TS);
54 file.statements = typescript_1.default.createNodeArray(root);
55 return [4, this.getPostProcess(plugins.post)];
56 case 4:
57 postProcess = _b.sent();
58 result = typescript_1.default.transform(file, postProcess);
59 result.dispose();
60 if (config_1.default.outputAST) {
61 return [2, JSON.stringify(file, null, 2)];
62 }
63 else {
64 printer = typescript_1.default.createPrinter();
65 return [2, printer.printFile(file)];
66 }
67 return [2];
68 }
69 });
70 });
71 };
72 DtsGenerator.prototype.buildSchemaMergedMap = function (schemas) {
73 var e_2, _a, e_3, _b, _c;
74 var map = {};
75 var paths = [];
76 try {
77 for (var schemas_1 = tslib_1.__values(schemas), schemas_1_1 = schemas_1.next(); !schemas_1_1.done; schemas_1_1 = schemas_1.next()) {
78 var type = schemas_1_1.value;
79 var path = type.id.toNames();
80 paths.push({ path: path, type: type });
81 }
82 }
83 catch (e_2_1) { e_2 = { error: e_2_1 }; }
84 finally {
85 try {
86 if (schemas_1_1 && !schemas_1_1.done && (_a = schemas_1.return)) _a.call(schemas_1);
87 }
88 finally { if (e_2) throw e_2.error; }
89 }
90 try {
91 for (var paths_1 = tslib_1.__values(paths), paths_1_1 = paths_1.next(); !paths_1_1.done; paths_1_1 = paths_1.next()) {
92 var item = paths_1_1.value;
93 var path = item.path;
94 var parent_1 = jsonPointer_1.get(map, path, true);
95 if (parent_1 == null) {
96 jsonPointer_1.set(map, path, (_c = {}, _c[typeMarker] = item.type, _c));
97 }
98 else {
99 parent_1[typeMarker] = item.type;
100 }
101 }
102 }
103 catch (e_3_1) { e_3 = { error: e_3_1 }; }
104 finally {
105 try {
106 if (paths_1_1 && !paths_1_1.done && (_b = paths_1.return)) _b.call(paths_1);
107 }
108 finally { if (e_3) throw e_3.error; }
109 }
110 if (Object.keys(map).length === 0) {
111 throw new Error('There is no schema in the input contents.');
112 }
113 return map;
114 };
115 DtsGenerator.prototype.getPlugins = function () {
116 return tslib_1.__awaiter(this, void 0, void 0, function () {
117 var pre, post, _a, _b, _c, name_1, option, plugin, e_4_1;
118 var e_4, _d;
119 return tslib_1.__generator(this, function (_e) {
120 switch (_e.label) {
121 case 0:
122 pre = [];
123 post = [];
124 _e.label = 1;
125 case 1:
126 _e.trys.push([1, 6, 7, 8]);
127 _a = tslib_1.__values(Object.entries(config_1.default.plugins)), _b = _a.next();
128 _e.label = 2;
129 case 2:
130 if (!!_b.done) return [3, 5];
131 _c = tslib_1.__read(_b.value, 2), name_1 = _c[0], option = _c[1];
132 return [4, type_1.loadPlugin(name_1, option)];
133 case 3:
134 plugin = _e.sent();
135 if (plugin == null) {
136 return [3, 4];
137 }
138 if (plugin.preProcess != null) {
139 pre.push({ plugin: plugin, option: option });
140 }
141 if (plugin.postProcess != null) {
142 post.push({ plugin: plugin, option: option });
143 }
144 _e.label = 4;
145 case 4:
146 _b = _a.next();
147 return [3, 2];
148 case 5: return [3, 8];
149 case 6:
150 e_4_1 = _e.sent();
151 e_4 = { error: e_4_1 };
152 return [3, 8];
153 case 7:
154 try {
155 if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
156 }
157 finally { if (e_4) throw e_4.error; }
158 return [7];
159 case 8: return [2, { pre: pre, post: post }];
160 }
161 });
162 });
163 };
164 DtsGenerator.prototype.getPreProcess = function (pre) {
165 return tslib_1.__awaiter(this, void 0, void 0, function () {
166 var result, inputSchemas, pre_1, pre_1_1, pc, p, handler, e_5_1;
167 var e_5, _a;
168 return tslib_1.__generator(this, function (_b) {
169 switch (_b.label) {
170 case 0:
171 debug('load pre process plugin.');
172 result = [];
173 inputSchemas = this.resolver.getAllRegisteredIdAndSchema();
174 _b.label = 1;
175 case 1:
176 _b.trys.push([1, 6, 7, 8]);
177 pre_1 = tslib_1.__values(pre), pre_1_1 = pre_1.next();
178 _b.label = 2;
179 case 2:
180 if (!!pre_1_1.done) return [3, 5];
181 pc = pre_1_1.value;
182 p = pc.plugin.preProcess;
183 if (p == null) {
184 return [3, 4];
185 }
186 return [4, p({ inputSchemas: inputSchemas, option: pc.option })];
187 case 3:
188 handler = _b.sent();
189 if (handler != null) {
190 result.push(handler);
191 debug(' pre process plugin:', pc.plugin.meta.name, pc.plugin.meta.description);
192 }
193 _b.label = 4;
194 case 4:
195 pre_1_1 = pre_1.next();
196 return [3, 2];
197 case 5: return [3, 8];
198 case 6:
199 e_5_1 = _b.sent();
200 e_5 = { error: e_5_1 };
201 return [3, 8];
202 case 7:
203 try {
204 if (pre_1_1 && !pre_1_1.done && (_a = pre_1.return)) _a.call(pre_1);
205 }
206 finally { if (e_5) throw e_5.error; }
207 return [7];
208 case 8: return [2, result];
209 }
210 });
211 });
212 };
213 DtsGenerator.prototype.getPostProcess = function (post) {
214 return tslib_1.__awaiter(this, void 0, void 0, function () {
215 var result, inputSchemas, post_1, post_1_1, pc, p, factory, e_6_1;
216 var e_6, _a;
217 return tslib_1.__generator(this, function (_b) {
218 switch (_b.label) {
219 case 0:
220 debug('load post process plugin.');
221 result = [];
222 inputSchemas = this.resolver.getAllRegisteredIdAndSchema();
223 _b.label = 1;
224 case 1:
225 _b.trys.push([1, 6, 7, 8]);
226 post_1 = tslib_1.__values(post), post_1_1 = post_1.next();
227 _b.label = 2;
228 case 2:
229 if (!!post_1_1.done) return [3, 5];
230 pc = post_1_1.value;
231 p = pc.plugin.postProcess;
232 if (p == null) {
233 return [3, 4];
234 }
235 return [4, p({ inputSchemas: inputSchemas, option: pc.option })];
236 case 3:
237 factory = _b.sent();
238 if (factory != null) {
239 result.push(factory);
240 debug(' pre process plugin:', pc.plugin.meta.name, pc.plugin.meta.description);
241 }
242 _b.label = 4;
243 case 4:
244 post_1_1 = post_1.next();
245 return [3, 2];
246 case 5: return [3, 8];
247 case 6:
248 e_6_1 = _b.sent();
249 e_6 = { error: e_6_1 };
250 return [3, 8];
251 case 7:
252 try {
253 if (post_1_1 && !post_1_1.done && (_a = post_1.return)) _a.call(post_1);
254 }
255 finally { if (e_6) throw e_6.error; }
256 return [7];
257 case 8: return [2, result];
258 }
259 });
260 });
261 };
262 DtsGenerator.prototype.walk = function (map, root) {
263 var e_7, _a;
264 var result = [];
265 var keys = Object.keys(map).sort();
266 try {
267 for (var keys_1 = tslib_1.__values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
268 var key = keys_1_1.value;
269 var value = map[key];
270 if (Object.prototype.hasOwnProperty.call(value, typeMarker)) {
271 var schema = value[typeMarker];
272 debug(" walk doProcess: key=" + key + " schemaId=" + schema.id.getAbsoluteId());
273 result.push(this.walkSchema(schema, root));
274 }
275 if (typeof value === 'object' && Object.keys(value).length > 0) {
276 result.push(ast.buildNamespaceNode(key, this.walk(value, false), root));
277 }
278 }
279 }
280 catch (e_7_1) { e_7 = { error: e_7_1 }; }
281 finally {
282 try {
283 if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1);
284 }
285 finally { if (e_7) throw e_7.error; }
286 }
287 return result;
288 };
289 DtsGenerator.prototype.walkSchema = function (schema, root) {
290 var _this = this;
291 var normalized = this.normalizeContent(schema);
292 this.currentSchema = normalized;
293 var getNode = function () {
294 var type = normalized.content.type;
295 switch (type) {
296 case 'any':
297 return _this.generateAnyTypeModel(normalized, root);
298 case 'array':
299 return _this.generateTypeCollection(normalized, root);
300 case 'object':
301 default:
302 return _this.generateDeclareType(normalized, root);
303 }
304 };
305 return ast.addOptionalInformation(ast.addComment(getNode(), normalized, true), normalized, true);
306 };
307 DtsGenerator.prototype.normalizeContent = function (schema, pointer) {
308 if (pointer != null) {
309 schema = jsonSchema_1.getSubSchema(schema, pointer);
310 }
311 schema.content = this.normalizeSchemaContent(schema.content);
312 return Object.assign({}, schema);
313 };
314 DtsGenerator.prototype.normalizeSchemaContent = function (content) {
315 var e_8, _a;
316 if (typeof content === 'boolean') {
317 content = content ? {} : { not: {} };
318 }
319 else {
320 if (content.allOf) {
321 var work = {};
322 var allOf = content.allOf;
323 delete content.allOf;
324 try {
325 for (var allOf_1 = tslib_1.__values(allOf), allOf_1_1 = allOf_1.next(); !allOf_1_1.done; allOf_1_1 = allOf_1.next()) {
326 var sub = allOf_1_1.value;
327 if (typeof sub === 'object' && sub.$ref) {
328 var ref = this.resolver.dereference(sub.$ref);
329 var normalized = this.normalizeContent(ref).content;
330 utils.mergeSchema(work, normalized);
331 }
332 else {
333 var normalized = this.normalizeSchemaContent(sub);
334 utils.mergeSchema(work, normalized);
335 }
336 }
337 }
338 catch (e_8_1) { e_8 = { error: e_8_1 }; }
339 finally {
340 try {
341 if (allOf_1_1 && !allOf_1_1.done && (_a = allOf_1.return)) _a.call(allOf_1);
342 }
343 finally { if (e_8) throw e_8.error; }
344 }
345 utils.mergeSchema(work, content);
346 content = Object.assign(content, work);
347 }
348 if (content.type === undefined &&
349 (content.properties || content.additionalProperties)) {
350 content.type = 'object';
351 }
352 if (content.nullable) {
353 var type = content.type;
354 var anyOf = content.anyOf;
355 if (Array.isArray(anyOf)) {
356 anyOf.push({ type: 'null' });
357 }
358 else if (type == null) {
359 content.type = 'null';
360 }
361 else if (!Array.isArray(type)) {
362 content.type = [type, 'null'];
363 }
364 else {
365 type.push('null');
366 }
367 }
368 var types = content.type;
369 if (Array.isArray(types)) {
370 var reduced = utils.reduceTypes(types);
371 content.type = reduced.length === 1 ? reduced[0] : reduced;
372 }
373 }
374 return content;
375 };
376 DtsGenerator.prototype.generateDeclareType = function (schema, root) {
377 var content = schema.content;
378 if (content.$ref ||
379 content.oneOf ||
380 content.anyOf ||
381 content.enum ||
382 'const' in content ||
383 content.type !== 'object') {
384 var type = this.generateTypeProperty(schema);
385 return ast.buildTypeAliasNode(schema.id, type, root);
386 }
387 else {
388 var members = this.generateProperties(schema);
389 return ast.buildInterfaceNode(schema.id, members, root);
390 }
391 };
392 DtsGenerator.prototype.generateAnyTypeModel = function (schema, root) {
393 var member = ast.buildIndexSignatureNode('name', ast.buildStringKeyword(), ast.buildAnyKeyword());
394 return ast.buildInterfaceNode(schema.id, [member], root);
395 };
396 DtsGenerator.prototype.generateTypeCollection = function (schema, root) {
397 var type = this.generateArrayTypeProperty(schema);
398 return ast.buildTypeAliasNode(schema.id, type, root);
399 };
400 DtsGenerator.prototype.generateProperties = function (baseSchema) {
401 var e_9, _a, e_10, _b;
402 var result = [];
403 var content = baseSchema.content;
404 if (content.additionalProperties) {
405 var schema = this.normalizeContent(baseSchema, '/additionalProperties');
406 var valueType = content.additionalProperties === true
407 ? ast.buildAnyKeyword()
408 : this.generateTypeProperty(schema);
409 var node = ast.buildIndexSignatureNode('name', ast.buildStringKeyword(), valueType);
410 result.push(ast.addOptionalInformation(node, schema, true));
411 }
412 if (content.properties) {
413 try {
414 for (var _c = tslib_1.__values(Object.keys(content.properties)), _d = _c.next(); !_d.done; _d = _c.next()) {
415 var propertyName = _d.value;
416 var schema = this.normalizeContent(baseSchema, '/properties/' + jsonPointer_1.tilde(propertyName));
417 var node = ast.buildPropertySignature(schema, propertyName, this.generateTypeProperty(schema), baseSchema.content.required, false);
418 result.push(ast.addOptionalInformation(ast.addComment(node, schema, true), schema, true));
419 }
420 }
421 catch (e_9_1) { e_9 = { error: e_9_1 }; }
422 finally {
423 try {
424 if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
425 }
426 finally { if (e_9) throw e_9.error; }
427 }
428 }
429 if (content.patternProperties) {
430 var schemasTypes = [];
431 try {
432 for (var _e = tslib_1.__values(Object.keys(content.patternProperties)), _f = _e.next(); !_f.done; _f = _e.next()) {
433 var propertyName = _f.value;
434 var schema = this.normalizeContent(baseSchema, '/patternProperties/' + jsonPointer_1.tilde(propertyName));
435 schemasTypes.push(this.generateTypeProperty(schema));
436 }
437 }
438 catch (e_10_1) { e_10 = { error: e_10_1 }; }
439 finally {
440 try {
441 if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
442 }
443 finally { if (e_10) throw e_10.error; }
444 }
445 var node = ast.buildPropertySignature({ content: { readOnly: false } }, 'pattern', typescript_1.default.createUnionTypeNode(schemasTypes), baseSchema.content.required, true);
446 result.push(typescript_1.default.addSyntheticTrailingComment(node, typescript_1.default.SyntaxKind.MultiLineCommentTrivia, " Patterns: " + Object.keys(content.patternProperties).join(' | ') + " "));
447 }
448 return result;
449 };
450 DtsGenerator.prototype.generateTypeProperty = function (schema, terminate) {
451 var _this = this;
452 if (terminate === void 0) { terminate = true; }
453 var content = schema.content;
454 if (content.$ref) {
455 var ref = this.resolver.dereference(content.$ref);
456 if (ref.id == null) {
457 throw new Error('target referenced id is nothing: ' + content.$ref);
458 }
459 var refSchema = this.normalizeContent(ref);
460 var node = ast.buildTypeReferenceNode(refSchema, this.currentSchema);
461 return ast.addOptionalInformation(ast.addComment(node, refSchema, false), refSchema, false);
462 }
463 if (content.anyOf) {
464 return this.generateArrayedType(schema, content.anyOf, '/anyOf/', terminate);
465 }
466 if (content.oneOf) {
467 return this.generateArrayedType(schema, content.oneOf, '/oneOf/', terminate);
468 }
469 if (content.enum) {
470 return ast.buildUnionTypeNode(content.enum, function (value) {
471 return _this.generateLiteralTypeNode(content, value);
472 }, terminate);
473 }
474 else if ('const' in content) {
475 return this.generateLiteralTypeNode(content, content.const);
476 }
477 else {
478 return this.generateType(schema, terminate);
479 }
480 };
481 DtsGenerator.prototype.generateLiteralTypeNode = function (content, value) {
482 switch (content.type) {
483 case 'integer':
484 case 'number':
485 return ast.buildNumericLiteralTypeNode('' + value);
486 case 'boolean':
487 return ast.buildBooleanLiteralTypeNode(value);
488 default:
489 return ast.buildStringLiteralTypeNode(value);
490 }
491 };
492 DtsGenerator.prototype.generateArrayedType = function (baseSchema, contents, path, terminate) {
493 var _this = this;
494 return ast.addOptionalInformation(ast.addComment(ast.buildUnionTypeNode(contents, function (_, index) {
495 var schema = _this.normalizeContent(baseSchema, path + index);
496 if (schema.id.isEmpty()) {
497 return ast.addOptionalInformation(_this.generateTypeProperty(schema, false), schema, false);
498 }
499 else {
500 return ast.addOptionalInformation(ast.buildTypeReferenceNode(schema, _this.currentSchema), schema, false);
501 }
502 }, terminate), baseSchema, false), baseSchema, terminate);
503 };
504 DtsGenerator.prototype.generateArrayTypeProperty = function (schema, terminate) {
505 if (terminate === void 0) { terminate = true; }
506 var items = schema.content.items;
507 var minItems = schema.content.minItems;
508 var maxItems = schema.content.maxItems;
509 if (items == null) {
510 return ast.buildSimpleArrayNode(ast.buildAnyKeyword());
511 }
512 else if (!Array.isArray(items)) {
513 var subSchema = this.normalizeContent(schema, '/items');
514 var node = this.generateTypeProperty(subSchema, false);
515 return ast.buildSimpleArrayNode(ast.addOptionalInformation(node, subSchema, false));
516 }
517 else if (items.length === 0 &&
518 minItems === undefined &&
519 maxItems === undefined) {
520 return ast.buildSimpleArrayNode(ast.buildAnyKeyword());
521 }
522 else if (minItems != null &&
523 maxItems != null &&
524 maxItems < minItems) {
525 return ast.buildNeverKeyword();
526 }
527 else {
528 var types = [];
529 for (var i = 0; i < items.length; i++) {
530 var type = this.normalizeContent(schema, '/items/' + i);
531 if (type.id.isEmpty()) {
532 types.push(this.generateTypeProperty(type, false));
533 }
534 else {
535 types.push(ast.addOptionalInformation(ast.buildTypeReferenceNode(type, this.currentSchema), type, false));
536 }
537 }
538 return ast.addOptionalInformation(ast.buildTupleTypeNode(types, minItems, maxItems), schema, terminate);
539 }
540 };
541 DtsGenerator.prototype.generateType = function (schema, terminate) {
542 var _this = this;
543 var type = schema.content.type;
544 if (type == null) {
545 return ast.buildAnyKeyword();
546 }
547 else if (typeof type === 'string') {
548 return this.generateTypeName(schema, type, terminate);
549 }
550 else {
551 var types = utils.reduceTypes(type);
552 if (types.length <= 1) {
553 schema.content.type = types[0];
554 return this.generateType(schema, terminate);
555 }
556 else {
557 return ast.buildUnionTypeNode(types, function (t) {
558 return _this.generateTypeName(schema, t, false);
559 }, terminate);
560 }
561 }
562 };
563 DtsGenerator.prototype.generateTypeName = function (schema, type, terminate) {
564 var tsType = utils.toTSType(type, schema.content);
565 if (tsType) {
566 return ast.buildKeyword(tsType);
567 }
568 else if (type === 'object') {
569 var elements = this.generateProperties(schema);
570 if (elements.length > 0) {
571 return ast.buildTypeLiteralNode(elements);
572 }
573 else {
574 return ast.buildUnknownKeyword();
575 }
576 }
577 else if (type === 'array') {
578 return this.generateArrayTypeProperty(schema, terminate);
579 }
580 else {
581 throw new Error('unknown type: ' + type);
582 }
583 };
584 return DtsGenerator;
585}());
586exports.default = DtsGenerator;
587//# sourceMappingURL=dtsGenerator.js.map
\No newline at end of file