UNPKG

13.5 kBJavaScriptView Raw
1"use strict";
2var __spreadArrays = (this && this.__spreadArrays) || function () {
3 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
4 for (var r = Array(s), k = 0, i = 0; i < il; i++)
5 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
6 r[k] = a[j];
7 return r;
8};
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.generate = void 0;
11var lodash_1 = require("lodash");
12var index_1 = require("./index");
13var AST_1 = require("./types/AST");
14var utils_1 = require("./utils");
15function generate(ast, options) {
16 if (options === void 0) { options = index_1.DEFAULT_OPTIONS; }
17 return ([
18 options.bannerComment,
19 declareNamedTypes(ast, options, ast.standaloneName),
20 declareNamedInterfaces(ast, options, ast.standaloneName),
21 declareEnums(ast, options)
22 ]
23 .filter(Boolean)
24 .join('\n\n') + '\n'); // trailing newline
25}
26exports.generate = generate;
27function declareEnums(ast, options, processed) {
28 if (processed === void 0) { processed = new Set(); }
29 if (processed.has(ast)) {
30 return '';
31 }
32 processed.add(ast);
33 var type = '';
34 switch (ast.type) {
35 case 'ENUM':
36 return generateStandaloneEnum(ast, options) + '\n';
37 case 'ARRAY':
38 return declareEnums(ast.params, options, processed);
39 case 'UNION':
40 case 'INTERSECTION':
41 return ast.params.reduce(function (prev, ast) { return prev + declareEnums(ast, options, processed); }, '');
42 case 'TUPLE':
43 type = ast.params.reduce(function (prev, ast) { return prev + declareEnums(ast, options, processed); }, '');
44 if (ast.spreadParam) {
45 type += declareEnums(ast.spreadParam, options, processed);
46 }
47 return type;
48 case 'INTERFACE':
49 return getSuperTypesAndParams(ast).reduce(function (prev, ast) { return prev + declareEnums(ast, options, processed); }, '');
50 default:
51 return '';
52 }
53}
54function declareNamedInterfaces(ast, options, rootASTName, processed) {
55 if (processed === void 0) { processed = new Set(); }
56 if (processed.has(ast)) {
57 return '';
58 }
59 processed.add(ast);
60 var type = '';
61 switch (ast.type) {
62 case 'ARRAY':
63 type = declareNamedInterfaces(ast.params, options, rootASTName, processed);
64 break;
65 case 'INTERFACE':
66 type = [
67 AST_1.hasStandaloneName(ast) &&
68 (ast.standaloneName === rootASTName || options.declareExternallyReferenced) &&
69 generateStandaloneInterface(ast, options),
70 getSuperTypesAndParams(ast)
71 .map(function (ast) { return declareNamedInterfaces(ast, options, rootASTName, processed); })
72 .filter(Boolean)
73 .join('\n')
74 ]
75 .filter(Boolean)
76 .join('\n');
77 break;
78 case 'INTERSECTION':
79 case 'TUPLE':
80 case 'UNION':
81 type = ast.params
82 .map(function (_) { return declareNamedInterfaces(_, options, rootASTName, processed); })
83 .filter(Boolean)
84 .join('\n');
85 if (ast.type === 'TUPLE' && ast.spreadParam) {
86 type += declareNamedInterfaces(ast.spreadParam, options, rootASTName, processed);
87 }
88 break;
89 default:
90 type = '';
91 }
92 return type;
93}
94function declareNamedTypes(ast, options, rootASTName, processed) {
95 if (processed === void 0) { processed = new Set(); }
96 if (processed.has(ast)) {
97 return '';
98 }
99 processed.add(ast);
100 var type = '';
101 switch (ast.type) {
102 case 'ARRAY':
103 type = [
104 declareNamedTypes(ast.params, options, rootASTName, processed),
105 AST_1.hasStandaloneName(ast) ? generateStandaloneType(ast, options) : undefined
106 ]
107 .filter(Boolean)
108 .join('\n');
109 break;
110 case 'ENUM':
111 type = '';
112 break;
113 case 'INTERFACE':
114 type = getSuperTypesAndParams(ast)
115 .map(function (ast) {
116 return (ast.standaloneName === rootASTName || options.declareExternallyReferenced) &&
117 declareNamedTypes(ast, options, rootASTName, processed);
118 })
119 .filter(Boolean)
120 .join('\n');
121 break;
122 case 'INTERSECTION':
123 case 'TUPLE':
124 case 'UNION':
125 type = [
126 AST_1.hasStandaloneName(ast) ? generateStandaloneType(ast, options) : undefined,
127 ast.params
128 .map(function (ast) { return declareNamedTypes(ast, options, rootASTName, processed); })
129 .filter(Boolean)
130 .join('\n'),
131 'spreadParam' in ast && ast.spreadParam
132 ? declareNamedTypes(ast.spreadParam, options, rootASTName, processed)
133 : undefined
134 ]
135 .filter(Boolean)
136 .join('\n');
137 break;
138 default:
139 if (AST_1.hasStandaloneName(ast)) {
140 type = generateStandaloneType(ast, options);
141 }
142 }
143 return type;
144}
145function generateType(ast, options) {
146 var type = generateRawType(ast, options);
147 if (options.strictIndexSignatures && ast.keyName === '[k: string]') {
148 return type + " | undefined";
149 }
150 return type;
151}
152function generateRawType(ast, options) {
153 utils_1.log('magenta', 'generator', ast);
154 if (AST_1.hasStandaloneName(ast)) {
155 return utils_1.toSafeString(ast.standaloneName);
156 }
157 switch (ast.type) {
158 case 'ANY':
159 return 'any';
160 case 'ARRAY':
161 return (function () {
162 var type = generateType(ast.params, options);
163 return type.endsWith('"') ? '(' + type + ')[]' : type + '[]';
164 })();
165 case 'BOOLEAN':
166 return 'boolean';
167 case 'INTERFACE':
168 return generateInterface(ast, options);
169 case 'INTERSECTION':
170 return generateSetOperation(ast, options);
171 case 'LITERAL':
172 return JSON.stringify(ast.params);
173 case 'NUMBER':
174 return 'number';
175 case 'NULL':
176 return 'null';
177 case 'OBJECT':
178 return 'object';
179 case 'REFERENCE':
180 return ast.params;
181 case 'STRING':
182 return 'string';
183 case 'TUPLE':
184 return (function () {
185 var minItems = ast.minItems;
186 var maxItems = ast.maxItems || -1;
187 var spreadParam = ast.spreadParam;
188 var astParams = __spreadArrays(ast.params);
189 if (minItems > 0 && minItems > astParams.length && ast.spreadParam === undefined) {
190 // this is a valid state, and JSONSchema doesn't care about the item type
191 if (maxItems < 0) {
192 // no max items and no spread param, so just spread any
193 spreadParam = options.unknownAny ? AST_1.T_UNKNOWN : AST_1.T_ANY;
194 }
195 }
196 if (maxItems > astParams.length && ast.spreadParam === undefined) {
197 // this is a valid state, and JSONSchema doesn't care about the item type
198 // fill the tuple with any elements
199 for (var i = astParams.length; i < maxItems; i += 1) {
200 astParams.push(options.unknownAny ? AST_1.T_UNKNOWN : AST_1.T_ANY);
201 }
202 }
203 function addSpreadParam(params) {
204 if (spreadParam) {
205 var spread = '...(' + generateType(spreadParam, options) + ')[]';
206 params.push(spread);
207 }
208 return params;
209 }
210 function paramsToString(params) {
211 return '[' + params.join(', ') + ']';
212 }
213 var paramsList = astParams.map(function (param) { return generateType(param, options); });
214 if (paramsList.length > minItems) {
215 /*
216 if there are more items than the min, we return a union of tuples instead of
217 using the optional element operator. This is done because it is more typesafe.
218
219 // optional element operator
220 type A = [string, string?, string?]
221 const a: A = ['a', undefined, 'c'] // no error
222
223 // union of tuples
224 type B = [string] | [string, string] | [string, string, string]
225 const b: B = ['a', undefined, 'c'] // TS error
226 */
227 var cumulativeParamsList = paramsList.slice(0, minItems);
228 var typesToUnion = [];
229 if (cumulativeParamsList.length > 0) {
230 // actually has minItems, so add the initial state
231 typesToUnion.push(paramsToString(cumulativeParamsList));
232 }
233 else {
234 // no minItems means it's acceptable to have an empty tuple type
235 typesToUnion.push(paramsToString([]));
236 }
237 for (var i = minItems; i < paramsList.length; i += 1) {
238 cumulativeParamsList.push(paramsList[i]);
239 if (i === paramsList.length - 1) {
240 // only the last item in the union should have the spread parameter
241 addSpreadParam(cumulativeParamsList);
242 }
243 typesToUnion.push(paramsToString(cumulativeParamsList));
244 }
245 return typesToUnion.join('|');
246 }
247 // no max items so only need to return one type
248 return paramsToString(addSpreadParam(paramsList));
249 })();
250 case 'UNION':
251 return generateSetOperation(ast, options);
252 case 'UNKNOWN':
253 return 'unknown';
254 case 'CUSTOM_TYPE':
255 return ast.params;
256 }
257}
258/**
259 * Generate a Union or Intersection
260 */
261function generateSetOperation(ast, options) {
262 var members = ast.params.map(function (_) { return generateType(_, options); });
263 var separator = ast.type === 'UNION' ? '|' : '&';
264 return members.length === 1 ? members[0] : '(' + members.join(' ' + separator + ' ') + ')';
265}
266function generateInterface(ast, options) {
267 return ("{" +
268 '\n' +
269 ast.params
270 .filter(function (_) { return !_.isPatternProperty && !_.isUnreachableDefinition; })
271 .map(function (_a) {
272 var isRequired = _a.isRequired, keyName = _a.keyName, ast = _a.ast;
273 return [isRequired, keyName, ast, generateType(ast, options)];
274 })
275 .map(function (_a) {
276 var isRequired = _a[0], keyName = _a[1], ast = _a[2], type = _a[3];
277 return (AST_1.hasComment(ast) && !ast.standaloneName ? generateComment(ast.comment) + '\n' : '') +
278 escapeKeyName(keyName) +
279 (isRequired ? '' : '?') +
280 ': ' +
281 (AST_1.hasStandaloneName(ast) ? utils_1.toSafeString(type) : type);
282 })
283 .join('\n') +
284 '\n' +
285 '}');
286}
287function generateComment(comment) {
288 return __spreadArrays(['/**'], comment.split('\n').map(function (_) { return ' * ' + _; }), [' */']).join('\n');
289}
290function generateStandaloneEnum(ast, options) {
291 return ((AST_1.hasComment(ast) ? generateComment(ast.comment) + '\n' : '') +
292 'export ' +
293 (options.enableConstEnums ? 'const ' : '') +
294 ("enum " + utils_1.toSafeString(ast.standaloneName) + " {") +
295 '\n' +
296 ast.params.map(function (_a) {
297 var ast = _a.ast, keyName = _a.keyName;
298 return keyName + ' = ' + generateType(ast, options);
299 }).join(',\n') +
300 '\n' +
301 '}');
302}
303function generateStandaloneInterface(ast, options) {
304 return ((AST_1.hasComment(ast) ? generateComment(ast.comment) + '\n' : '') +
305 ("export interface " + utils_1.toSafeString(ast.standaloneName) + " ") +
306 (ast.superTypes.length > 0
307 ? "extends " + ast.superTypes.map(function (superType) { return utils_1.toSafeString(superType.standaloneName); }).join(', ') + " "
308 : '') +
309 generateInterface(ast, options));
310}
311function generateStandaloneType(ast, options) {
312 return ((AST_1.hasComment(ast) ? generateComment(ast.comment) + '\n' : '') +
313 ("export type " + utils_1.toSafeString(ast.standaloneName) + " = " + generateType(lodash_1.omit(ast, 'standaloneName') /* TODO */, options)));
314}
315function escapeKeyName(keyName) {
316 if (keyName.length && /[A-Za-z_$]/.test(keyName.charAt(0)) && /^[\w$]+$/.test(keyName)) {
317 return keyName;
318 }
319 if (keyName === '[k: string]') {
320 return keyName;
321 }
322 return JSON.stringify(keyName);
323}
324function getSuperTypesAndParams(ast) {
325 return ast.params.map(function (param) { return param.ast; }).concat(ast.superTypes);
326}
327//# sourceMappingURL=generator.js.map
\No newline at end of file