runtime-type-inspector 2.0.2 → 2.0.3
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/build/rti-transpiler.cjs +2359 -0
- package/build/rti-transpiler.mjs +1979 -0
- package/package.json +4 -2
- package/.eslintrc.js +0 -480
- package/jsconfig.json +0 -10
- package/plugin-parcel/index.mjs +0 -4
- package/plugin-rollup/index.mjs +0 -78
- package/plugin-webpack/index.mjs +0 -4
- package/rollup.config.mjs +0 -183
- package/src-runtime/assertType.mjs +0 -54
- package/src-runtime/createDiv.mjs +0 -69
- package/src-runtime/index.mjs +0 -21
- package/src-runtime/makeJSDoc.mjs +0 -40
- package/src-runtime/registerClass.mjs +0 -11
- package/src-runtime/registerTypedef.mjs +0 -12
- package/src-runtime/typecheckDiv.mjs +0 -3
- package/src-runtime/typecheckEvery.mjs +0 -21
- package/src-runtime/typecheckOptions.mjs +0 -60
- package/src-runtime/typecheckTable.mjs +0 -14
- package/src-runtime/typecheckWarn.mjs +0 -23
- package/src-runtime/validateArray.mjs +0 -26
- package/src-runtime/validateDivision.mjs +0 -31
- package/src-runtime/validateMap.mjs +0 -37
- package/src-runtime/validateNumber.mjs +0 -29
- package/src-runtime/validateObject.mjs +0 -43
- package/src-runtime/validateRecord.mjs +0 -31
- package/src-runtime/validateSet.mjs +0 -26
- package/src-runtime/validateTuple.mjs +0 -28
- package/src-runtime/validateType.mjs +0 -214
- package/src-runtime/validateTypedef.mjs +0 -18
- package/src-runtime/validateUnion.mjs +0 -19
- package/src-runtime/youCanAddABreakpointHere.mjs +0 -11
- package/src-transpiler/Stringifier.mjs +0 -1275
- package/src-transpiler/StringifierWithTypeAssertions.mjs +0 -478
- package/src-transpiler/addTypeChecks.mjs +0 -20
- package/src-transpiler/ast2json.mjs +0 -13
- package/src-transpiler/ast2jsonForComparison.mjs +0 -28
- package/src-transpiler/code2ast2code.mjs +0 -16
- package/src-transpiler/expandType.mjs +0 -187
- package/src-transpiler/expandTypeDepFree.mjs +0 -122
- package/src-transpiler/extractNameAndOptionality.mjs +0 -23
- package/src-transpiler/index.mjs +0 -13
- package/src-transpiler/parseJSDoc.mjs +0 -69
- package/src-transpiler/parseJSDocSetter.mjs +0 -16
- package/src-transpiler/parseJSDocTypedef.mjs +0 -69
- package/src-transpiler/simplifyType.mjs +0 -31
- package/src-transpiler/stat.mjs +0 -13
- package/ui/babel-core.mjs +0 -5
- package/ui/babel-helper-plugin-utils.mjs +0 -7
- package/ui/babel-parser.mjs +0 -8
- package/ui/babel-plugin-syntax-typescript.mjs +0 -58
- package/ui/importmap.js +0 -38
- package/ui/index.html +0 -30
- package/ui/index.mjs +0 -379
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
import {expandTypeDepFree} from './expandTypeDepFree.mjs';
|
|
2
|
-
import {parseJSDoc } from './parseJSDoc.mjs';
|
|
3
|
-
import {parseJSDocSetter } from './parseJSDocSetter.mjs';
|
|
4
|
-
import {parseJSDocTypedef} from './parseJSDocTypedef.mjs';
|
|
5
|
-
import {statReset } from './stat.mjs';
|
|
6
|
-
import {Stringifier } from './Stringifier.mjs';
|
|
7
|
-
/** @typedef {import('@babel/types').Node} Node */
|
|
8
|
-
/** @typedef {import('./stat.mjs').Stat} Stat */
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {object} Options
|
|
11
|
-
* @property {boolean} [forceCurly]
|
|
12
|
-
* @property {boolean} [validateDivision]
|
|
13
|
-
* @property {Function} [expandType]
|
|
14
|
-
* @property {string} [filename]
|
|
15
|
-
*/
|
|
16
|
-
class StringifierWithTypeAssertions extends Stringifier {
|
|
17
|
-
/**
|
|
18
|
-
* @param {Options} [options]
|
|
19
|
-
*/
|
|
20
|
-
constructor({
|
|
21
|
-
forceCurly = true,
|
|
22
|
-
validateDivision = true,
|
|
23
|
-
expandType = expandTypeDepFree,
|
|
24
|
-
filename
|
|
25
|
-
} = {}) {
|
|
26
|
-
super();
|
|
27
|
-
this.forceCurly = forceCurly;
|
|
28
|
-
this.validateDivision = validateDivision;
|
|
29
|
-
// @todo collect every type + manually validate as test set
|
|
30
|
-
// + implement expandType using Babel Flow type parser aswell
|
|
31
|
-
this.expandType = expandType;
|
|
32
|
-
this.filename = filename;
|
|
33
|
-
}
|
|
34
|
-
/** @type {Record<string, Stat>} */
|
|
35
|
-
stats = {
|
|
36
|
-
'FunctionDeclaration' : {checked: 0, unchecked: 0},
|
|
37
|
-
'FunctionExpression' : {checked: 0, unchecked: 0},
|
|
38
|
-
'ArrowFunctionExpression': {checked: 0, unchecked: 0},
|
|
39
|
-
'ClassMethod#constructor': {checked: 0, unchecked: 0},
|
|
40
|
-
'ClassMethod#method' : {checked: 0, unchecked: 0},
|
|
41
|
-
'ClassMethod#set' : {checked: 0, unchecked: 0},
|
|
42
|
-
'ClassMethod#get' : {checked: 0, unchecked: 0},
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* We expand type-asserted ArrowFunctionExpressions in order to add type assertions.
|
|
46
|
-
* @override
|
|
47
|
-
* @param {import("@babel/types").ArrowFunctionExpression} node - The Babel AST node.
|
|
48
|
-
* @returns {string} Stringification of the node.
|
|
49
|
-
*/
|
|
50
|
-
ArrowFunctionExpression(node) {
|
|
51
|
-
const {async, body, generator, params/*, extra*/} = node;
|
|
52
|
-
let out = '';
|
|
53
|
-
if (async) {
|
|
54
|
-
out += 'async ';
|
|
55
|
-
}
|
|
56
|
-
if (generator) {
|
|
57
|
-
out += ' * ';
|
|
58
|
-
}
|
|
59
|
-
out += this.FunctionDeclarationParams(params);
|
|
60
|
-
out += ' =>';
|
|
61
|
-
if (body.type === 'BlockStatement') {
|
|
62
|
-
out += this.toSource(body);
|
|
63
|
-
} else {
|
|
64
|
-
out += ' {\n';
|
|
65
|
-
out += this.generateTypeChecks(node);
|
|
66
|
-
out += this.spaces + 'return ' + this.toSource(body) + ';\n';
|
|
67
|
-
out += '}';
|
|
68
|
-
}
|
|
69
|
-
return out;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* @override
|
|
73
|
-
* @param {import("@babel/types").ClassDeclaration} node - The Babel AST node.
|
|
74
|
-
* @returns {string} Stringification of the node.
|
|
75
|
-
*/
|
|
76
|
-
ClassDeclaration(node) {
|
|
77
|
-
const {id} = node;
|
|
78
|
-
const id_ = this.toSource(id);
|
|
79
|
-
let out = super.ClassDeclaration(node);
|
|
80
|
-
out += `${this.spaces}registerClass(${id_});`;
|
|
81
|
-
return out;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* @param {Node} node
|
|
85
|
-
* @param {string} type
|
|
86
|
-
* @returns {Node|undefined}
|
|
87
|
-
*/
|
|
88
|
-
findParentOfType(node, type) {
|
|
89
|
-
const currentIndex = this.parents.findLastIndex(_ => _ == node);
|
|
90
|
-
return this.parents.findLast((_, i) => {
|
|
91
|
-
if (i > currentIndex) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
return _.type === type;
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* @param {Node} node - Start searching above this node.
|
|
99
|
-
* @param {string} type - Type we are searching for.
|
|
100
|
-
* @param {Function} predicate - Stop searching when this returns true.
|
|
101
|
-
* @returns {Node|undefined}
|
|
102
|
-
*/
|
|
103
|
-
findParentOfTypeWithPredicate(node, type, predicate) {
|
|
104
|
-
const {parents} = this;
|
|
105
|
-
let i = parents.findLastIndex(_ => _ == node);
|
|
106
|
-
i--; // not interested in our start node
|
|
107
|
-
while (i >= 0) {
|
|
108
|
-
const parent = parents[i];
|
|
109
|
-
if (predicate(parent)) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (parent.type === type) {
|
|
113
|
-
return parent;
|
|
114
|
-
}
|
|
115
|
-
i--;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
*
|
|
120
|
-
* @param {...any} args
|
|
121
|
-
*/
|
|
122
|
-
warn(...args) {
|
|
123
|
-
if (this.filename) {
|
|
124
|
-
console.warn("[WARN]", this.filename);
|
|
125
|
-
}
|
|
126
|
-
console.warn(...args);
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* @param {Node} node - The Babel AST node.
|
|
130
|
-
* @returns {undefined | {}}
|
|
131
|
-
*/
|
|
132
|
-
getJSDoc(node) {
|
|
133
|
-
if (node.type === 'BlockStatement') {
|
|
134
|
-
node = this.parent;
|
|
135
|
-
}
|
|
136
|
-
// Receive the leadingComments from the ExpressionStatement, not the FunctionExpression itself.
|
|
137
|
-
if (node.type === 'FunctionExpression') {
|
|
138
|
-
if (node.leadingComments) {
|
|
139
|
-
this.warn("Case of FunctionExpression containing its own leadingComments is not handled");
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
node = this.findParentOfType(node, 'ExpressionStatement');
|
|
143
|
-
if (!node) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
let {leadingComments} = node;
|
|
148
|
-
// Receive the leadingComments from ExportNamedDeclaration, if FunctionDeclaration has none
|
|
149
|
-
if (!leadingComments) {
|
|
150
|
-
if (node.type === 'FunctionDeclaration') {
|
|
151
|
-
const exportNamedDeclaration = this.findParentOfType(node, 'ExportNamedDeclaration');
|
|
152
|
-
leadingComments = exportNamedDeclaration?.leadingComments;
|
|
153
|
-
}
|
|
154
|
-
if (node.type === 'ArrowFunctionExpression') {
|
|
155
|
-
let tmp = this.findParentOfType(node, 'VariableDeclaration');
|
|
156
|
-
if (!tmp?.leadingComments) {
|
|
157
|
-
function isFunc(node) {
|
|
158
|
-
// console.log("isFunc", node.type);
|
|
159
|
-
return (
|
|
160
|
-
node.type === 'ArrowFunctionExpression' ||
|
|
161
|
-
node.type === 'FunctionDeclaration'
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
tmp = this.findParentOfTypeWithPredicate(node, 'ExportNamedDeclaration', isFunc);
|
|
165
|
-
}
|
|
166
|
-
leadingComments = tmp?.leadingComments;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (leadingComments && leadingComments.length) {
|
|
170
|
-
const lastComment = leadingComments[leadingComments.length - 1];
|
|
171
|
-
if (lastComment.type == "CommentBlock") {
|
|
172
|
-
if (lastComment.value.includes('@event')) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (node.type === 'ClassMethod' && node.kind === 'set') {
|
|
176
|
-
const paramName = this.getNameOfParam(node.params[0]);
|
|
177
|
-
if (node.params.length !== 1) {
|
|
178
|
-
this.warn("getJSDoc> setters require exactly one argument");
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
[paramName]: parseJSDocSetter(lastComment.value, this.expandType)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
return parseJSDoc(lastComment.value, this.expandType);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* @param {Node} param - The Babel AST node.
|
|
190
|
-
* @returns {string}
|
|
191
|
-
*/
|
|
192
|
-
getNameOfParam(param) {
|
|
193
|
-
if (param.type === 'Identifier') {
|
|
194
|
-
return param.name;
|
|
195
|
-
} else if (param.type === 'AssignmentPattern') {
|
|
196
|
-
if (param.left.type === 'Identifier') {
|
|
197
|
-
return param.left.name;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
debugger;
|
|
201
|
-
this.warn("unable to extra name from param in specified way - may contain too much information");
|
|
202
|
-
return this.toSource(param);
|
|
203
|
-
}
|
|
204
|
-
statsReset() {
|
|
205
|
-
Object.values(this.stats).forEach(statReset);
|
|
206
|
-
}
|
|
207
|
-
statsPrint() {
|
|
208
|
-
console.table(this.stats);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* @param {Node} node - The Babel AST node.
|
|
212
|
-
* @returns {Stat}
|
|
213
|
-
*/
|
|
214
|
-
getStatsForNode(node) {
|
|
215
|
-
const {parentType, stats} = this;
|
|
216
|
-
if (parentType == 'ClassMethod') {
|
|
217
|
-
const kind = this.parent.kind;
|
|
218
|
-
return stats[`ClassMethod#${kind}`];
|
|
219
|
-
} else if (node.type === 'ArrowFunctionExpression') {
|
|
220
|
-
return stats.ArrowFunctionExpression;
|
|
221
|
-
}
|
|
222
|
-
const stat = stats[parentType];
|
|
223
|
-
if (!stat) {
|
|
224
|
-
this.warn("getStatsForNode> dummy, but unhandled... fix for node type", node);
|
|
225
|
-
return {checked: 0, unchecked: 0};
|
|
226
|
-
}
|
|
227
|
-
return stat;
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* @param {Node} node - The Babel AST node.
|
|
231
|
-
* @param {string} name
|
|
232
|
-
* @returns {boolean}
|
|
233
|
-
*/
|
|
234
|
-
nodeHasParamName(node, name) {
|
|
235
|
-
if (node.type === 'BlockStatement') {
|
|
236
|
-
node = this.parent;
|
|
237
|
-
}
|
|
238
|
-
const {params} = node;
|
|
239
|
-
if (!params) {
|
|
240
|
-
this.warn("nodeHasParamName> Expected params for", {node, name});
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
return params.some(node => {
|
|
244
|
-
const {type} = node;
|
|
245
|
-
if (type === "AssignmentPattern") {
|
|
246
|
-
const {left} = node;
|
|
247
|
-
console.assert(
|
|
248
|
-
left.type === 'Identifier' ||
|
|
249
|
-
left.type === 'ObjectPattern' ||
|
|
250
|
-
left.type === 'ArrayPattern' ||
|
|
251
|
-
left.type === 'AssignmentPattern',
|
|
252
|
-
'Expected Identifier or ObjectPattern'
|
|
253
|
-
);
|
|
254
|
-
return left.name === name;
|
|
255
|
-
} else if (type === 'Identifier') {
|
|
256
|
-
return node.name === name;
|
|
257
|
-
} else if (type === 'ArrayPattern' || type === 'ObjectPattern' || type === 'RestElement') {
|
|
258
|
-
return false;
|
|
259
|
-
} else {
|
|
260
|
-
const _ = new Stringifier();
|
|
261
|
-
const code = _.toSource(node);
|
|
262
|
-
console.log("Unknown type to test params for", type, code);
|
|
263
|
-
}
|
|
264
|
-
return false;
|
|
265
|
-
})
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* @override
|
|
269
|
-
* @param {Node} node - The Babel AST node.
|
|
270
|
-
* @returns {string}
|
|
271
|
-
*/
|
|
272
|
-
generateTypeChecks(node) {
|
|
273
|
-
const {parentType} = this;
|
|
274
|
-
if (
|
|
275
|
-
node.type === 'BlockStatement' &&
|
|
276
|
-
parentType != 'FunctionDeclaration' &&
|
|
277
|
-
parentType != 'ClassMethod' &&
|
|
278
|
-
parentType != 'FunctionExpression'
|
|
279
|
-
) {
|
|
280
|
-
return '';
|
|
281
|
-
}
|
|
282
|
-
const jsdoc = this.getJSDoc(node);
|
|
283
|
-
// return '// ' + JSON.stringify(jsdoc) + '\n';
|
|
284
|
-
const stat = this.getStatsForNode(node);
|
|
285
|
-
if (!jsdoc) {
|
|
286
|
-
stat.unchecked++;
|
|
287
|
-
return '';
|
|
288
|
-
}
|
|
289
|
-
stat.checked++;
|
|
290
|
-
let spaces = this.spaces;
|
|
291
|
-
if (node.type !== 'ArrowFunctionExpression') {
|
|
292
|
-
spaces += ' ';
|
|
293
|
-
}
|
|
294
|
-
let out = '';
|
|
295
|
-
//out += `${spaces}/*${spaces} node.type=${node.type}\n${spaces}
|
|
296
|
-
// ${JSON.stringify(jsdoc)}\n${parent}\n${spaces}*/\n`;
|
|
297
|
-
for (let name in jsdoc) {
|
|
298
|
-
const type = jsdoc[name];
|
|
299
|
-
const hasParam = this.nodeHasParamName(node, name);
|
|
300
|
-
if (!hasParam) {
|
|
301
|
-
let testNode = node;
|
|
302
|
-
if (node.type === 'BlockStatement') {
|
|
303
|
-
testNode = this.parent;
|
|
304
|
-
}
|
|
305
|
-
const paramIndex = Object.keys(jsdoc).findIndex(_ => _ === name);
|
|
306
|
-
const param = testNode.params[paramIndex];
|
|
307
|
-
if (param) {
|
|
308
|
-
const isObjectPattern = param.type === 'ObjectPattern';
|
|
309
|
-
const isArrayPattern = param.type === 'ArrayPattern';
|
|
310
|
-
const isSupportedPattern = isObjectPattern || isArrayPattern;
|
|
311
|
-
// There are four kinds of patterns:
|
|
312
|
-
// ObjectPattern:
|
|
313
|
-
// function test({x = 123}) {return x;} test({x: 456});
|
|
314
|
-
// ArrayPattern:
|
|
315
|
-
// function test([x = 123]) {return x;}; test([456]);
|
|
316
|
-
// AssignmentPattern made up of ObjectPattern:
|
|
317
|
-
// function test({x = 123} = {}) {return x;} test();
|
|
318
|
-
// AssignmentPattern made up of ArrayPattern:
|
|
319
|
-
// function test([x = 123] = []) {return x;} test();
|
|
320
|
-
if (isSupportedPattern) {
|
|
321
|
-
// The name doesn't matter any longer, because any pattern inherently
|
|
322
|
-
// drops the identifier from the AST. But we can access it
|
|
323
|
-
// via arguments[paramIndex] anyway.
|
|
324
|
-
name = `arguments[${paramIndex}]`;
|
|
325
|
-
} else if (param.type === 'AssignmentPattern') {
|
|
326
|
-
const loc = this.getName(node);
|
|
327
|
-
if (param.left.type === 'ArrayPattern' && type.type === 'array') {
|
|
328
|
-
// Add a type assertion for each element of the ArrayPattern
|
|
329
|
-
for (const element of param.left.elements) {
|
|
330
|
-
if (element.type !== 'Identifier') {
|
|
331
|
-
this.warn('Only Identifier case handled right now');
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
const t = JSON.stringify(type.elementType, null, 2).replaceAll('\n', '\n' + spaces);
|
|
335
|
-
out += `${spaces}if (!assertType(${element.name}, ${t}, '${loc}', '${name}')) {\n`;
|
|
336
|
-
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
|
|
337
|
-
}
|
|
338
|
-
continue;
|
|
339
|
-
} else if (param.left.type === 'ObjectPattern' && type.type === 'object') {
|
|
340
|
-
// Add a type assertion for each property of the ObjectPattern
|
|
341
|
-
for (const property of param.left.properties) {
|
|
342
|
-
if (property.key.type !== 'Identifier') {
|
|
343
|
-
this.warn('ObjectPattern> Only Identifier case handled right now');
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
const keyName = property.key.name;
|
|
347
|
-
const subType = type.properties[keyName];
|
|
348
|
-
if (!subType) {
|
|
349
|
-
this.warn("missing subtype information in JSDoc");
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
const t = JSON.stringify(subType, null, 2).replaceAll('\n', '\n' + spaces);
|
|
353
|
-
out += `${spaces}if (!assertType(${keyName}, ${t}, '${loc}', '${name}')) {\n`;
|
|
354
|
-
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
|
|
355
|
-
}
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
this.warn(`generateTypeChecks> ${loc}> todo implement`,
|
|
359
|
-
`AssignmentPattern for parameter ${name}`);
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
} else {
|
|
363
|
-
const loc = this.getName(node);
|
|
364
|
-
this.warn(`generateTypeChecks> ${loc}> Missing param: ${name}`);
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
let t = JSON.stringify(type, null, 2).replaceAll('\n', '\n' + spaces);
|
|
369
|
-
if (type === 'this') {
|
|
370
|
-
const classDecl = this.findParentOfType(node, 'ClassDeclaration');
|
|
371
|
-
if (!classDecl?.id) {
|
|
372
|
-
this.warn('generateTypeChecks> !classDecl?.id');
|
|
373
|
-
}
|
|
374
|
-
t = '"' + this.toSource(classDecl.id) + '"';
|
|
375
|
-
}
|
|
376
|
-
const loc = this.getName(node);
|
|
377
|
-
let prevCheck = '';
|
|
378
|
-
// JSDoc doesn't support multiple function signatures yet, but this is
|
|
379
|
-
// exactly what we would need to deal with ObjectPool'ing
|
|
380
|
-
if (
|
|
381
|
-
loc === 'ContactPoint#constructor' ||
|
|
382
|
-
loc === 'ContactResult#constructor' ||
|
|
383
|
-
loc === 'SingleContactResult#constructor'
|
|
384
|
-
) {
|
|
385
|
-
prevCheck = 'arguments.length !== 0 && ';
|
|
386
|
-
}
|
|
387
|
-
out += `${spaces}if (${prevCheck}!assertType(${name}, ${t}, '${loc}', '${name}')) {\n`;
|
|
388
|
-
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
|
|
389
|
-
}
|
|
390
|
-
return out;
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* @param {Node} node - The Babel AST node.
|
|
394
|
-
* @returns {string} Stringification of the node.
|
|
395
|
-
*/
|
|
396
|
-
getName(node) {
|
|
397
|
-
const toSource = this.toSource.bind(this);
|
|
398
|
-
if (node.type === 'BlockStatement') {
|
|
399
|
-
node = this.parent;
|
|
400
|
-
}
|
|
401
|
-
const {type, key, id} = node;
|
|
402
|
-
switch (type) {
|
|
403
|
-
case 'FunctionDeclaration':
|
|
404
|
-
return toSource(id);
|
|
405
|
-
case "ClassMethod":
|
|
406
|
-
const classDecl = this.parents.findLast(_ => _.type == 'ClassDeclaration');
|
|
407
|
-
let out = ''
|
|
408
|
-
if (classDecl) {
|
|
409
|
-
out += toSource(classDecl.id) + '#';
|
|
410
|
-
}
|
|
411
|
-
out += toSource(key);
|
|
412
|
-
return out;
|
|
413
|
-
case 'FunctionExpression':
|
|
414
|
-
if (id) {
|
|
415
|
-
return toSource(id);
|
|
416
|
-
}
|
|
417
|
-
const expressionStatement = this.findParentOfType(node, 'ExpressionStatement');
|
|
418
|
-
if (!expressionStatement) {
|
|
419
|
-
return "unnamed function expression";
|
|
420
|
-
}
|
|
421
|
-
return toSource(expressionStatement.expression.left);
|
|
422
|
-
case 'ArrowFunctionExpression':
|
|
423
|
-
const parent = this.findParentOfType(node, 'VariableDeclarator');
|
|
424
|
-
if (parent) {
|
|
425
|
-
return toSource(parent.id);
|
|
426
|
-
} else {
|
|
427
|
-
return "getName> missing parent for " + node.type;
|
|
428
|
-
}
|
|
429
|
-
default:
|
|
430
|
-
this.warn("getName> unhandled type", type, "for", node);
|
|
431
|
-
return '/*MISSING*/';
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* @override
|
|
436
|
-
* @param {import("@babel/types").BinaryExpression} node - The Babel AST node.
|
|
437
|
-
* @returns {string} Stringification of the node.
|
|
438
|
-
*/
|
|
439
|
-
BinaryExpression(node) {
|
|
440
|
-
if (!this.validateDivision) {
|
|
441
|
-
return super.BinaryExpression(node);
|
|
442
|
-
}
|
|
443
|
-
const {left, operator, right} = node;
|
|
444
|
-
const left_ = this.toSource(left);
|
|
445
|
-
const right_ = this.toSource(right);
|
|
446
|
-
if (operator === '/') {
|
|
447
|
-
return `validateDivision(${left_}, ${right_})`;
|
|
448
|
-
}
|
|
449
|
-
return `${left_} ${operator} ${right_}`;
|
|
450
|
-
}
|
|
451
|
-
/** @type {Record<string, object>} */
|
|
452
|
-
typedefs = {};
|
|
453
|
-
/**
|
|
454
|
-
* @override
|
|
455
|
-
* @param {import("@babel/types").File} node - The Babel AST node.
|
|
456
|
-
* @returns {string} Stringification of the node.
|
|
457
|
-
*/
|
|
458
|
-
File(node) {
|
|
459
|
-
const {errors, program, comments} = node;
|
|
460
|
-
if (comments) {
|
|
461
|
-
for (const comment of comments) {
|
|
462
|
-
const warn = this.warn.bind(this);
|
|
463
|
-
parseJSDocTypedef(this.typedefs, warn, comment, this.expandType);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
//console.log("this.typedefs", this.typedefs);
|
|
467
|
-
let out = '';
|
|
468
|
-
for (const name in this.typedefs) {
|
|
469
|
-
const typedef = this.typedefs[name];
|
|
470
|
-
const json = JSON.stringify(typedef, null, 2);
|
|
471
|
-
out += `registerTypedef('${name}', ${json});\n`;
|
|
472
|
-
}
|
|
473
|
-
const code = this.toSource(program) + '\n';
|
|
474
|
-
out += code;
|
|
475
|
-
return out;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
export {StringifierWithTypeAssertions};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import {parse } from '@babel/parser';
|
|
2
|
-
import {StringifierWithTypeAssertions} from './StringifierWithTypeAssertions.mjs';
|
|
3
|
-
/**
|
|
4
|
-
* Simple facade which does all the processing.
|
|
5
|
-
* @param {string} src - The input source with JSDoc comments.
|
|
6
|
-
* @param {import('./StringifierWithTypeAssertions.mjs').Options} [options]
|
|
7
|
-
* @returns {string} The output source with runtime type testing.
|
|
8
|
-
*/
|
|
9
|
-
function addTypeChecks(src, options) {
|
|
10
|
-
try {
|
|
11
|
-
const stringifierWithTypeAssertions = new StringifierWithTypeAssertions(options);
|
|
12
|
-
const ast = parse(src, {sourceType: 'module'});
|
|
13
|
-
const out = stringifierWithTypeAssertions.toSource(ast);
|
|
14
|
-
return out;
|
|
15
|
-
} catch (e) {
|
|
16
|
-
console.error(e);
|
|
17
|
-
return `/*<addTypeChecks-error>*/${src}/*</addTypeChecks-error>*/`;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
export {addTypeChecks};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {object} ast - The Babel AST.
|
|
3
|
-
* @returns {string} String representation in JSON format for debugging/inspecting the AST.
|
|
4
|
-
*/
|
|
5
|
-
function ast2json(ast) {
|
|
6
|
-
return JSON.stringify(ast, function(name, val) {
|
|
7
|
-
if (name == "loc" || name == "start" || name == "end") {
|
|
8
|
-
return undefined; // remove
|
|
9
|
-
}
|
|
10
|
-
return val; // keep
|
|
11
|
-
}, 2);
|
|
12
|
-
}
|
|
13
|
-
export {ast2json};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const drop = [
|
|
2
|
-
'loc',
|
|
3
|
-
'start',
|
|
4
|
-
'end',
|
|
5
|
-
'leadingComments',
|
|
6
|
-
'trailingComments',
|
|
7
|
-
'innerComments',
|
|
8
|
-
'innerComments',
|
|
9
|
-
'comments',
|
|
10
|
-
];
|
|
11
|
-
/**
|
|
12
|
-
* @example
|
|
13
|
-
* setRight(ast2jsonForComparison(parseSync("/** *"))); // Close comment with / after last *
|
|
14
|
-
* @param {object} ast - The Babel AST.
|
|
15
|
-
* @returns {string} String representation in JSON format for debugging/inspecting the AST.
|
|
16
|
-
*/
|
|
17
|
-
function ast2jsonForComparison(ast) {
|
|
18
|
-
return JSON.stringify(ast, function(name, val) {
|
|
19
|
-
if (name === 'trailingComma' || name === 'parenStart') {
|
|
20
|
-
return 'offset removed for better comparison';
|
|
21
|
-
}
|
|
22
|
-
if (drop.includes(name)) {
|
|
23
|
-
return undefined; // remove
|
|
24
|
-
}
|
|
25
|
-
return val; // keep
|
|
26
|
-
}, 2);
|
|
27
|
-
}
|
|
28
|
-
export {ast2jsonForComparison};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {parse } from "@babel/parser";
|
|
2
|
-
import {Stringifier} from "./Stringifier.mjs";
|
|
3
|
-
/**
|
|
4
|
-
* A roundtrip between code -> AST -> code to validate Stringifier.
|
|
5
|
-
* @param {string} code - The code.
|
|
6
|
-
*/
|
|
7
|
-
function code2ast2code(code) {
|
|
8
|
-
const stringifier = new Stringifier();
|
|
9
|
-
const ast = parse(code, {sourceType: 'module'});
|
|
10
|
-
if (!ast) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const out = stringifier.toSource(ast);
|
|
14
|
-
return out;
|
|
15
|
-
}
|
|
16
|
-
export {code2ast2code};
|