-
Notifications
You must be signed in to change notification settings - Fork 4
/
converter.js
110 lines (96 loc) · 2.72 KB
/
converter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
'use strict';
class Converter {
constructor(options) {
this.options = options;
}
createType(schema) {
const docs = schema.description ? this.toJSDoc(schema.description) : '';
const name = this.toTypeName(schema.id);
const type = this.getType(schema);
return `${docs}type ${name} = ${type}`;
}
extend(type, types) {
if (!Array.isArray(types)) {
types = [types];
}
const refs = types.map(type => this.toTypeName(type));
return [type, ...refs].join('&');
}
getType(schema) {
let {repeated, ...schemaCopy} = schema;
if (repeated) {
return `Array<${this.getType(schemaCopy)}>`;
}
if (schema.$ref) {
return this.toTypeName(schema.$ref);
}
if (schema.enum) {
return this.toLiteralUnion(schema.enum);
}
if (schema.type === 'integer') {
return 'number';
}
if (schema.type === 'array') {
return this.toArray(schema.items, schema.additionalItems);
}
if (schema.type !== 'object') {
return schema.type;
}
const type = this.toObject(schema.properties, schema.additionalProperties);
return schema.extends ? this.extend(type, schema.extends) : type;
}
toArray(schema, additional = false) {
if (Array.isArray(schema)) {
return this.toTuple(schema, additional);
}
const types = [this.getType(schema)];
if (additional) {
types.push('any');
}
return `Array<${this.toUnion(types)}>`;
}
toLiteralUnion(values) {
const types = values.map(v => (typeof v === 'string' ? `'${v}'` : v));
return this.toUnion(types);
}
toJSDoc(str) {
const docs = str
.split('\n')
.join('\n * ')
.replace(/\*\//g, '*\\/');
return `\n/**\n * ${docs}\n */\n`;
}
toObject(props = {}, additional = false) {
const fields = [];
Object.keys(props)
.sort()
.forEach(name => {
const prop = props[name];
const docs = prop.description ? this.toJSDoc(prop.description) : '';
const prefix = prop.readonly ? 'readonly ' : '';
const suffix = prop.required ? '' : '?';
const key = `${prefix}${name}${suffix}`;
const value = this.getType(prop);
fields.push(`${docs}${key}: ${value}`);
});
if (additional) {
if (additional === true) additional = {type: 'any'};
fields.push(`[key: string]: ${this.getType(additional)}`);
}
return `{${fields.join(';')}}`;
}
toTuple(schemas, additional = false) {
const types = schemas.map(schema => this.getType(schema));
if (additional) {
types.push('...any[]');
}
return `[${types.join(', ')}]`;
}
toTypeName(ref) {
return `I${ref}`;
}
toUnion(types) {
return types.join('|');
}
}
module.exports = Converter;