runtime-type-inspector 1.0.0 → 2.0.0

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.
Files changed (54) hide show
  1. package/.eslintrc.js +480 -0
  2. package/README.md +12 -4
  3. package/jsconfig.json +10 -0
  4. package/package.json +32 -4
  5. package/plugin-parcel/index.mjs +4 -0
  6. package/plugin-rollup/index.mjs +78 -0
  7. package/plugin-webpack/index.mjs +4 -0
  8. package/rollup.config.mjs +183 -0
  9. package/src-runtime/assertType.mjs +54 -0
  10. package/src-runtime/createDiv.mjs +69 -0
  11. package/src-runtime/index.mjs +21 -0
  12. package/src-runtime/makeJSDoc.mjs +40 -0
  13. package/src-runtime/registerClass.mjs +11 -0
  14. package/src-runtime/registerTypedef.mjs +12 -0
  15. package/src-runtime/typecheckDiv.mjs +3 -0
  16. package/src-runtime/typecheckEvery.mjs +21 -0
  17. package/src-runtime/typecheckOptions.mjs +60 -0
  18. package/src-runtime/typecheckTable.mjs +14 -0
  19. package/src-runtime/typecheckWarn.mjs +23 -0
  20. package/src-runtime/validateArray.mjs +26 -0
  21. package/src-runtime/validateDivision.mjs +31 -0
  22. package/src-runtime/validateMap.mjs +36 -0
  23. package/src-runtime/validateNumber.mjs +29 -0
  24. package/src-runtime/validateObject.mjs +43 -0
  25. package/src-runtime/validateRecord.mjs +31 -0
  26. package/src-runtime/validateSet.mjs +26 -0
  27. package/src-runtime/validateTuple.mjs +28 -0
  28. package/src-runtime/validateType.mjs +214 -0
  29. package/src-runtime/validateTypedef.mjs +18 -0
  30. package/src-runtime/validateUnion.mjs +19 -0
  31. package/src-runtime/youCanAddABreakpointHere.mjs +11 -0
  32. package/src-transpiler/Stringifier.mjs +1268 -0
  33. package/src-transpiler/StringifierWithTypeAssertions.mjs +478 -0
  34. package/src-transpiler/addTypeChecks.mjs +20 -0
  35. package/src-transpiler/ast2json.mjs +13 -0
  36. package/src-transpiler/ast2jsonForComparison.mjs +28 -0
  37. package/src-transpiler/code2ast2code.mjs +16 -0
  38. package/src-transpiler/expandType.mjs +187 -0
  39. package/src-transpiler/expandTypeDepFree.mjs +122 -0
  40. package/src-transpiler/extractNameAndOptionality.mjs +23 -0
  41. package/src-transpiler/index.mjs +13 -0
  42. package/src-transpiler/parseJSDoc.mjs +69 -0
  43. package/src-transpiler/parseJSDocSetter.mjs +16 -0
  44. package/src-transpiler/parseJSDocTypedef.mjs +69 -0
  45. package/src-transpiler/simplifyType.mjs +31 -0
  46. package/src-transpiler/stat.mjs +13 -0
  47. package/ui/babel-core.mjs +5 -0
  48. package/ui/babel-helper-plugin-utils.mjs +7 -0
  49. package/ui/babel-parser.mjs +8 -0
  50. package/ui/babel-plugin-syntax-typescript.mjs +58 -0
  51. package/ui/importmap.js +38 -0
  52. package/ui/index.html +30 -0
  53. package/ui/index.mjs +379 -0
  54. package/src/index.mjs +0 -1
@@ -0,0 +1,43 @@
1
+ import {assertType } from "./assertType.mjs";
2
+ import {typecheckOptions} from "./typecheckOptions.mjs";
3
+ import {typecheckWarn } from "./typecheckWarn.mjs";
4
+ /**
5
+ * @param {*} value
6
+ * @param {*} properties
7
+ * @param {*} loc
8
+ * @param {*} name
9
+ * @param {*} critical
10
+ * @returns {boolean}
11
+ */
12
+ function validateObject(value, properties, loc, name, critical) {
13
+ if (!(value instanceof Object)) {
14
+ return false;
15
+ }
16
+ if (properties && Object.keys(properties).length) {
17
+ if (loc !== 'sortPriority' && loc !== 'getResource' && loc !== 'cmpPriority') {
18
+ Object.keys(value).forEach((key) => {
19
+ if (key === 'profilerHint') {
20
+ return;
21
+ }
22
+ if (!properties[key]) {
23
+ if (typecheckOptions.logSuperfluousProperty) {
24
+ typecheckWarn(`${loc}> superfluous property> ${name}.${key}`, { properties, value });
25
+ }
26
+ }
27
+ });
28
+ }
29
+ return Object.keys(properties).every((key) => {
30
+ const innerValue = value[key];
31
+ const innerType = properties[key];
32
+ return assertType(
33
+ innerValue,
34
+ innerType,
35
+ loc,
36
+ `${name}.${key}`,
37
+ critical
38
+ );
39
+ });
40
+ }
41
+ return value instanceof Object;
42
+ }
43
+ export {validateObject};
@@ -0,0 +1,31 @@
1
+ import {assertType } from "./assertType.mjs";
2
+ import {typecheckWarn} from "./typecheckWarn.mjs";
3
+ /**
4
+ * @param {*} value
5
+ * @param {*} expect
6
+ * @param {*} loc
7
+ * @param {*} name
8
+ * @param {*} critical
9
+ * @returns {boolean}
10
+ */
11
+ function validateRecord(value, expect, loc, name, critical) {
12
+ const {key, val} = expect;
13
+ if (key !== 'string') {
14
+ typecheckWarn(`${loc}> validateType> record> unhandled key '${key}'`);
15
+ return false;
16
+ }
17
+ if (typeof value !== 'object') {
18
+ typecheckWarn(`${loc}> validateType> record> expected object, not '${value}'`);
19
+ return false;
20
+ }
21
+ return Object.keys(value).every(
22
+ key => assertType(
23
+ value[key],
24
+ val,
25
+ loc,
26
+ `${name}['${key}']`,
27
+ critical
28
+ )
29
+ );
30
+ }
31
+ export {validateRecord};
@@ -0,0 +1,26 @@
1
+ import {assertType } from "./assertType.mjs";
2
+ import {typecheckWarn} from "./typecheckWarn.mjs";
3
+ /**
4
+ * @param {*} value
5
+ * @param {*} expect
6
+ * @param {*} loc
7
+ * @param {*} name
8
+ * @param {*} critical
9
+ * @return {boolean}
10
+ */
11
+ function validateSet(value, expect, loc, name, critical) {
12
+ if (!(value instanceof Set)) {
13
+ return false;
14
+ }
15
+ let errors = 0;
16
+ const {elementType} = expect;
17
+ value.forEach((x, i) => {
18
+ const test = assertType(x, elementType, loc, name, critical);
19
+ if (!test) {
20
+ typecheckWarn(`validateSet> invalid set member at ${i}, expected ${elementType}, got ${typeof x}`);
21
+ errors++;
22
+ }
23
+ });
24
+ return errors === 0;
25
+ }
26
+ export {validateSet};
@@ -0,0 +1,28 @@
1
+ import {assertType} from "./assertType.mjs";
2
+ /**
3
+ * @param {*} value
4
+ * @param {*} expect
5
+ * @param {*} loc
6
+ * @param {*} name
7
+ * @param {*} critical
8
+ * @returns {boolean}
9
+ */
10
+ function validateTuple(value, expect, loc, name, critical) {
11
+ if (!value) {
12
+ return false;
13
+ }
14
+ if (!(value instanceof Array)) {
15
+ return false;
16
+ }
17
+ const { elements } = expect;
18
+ return elements.every((element, i) => {
19
+ return assertType(
20
+ value[i],
21
+ element,
22
+ loc,
23
+ `${name}[${i}]`,
24
+ critical
25
+ );
26
+ });
27
+ }
28
+ export {validateTuple};
@@ -0,0 +1,214 @@
1
+ import {classes } from "./registerClass.mjs";
2
+ import {typedefs } from "./registerTypedef.mjs";
3
+ import {typecheckOptions} from "./typecheckOptions.mjs";
4
+ import {typecheckWarn } from "./typecheckWarn.mjs";
5
+ import {validateArray } from "./validateArray.mjs";
6
+ import {validateMap } from "./validateMap.mjs";
7
+ import {validateNumber } from "./validateNumber.mjs";
8
+ import {validateObject } from "./validateObject.mjs";
9
+ import {validateRecord } from "./validateRecord.mjs";
10
+ import {validateSet } from "./validateSet.mjs";
11
+ import {validateTuple } from "./validateTuple.mjs";
12
+ import {validateTypedef } from "./validateTypedef.mjs";
13
+ import {validateUnion } from "./validateUnion.mjs";
14
+ // For quickly checking props of Vec2/Vec3/Vec4/Quat/Mat3/Mat4 without GC
15
+ const propsXY = ['x', 'y'];
16
+ const propsXYZ = ['x', 'y', 'z'];
17
+ const propsXYZW = ['x', 'y', 'z', 'w'];
18
+ const props9 = [0, 1, 2, 3, 4, 5, 6, 7, 8];
19
+ const props16 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
20
+ /**
21
+ * @param {*} value - The actual value which we need to check.
22
+ * @param {object} expect - Can also be a string, but string|object is unsupported in VSCode
23
+ * @param {string} expect.type - Something like 'string', 'number', 'object', 'MeshInstance' etc.
24
+ * @param {boolean} expect.optional - Is it an optional argument?
25
+ * @param {object} [expect.properties] - Extra information for `expect.type === 'object'`.
26
+ * @param {string} [expect.key] - Extra information for `expect.type === 'record'`.
27
+ * @param {any} [expect.val] - Extra information for `expect.type === 'record'`, same
28
+ * type as "expect".
29
+ * @param {any[]} [expect.elements] - Extra information for `expect.type === 'record'`, same
30
+ * type as "expect".
31
+ * @param {any[]} [expect.elementType] - Extra information for array/class.
32
+ * @todo Split array/class.
33
+ * @param {string} loc - String like `BoundingBox#compute`
34
+ * @param {string} name - Name of the argument.
35
+ * @param {boolean} critical - Only false for unions.
36
+ * @returns {boolean} - Returns wether `value` is in the shape of `expect`.
37
+ */
38
+ function validateType(value, expect, loc, name, critical = true) {
39
+ if (typeof expect === 'string') {
40
+ expect = {
41
+ type: expect,
42
+ optional: false
43
+ };
44
+ }
45
+ let { type } = expect;
46
+ const { optional, properties } = expect;
47
+ if (!type) {
48
+ console.error('validateType> missing type');
49
+ return false;
50
+ }
51
+ // todo: keep everything const, should be trimmed anyway already (add unit tests)
52
+ type = type.trim();
53
+ if (optional) {
54
+ if (value === undefined) {
55
+ return true;
56
+ }
57
+ // Allow `null` for optional, because engine doesn't support strictNullChecks yet.
58
+ if (value === null) {
59
+ return true;
60
+ }
61
+ }
62
+ const customCheck = typecheckOptions.customTypes[type];
63
+ if (customCheck) {
64
+ return customCheck(value);
65
+ }
66
+ if (type === "undefined") {
67
+ return value === undefined;
68
+ }
69
+ if (typeof value === 'number') {
70
+ if (isNaN(value)) {
71
+ typecheckWarn("value is NaN");
72
+ return false;
73
+ }
74
+ if (!isFinite(value)) {
75
+ typecheckWarn("value is +-infinite");
76
+ return false;
77
+ }
78
+ }
79
+ if (window.pc) {
80
+ /**
81
+ * @param {string|number} prop - Something like 'x', 'y', 'z', 'w', 0, 1, 2, 3, 4 etc.
82
+ * @returns {boolean} Wether prop is a valid number.
83
+ */
84
+ const checkProp = (prop) => {
85
+ return validateNumber(value, prop);
86
+ };
87
+ // In a bundle pc can be defined while pc is not filled with all classes yet,
88
+ // therefore we need to check if class is added already.
89
+ if (pc.Vec2 && value instanceof pc.Vec2) {
90
+ return propsXY.every(checkProp);
91
+ }
92
+ if (pc.Vec3 && value instanceof pc.Vec3) {
93
+ return propsXYZ.every(checkProp);
94
+ }
95
+ if ((pc.Vec4 && value instanceof pc.Vec4) || (pc.Quat && value instanceof pc.Quat)) {
96
+ return propsXYZW.every(checkProp);
97
+ }
98
+ if (pc.Mat3 && value instanceof pc.Mat3) {
99
+ return props9.every(prop => validateNumber(value.data, prop));
100
+ }
101
+ if (pc.Mat4 && value instanceof pc.Mat4) {
102
+ return props16.every(prop => validateNumber(value.data, prop));
103
+ }
104
+ }
105
+ // todo: either switch or object lookup for custom hooks
106
+ if (type === "object") {
107
+ return validateObject(value, properties, loc, name, critical);
108
+ }
109
+ if (type === 'record') {
110
+ return validateRecord(value, expect, loc, name, critical);
111
+ }
112
+ if (type === 'map') {
113
+ return validateMap(value, expect, loc, name, critical);
114
+ }
115
+ if (type === 'array') {
116
+ return validateArray(value, expect, loc, name, critical);
117
+ }
118
+ // If a typedef is also a class, it's just a shorthand-typedef-class
119
+ if (typedefs[type] && !classes[type]) {
120
+ return validateTypedef(value, expect, loc, name, critical);
121
+ }
122
+ if (type === 'union') {
123
+ return validateUnion(value, expect, loc, name, critical);
124
+ }
125
+ if (type === 'set') {
126
+ return validateSet(value, expect, loc, name, critical);
127
+ }
128
+ // Trigger: pc.app.scene.setSkybox([1, 2, 3]);
129
+ if (type === 'tuple') {
130
+ return validateTuple(value, expect, loc, name, critical);
131
+ }
132
+ if (type === '*' || type === 'any') {
133
+ return true;
134
+ }
135
+ /** @todo allow strict/non-strict null/undefined with checkbox in <div> */
136
+ if (type === 'null') {
137
+ return value === null;
138
+ }
139
+ /** @todo add unit-tests/asserts tests to make sure this never happens */
140
+ if (value === null) {
141
+ // type !== null already, so this can only be false
142
+ return false;
143
+ }
144
+ /** @todo use validateNumber() */
145
+ if (type === 'number') {
146
+ if (Number.isNaN(value)) {
147
+ return false;
148
+ }
149
+ return typeof value === type;
150
+ }
151
+ if (type === 'string' || type === 'boolean') {
152
+ return typeof value === type;
153
+ }
154
+ if (type[0] === '"' && type[type.length - 1] === '"') {
155
+ const typeSlice = type.slice(1, -1);
156
+ return value === typeSlice;
157
+ }
158
+ if (type[0] === "'" && type[type.length - 1] === "'") {
159
+ const typeSlice = type.slice(1, -1);
160
+ return value === typeSlice;
161
+ }
162
+ /** @todo Callback is PC specific, parse JSDoc callback types like typedefs */
163
+ if (type === 'Function' || type === 'function' || type.includes('Callback')) {
164
+ return typeof value === "function";
165
+ }
166
+ if (type === 'ObjectConstructor') {
167
+ return typeof value.constructor === 'function';
168
+ }
169
+ if (type === 'class') {
170
+ if (value && expect.elementType === 'ScriptType') {
171
+ if (value.name === 'scriptType') {
172
+ return true;
173
+ }
174
+ const proto = Object.getPrototypeOf(value);
175
+ if (proto?.name === 'ScriptType') {
176
+ return true;
177
+ }
178
+ }
179
+ typecheckWarn(`${loc}> validateType> class> expected object, not '${value}'`);
180
+ return false;
181
+ }
182
+ if (type === 'ResourceHandler') {
183
+ return value?.constructor?.name.endsWith('Handler');
184
+ }
185
+ // Camera, Float32Array etc.
186
+ if (value && value.constructor && value.constructor.name === type) {
187
+ return true;
188
+ }
189
+ const windowClass = window[type];
190
+ if (windowClass) {
191
+ return value instanceof windowClass;
192
+ }
193
+ if (type.startsWith('globalThis.')) {
194
+ const innerType = type.slice(11);
195
+ const windowClass = window[innerType];
196
+ if (windowClass) {
197
+ return value instanceof windowClass;
198
+ }
199
+ }
200
+ // inheritance check, allow Application for AppBase, allow Entity for GraphNode etc.
201
+ if (classes[type]) {
202
+ return value instanceof classes[type];
203
+ }
204
+ //} /*else if (typeof theClass === 'number' || typeof theClass === 'string') {
205
+ // todo register these too individually?
206
+ // return value === theClass;
207
+ //}*/
208
+ // typecheckWarn('unhandled pc member', { value, type, expect, theClass });
209
+ // return false;
210
+ //}
211
+ typecheckWarn("unchecked", { value, type, loc, name });
212
+ return false;
213
+ }
214
+ export {validateType};
@@ -0,0 +1,18 @@
1
+ import {typedefs } from "./registerTypedef.mjs";
2
+ import {validateType} from "./validateType.mjs";
3
+ /**
4
+ * @param {*} value
5
+ * @param {*} expect
6
+ * @param {*} loc
7
+ * @param {*} name
8
+ * @param {*} critical
9
+ * @return {boolean}
10
+ */
11
+ function validateTypedef(value, expect, loc, name, critical) {
12
+ if (expect.optional && value === undefined) {
13
+ return true;
14
+ }
15
+ const typedef = typedefs[expect.type];
16
+ return validateType(value, typedef, loc, name, critical);
17
+ }
18
+ export {validateTypedef};
@@ -0,0 +1,19 @@
1
+ import {assertType} from "./assertType.mjs";
2
+ /**
3
+ * @param {*} value
4
+ * @param {*} expect
5
+ * @param {*} loc
6
+ * @param {*} name
7
+ * @param {*} critical
8
+ * @returns {boolean}
9
+ */
10
+ function validateUnion(value, expect, loc, name, critical) {
11
+ return expect.members.some(member => assertType(
12
+ value,
13
+ member,
14
+ loc,
15
+ name + ` union type: ${member?.type || member}`,
16
+ false
17
+ ));
18
+ }
19
+ export {validateUnion};
@@ -0,0 +1,11 @@
1
+ let breakpointID = 0;
2
+ /**
3
+ * Function for the sole purpose of being able to add a breakpoint in devtools.
4
+ * It must do "something" or Babel strips it, so we are counting up `breakpointID`.
5
+ *
6
+ * @returns {number} The breakpointID.
7
+ */
8
+ function youCanAddABreakpointHere() {
9
+ return breakpointID++;
10
+ }
11
+ export {breakpointID, youCanAddABreakpointHere};