UNPKG

24.6 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 var content = this.normalizeSchemaContent(schema.content);
312 return Object.assign({}, schema, { content: content });
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 = content;
322 try {
323 for (var _b = tslib_1.__values(content.allOf), _c = _b.next(); !_c.done; _c = _b.next()) {
324 var sub = _c.value;
325 if (typeof sub === 'object' && sub.$ref) {
326 var ref = this.resolver.dereference(sub.$ref);
327 var normalized = this.normalizeContent(ref).content;
328 utils.mergeSchema(work, normalized);
329 }
330 else if (typeof sub === 'object') {
331 var normalized = this.normalizeSchemaContent(sub);
332 utils.mergeSchema(work, normalized);
333 }
334 else {
335 utils.mergeSchema(work, sub);
336 }
337 }
338 }
339 catch (e_8_1) { e_8 = { error: e_8_1 }; }
340 finally {
341 try {
342 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
343 }
344 finally { if (e_8) throw e_8.error; }
345 }
346 delete content.allOf;
347 content = work;
348 }
349 if (content.type === undefined && (content.properties || content.additionalProperties)) {
350 content.type = 'object';
351 }
352 if (content.nullable) {
353 var type = content.type;
354 if (type == null) {
355 content.type = 'null';
356 }
357 else if (!Array.isArray(type)) {
358 content.type = [type, 'null'];
359 }
360 else {
361 type.push('null');
362 }
363 }
364 var types = content.type;
365 if (Array.isArray(types)) {
366 var reduced = utils.reduceTypes(types);
367 content.type = reduced.length === 1 ? reduced[0] : reduced;
368 }
369 }
370 return content;
371 };
372 DtsGenerator.prototype.generateDeclareType = function (schema, root) {
373 var content = schema.content;
374 if (content.$ref || content.oneOf || content.anyOf || content.enum || 'const' in content || content.type !== 'object') {
375 var type = this.generateTypeProperty(schema);
376 return ast.buildTypeAliasNode(schema.id, type, root);
377 }
378 else {
379 var members = this.generateProperties(schema);
380 return ast.buildInterfaceNode(schema.id, members, root);
381 }
382 };
383 DtsGenerator.prototype.generateAnyTypeModel = function (schema, root) {
384 var member = ast.buildIndexSignatureNode('name', ast.buildStringKeyword(), ast.buildAnyKeyword());
385 return ast.buildInterfaceNode(schema.id, [member], root);
386 };
387 DtsGenerator.prototype.generateTypeCollection = function (schema, root) {
388 var type = this.generateArrayTypeProperty(schema);
389 return ast.buildTypeAliasNode(schema.id, type, root);
390 };
391 DtsGenerator.prototype.generateProperties = function (baseSchema) {
392 var e_9, _a;
393 var result = [];
394 var content = baseSchema.content;
395 if (content.additionalProperties) {
396 var schema = this.normalizeContent(baseSchema, '/additionalProperties');
397 var valueType = content.additionalProperties === true ? ast.buildAnyKeyword() : this.generateTypeProperty(schema);
398 var node = ast.buildIndexSignatureNode('name', ast.buildStringKeyword(), valueType);
399 result.push(ast.addOptionalInformation(node, schema, true));
400 }
401 if (content.properties) {
402 try {
403 for (var _b = tslib_1.__values(Object.keys(content.properties)), _c = _b.next(); !_c.done; _c = _b.next()) {
404 var propertyName = _c.value;
405 var schema = this.normalizeContent(baseSchema, '/properties/' + jsonPointer_1.tilde(propertyName));
406 var node = ast.buildPropertySignature(schema, propertyName, this.generateTypeProperty(schema), baseSchema.content.required);
407 result.push(ast.addOptionalInformation(ast.addComment(node, schema, true), schema, true));
408 }
409 }
410 catch (e_9_1) { e_9 = { error: e_9_1 }; }
411 finally {
412 try {
413 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
414 }
415 finally { if (e_9) throw e_9.error; }
416 }
417 }
418 return result;
419 };
420 DtsGenerator.prototype.generateTypeProperty = function (schema, terminate) {
421 var _this = this;
422 if (terminate === void 0) { terminate = true; }
423 var content = schema.content;
424 if (content.$ref) {
425 var ref = this.resolver.dereference(content.$ref);
426 if (ref.id == null) {
427 throw new Error('target referenced id is nothing: ' + content.$ref);
428 }
429 var refSchema = this.normalizeContent(ref);
430 var node = ast.buildTypeReferenceNode(refSchema, this.currentSchema);
431 return ast.addOptionalInformation(ast.addComment(node, refSchema, false), refSchema, false);
432 }
433 if (content.anyOf) {
434 return this.generateArrayedType(schema, content.anyOf, '/anyOf/', terminate);
435 }
436 if (content.oneOf) {
437 return this.generateArrayedType(schema, content.oneOf, '/oneOf/', terminate);
438 }
439 if (content.enum) {
440 return ast.buildUnionTypeNode(content.enum, function (value) {
441 return _this.generateLiteralTypeNode(content, value);
442 }, terminate);
443 }
444 else if ('const' in content) {
445 return this.generateLiteralTypeNode(content, content.const);
446 }
447 else {
448 return this.generateType(schema, terminate);
449 }
450 };
451 DtsGenerator.prototype.generateLiteralTypeNode = function (content, value) {
452 switch (content.type) {
453 case 'integer':
454 case 'number':
455 return ast.buildNumericLiteralTypeNode('' + value);
456 case 'boolean':
457 return ast.buildBooleanLiteralTypeNode(value);
458 default:
459 return ast.buildStringLiteralTypeNode(value);
460 }
461 };
462 DtsGenerator.prototype.generateArrayedType = function (baseSchema, contents, path, terminate) {
463 var _this = this;
464 return ast.addOptionalInformation(ast.addComment(ast.buildUnionTypeNode(contents, function (_, index) {
465 var schema = _this.normalizeContent(baseSchema, path + index);
466 if (schema.id.isEmpty()) {
467 return ast.addOptionalInformation(_this.generateTypeProperty(schema, false), schema, false);
468 }
469 else {
470 return ast.addOptionalInformation(ast.buildTypeReferenceNode(schema, _this.currentSchema), schema, false);
471 }
472 }, terminate), baseSchema, false), baseSchema, terminate);
473 };
474 DtsGenerator.prototype.generateArrayTypeProperty = function (schema, terminate) {
475 if (terminate === void 0) { terminate = true; }
476 var items = schema.content.items;
477 var minItems = schema.content.minItems;
478 var maxItems = schema.content.maxItems;
479 if (items == null) {
480 return ast.buildSimpleArrayNode(ast.buildAnyKeyword());
481 }
482 else if (!Array.isArray(items)) {
483 var subSchema = this.normalizeContent(schema, '/items');
484 var node = this.generateTypeProperty(subSchema, false);
485 return ast.buildSimpleArrayNode(ast.addOptionalInformation(node, subSchema, false));
486 }
487 else if (items.length === 0 && minItems === undefined && maxItems === undefined) {
488 return ast.buildSimpleArrayNode(ast.buildAnyKeyword());
489 }
490 else if (minItems != null && maxItems != null && maxItems < minItems) {
491 return ast.buildNeverKeyword();
492 }
493 else {
494 var types = [];
495 for (var i = 0; i < items.length; i++) {
496 var type = this.normalizeContent(schema, '/items/' + i);
497 if (type.id.isEmpty()) {
498 types.push(this.generateTypeProperty(type, false));
499 }
500 else {
501 types.push(ast.addOptionalInformation(ast.buildTypeReferenceNode(type, this.currentSchema), type, false));
502 }
503 }
504 return ast.addOptionalInformation(ast.buildTupleTypeNode(types, minItems, maxItems), schema, terminate);
505 }
506 };
507 DtsGenerator.prototype.generateType = function (schema, terminate) {
508 var _this = this;
509 var type = schema.content.type;
510 if (type == null) {
511 return ast.buildAnyKeyword();
512 }
513 else if (typeof type === 'string') {
514 return this.generateTypeName(schema, type, terminate);
515 }
516 else {
517 var types = utils.reduceTypes(type);
518 if (types.length <= 1) {
519 schema.content.type = types[0];
520 return this.generateType(schema, terminate);
521 }
522 else {
523 return ast.buildUnionTypeNode(types, function (t) {
524 return _this.generateTypeName(schema, t, false);
525 }, terminate);
526 }
527 }
528 };
529 DtsGenerator.prototype.generateTypeName = function (schema, type, terminate) {
530 var tsType = utils.toTSType(type, schema.content);
531 if (tsType) {
532 return ast.buildKeyword(tsType);
533 }
534 else if (type === 'object') {
535 return ast.buildTypeLiteralNode(this.generateProperties(schema));
536 }
537 else if (type === 'array') {
538 return this.generateArrayTypeProperty(schema, terminate);
539 }
540 else {
541 throw new Error('unknown type: ' + type);
542 }
543 };
544 return DtsGenerator;
545}());
546exports.default = DtsGenerator;
547//# sourceMappingURL=dtsGenerator.js.map
\No newline at end of file