@runtime-type-inspector/transpiler 5.0.3 → 5.0.5
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/index.cjs +173 -21
- package/index.mjs +154 -19
- package/package.json +2 -2
package/index.cjs
CHANGED
|
@@ -449,9 +449,9 @@
|
|
|
449
449
|
TypeQuery = _ts$SyntaxKind.TypeQuery,
|
|
450
450
|
TypeOperator = _ts$SyntaxKind.TypeOperator,
|
|
451
451
|
KeyOfKeyword = _ts$SyntaxKind.KeyOfKeyword,
|
|
452
|
-
ReadonlyKeyword = _ts$SyntaxKind.ReadonlyKeyword
|
|
453
|
-
_ts$SyntaxKind.UniqueKeyword
|
|
454
|
-
|
|
452
|
+
ReadonlyKeyword = _ts$SyntaxKind.ReadonlyKeyword,
|
|
453
|
+
UniqueKeyword = _ts$SyntaxKind.UniqueKeyword,
|
|
454
|
+
ConstructorType = _ts$SyntaxKind.ConstructorType,
|
|
455
455
|
NamedTupleMember = _ts$SyntaxKind.NamedTupleMember,
|
|
456
456
|
MappedType = _ts$SyntaxKind.MappedType,
|
|
457
457
|
MinusToken = _ts$SyntaxKind.MinusToken,
|
|
@@ -639,6 +639,11 @@
|
|
|
639
639
|
// readonly erased at runtime, same shape as the inner type.
|
|
640
640
|
return toSourceTS(node.type);
|
|
641
641
|
}
|
|
642
|
+
if (node.operator === UniqueKeyword) {
|
|
643
|
+
// `unique symbol` is a symbol at runtime; the uniqueness refers to
|
|
644
|
+
// a specific declaration which we cannot track here.
|
|
645
|
+
return toSourceTS(node.type);
|
|
646
|
+
}
|
|
642
647
|
console.warn("unimplemented TypeOperator", node);
|
|
643
648
|
return 'any';
|
|
644
649
|
case TypeReference:
|
|
@@ -1370,7 +1375,7 @@
|
|
|
1370
1375
|
return expandTypeDepFree(type.slice(9).trim());
|
|
1371
1376
|
}
|
|
1372
1377
|
if (type === 'unique symbol') {
|
|
1373
|
-
return '
|
|
1378
|
+
return 'symbol';
|
|
1374
1379
|
}
|
|
1375
1380
|
// Conditionals before nullable: `A extends B ? C : D?` must keep the
|
|
1376
1381
|
// nullable on the false branch, not lift it over the whole condition.
|
|
@@ -2634,6 +2639,21 @@
|
|
|
2634
2639
|
var matches = _toConsumableArray(src.matchAll(regexTemplateTyped));
|
|
2635
2640
|
/** @type {Record<string, ExpandTypeReturnType>} */
|
|
2636
2641
|
var templates = Object.create(null);
|
|
2642
|
+
// `@template {Constraint} [Name=Default]` (or `[Name]`): constraint wins,
|
|
2643
|
+
// the default only matters when nothing is inferred.
|
|
2644
|
+
var regexTemplateConstrainedDefault = /@template \{(.*?)\}\s*\[([a-zA-Z0-9_$]+)(?:=([^\]]+))?\]/g;
|
|
2645
|
+
var _iterator = _createForOfIteratorHelper(src.matchAll(regexTemplateConstrainedDefault)),
|
|
2646
|
+
_step;
|
|
2647
|
+
try {
|
|
2648
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
2649
|
+
var match = _step.value;
|
|
2650
|
+
templates[match[2]] = expandType(match[1].trim());
|
|
2651
|
+
}
|
|
2652
|
+
} catch (err) {
|
|
2653
|
+
_iterator.e(err);
|
|
2654
|
+
} finally {
|
|
2655
|
+
_iterator.f();
|
|
2656
|
+
}
|
|
2637
2657
|
matches.forEach(function (_) {
|
|
2638
2658
|
var type = expandType(_[1].trim());
|
|
2639
2659
|
var name = _[2].trim();
|
|
@@ -2641,34 +2661,34 @@
|
|
|
2641
2661
|
});
|
|
2642
2662
|
// `@template [A=X]` defaults: constraint X under name A.
|
|
2643
2663
|
var regexTemplateDefault = /@template \[([a-zA-Z0-9_$]+)=([^\]]+)\]/g;
|
|
2644
|
-
var
|
|
2645
|
-
|
|
2664
|
+
var _iterator2 = _createForOfIteratorHelper(src.matchAll(regexTemplateDefault)),
|
|
2665
|
+
_step2;
|
|
2646
2666
|
try {
|
|
2647
|
-
for (
|
|
2648
|
-
var
|
|
2649
|
-
templates[
|
|
2667
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
2668
|
+
var _match = _step2.value;
|
|
2669
|
+
templates[_match[1]] = expandType(_match[2].trim());
|
|
2650
2670
|
}
|
|
2651
2671
|
// Bare `@template T`: unconstrained, stands in as any.
|
|
2652
2672
|
} catch (err) {
|
|
2653
|
-
|
|
2673
|
+
_iterator2.e(err);
|
|
2654
2674
|
} finally {
|
|
2655
|
-
|
|
2675
|
+
_iterator2.f();
|
|
2656
2676
|
}
|
|
2657
2677
|
var regexTemplateBare = /@template ([a-zA-Z0-9_$]+)(?![a-zA-Z0-9_$])/g;
|
|
2658
|
-
var
|
|
2659
|
-
|
|
2678
|
+
var _iterator3 = _createForOfIteratorHelper(src.matchAll(regexTemplateBare)),
|
|
2679
|
+
_step3;
|
|
2660
2680
|
try {
|
|
2661
|
-
for (
|
|
2662
|
-
var
|
|
2663
|
-
var name =
|
|
2681
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
2682
|
+
var _match2 = _step3.value;
|
|
2683
|
+
var name = _match2[1];
|
|
2664
2684
|
if (!(name in templates)) {
|
|
2665
2685
|
templates[name] = 'any';
|
|
2666
2686
|
}
|
|
2667
2687
|
}
|
|
2668
2688
|
} catch (err) {
|
|
2669
|
-
|
|
2689
|
+
_iterator3.e(err);
|
|
2670
2690
|
} finally {
|
|
2671
|
-
|
|
2691
|
+
_iterator3.f();
|
|
2672
2692
|
}
|
|
2673
2693
|
if (!Object.keys(templates).length) {
|
|
2674
2694
|
return;
|
|
@@ -4938,6 +4958,10 @@
|
|
|
4938
4958
|
* @property {string} [filename] - The name of a file to which the instance pertains.
|
|
4939
4959
|
* @property {boolean} [addHeader] - Whether to add import declarations headers. Defaults to true.
|
|
4940
4960
|
* @property {string[]} [ignoreLocations] - Ignore these locations because they are known false-positives.
|
|
4961
|
+
* @property {string} [projectVersion] - Host project version funneled into
|
|
4962
|
+
* the emitted header via `setProjectVersion(...)`, so `Download log` meta
|
|
4963
|
+
* identifies the app build. Bundler plugins resolve it from their own
|
|
4964
|
+
* option or the host package.json.
|
|
4941
4965
|
*/
|
|
4942
4966
|
var Asserter = /*#__PURE__*/function (_Stringifier) {
|
|
4943
4967
|
_inherits(Asserter, _Stringifier);
|
|
@@ -4960,7 +4984,8 @@
|
|
|
4960
4984
|
_ref$addHeader = _ref.addHeader,
|
|
4961
4985
|
addHeader = _ref$addHeader === void 0 ? true : _ref$addHeader,
|
|
4962
4986
|
_ref$ignoreLocations = _ref.ignoreLocations,
|
|
4963
|
-
ignoreLocations = _ref$ignoreLocations === void 0 ? [] : _ref$ignoreLocations
|
|
4987
|
+
ignoreLocations = _ref$ignoreLocations === void 0 ? [] : _ref$ignoreLocations,
|
|
4988
|
+
projectVersion = _ref.projectVersion;
|
|
4964
4989
|
_classCallCheck(this, Asserter);
|
|
4965
4990
|
_this = _super.call(this);
|
|
4966
4991
|
/** @type {Record<string, Stat>} */
|
|
@@ -5025,6 +5050,7 @@
|
|
|
5025
5050
|
_this.filename = filename;
|
|
5026
5051
|
_this.addHeader = addHeader;
|
|
5027
5052
|
_this.ignoreLocations = ignoreLocations;
|
|
5053
|
+
_this.projectVersion = projectVersion;
|
|
5028
5054
|
return _this;
|
|
5029
5055
|
}
|
|
5030
5056
|
_createClass(Asserter, [{
|
|
@@ -5133,9 +5159,16 @@
|
|
|
5133
5159
|
if (this.validateDivision) {
|
|
5134
5160
|
header += ", validateDivision";
|
|
5135
5161
|
}
|
|
5136
|
-
header += ", registerTypedef, registerClass, registerImportNamespaceSpecifier
|
|
5162
|
+
header += ", registerTypedef, registerClass, registerImportNamespaceSpecifier";
|
|
5163
|
+
if (this.projectVersion !== undefined && this.projectVersion !== null) {
|
|
5164
|
+
header += ", setProjectVersion";
|
|
5165
|
+
}
|
|
5166
|
+
header += "} from '@runtime-type-inspector/runtime';\n";
|
|
5137
5167
|
// Prevent tree-shaking in UMD build so we can always "add a breakpoint here".
|
|
5138
5168
|
header += "export * from '@runtime-type-inspector/runtime';\n";
|
|
5169
|
+
if (this.projectVersion !== undefined && this.projectVersion !== null) {
|
|
5170
|
+
header += "setProjectVersion(".concat(JSON.stringify(this.projectVersion), ");\n");
|
|
5171
|
+
}
|
|
5139
5172
|
return header;
|
|
5140
5173
|
}
|
|
5141
5174
|
/**
|
|
@@ -5350,6 +5383,115 @@
|
|
|
5350
5383
|
params: params
|
|
5351
5384
|
};
|
|
5352
5385
|
}
|
|
5386
|
+
/**
|
|
5387
|
+
* Reads `@template` bindings from every lexically enclosing scope, outer
|
|
5388
|
+
* to inner: classes (declaration or expression, incl. `export` wrappers)
|
|
5389
|
+
* and functions with their own `@template` tags. Class templates scope
|
|
5390
|
+
* over the constructor and methods, mirroring TypeScript:
|
|
5391
|
+
* `new Asset('x', ...)` infers `K` from the constructor's `@param {K}`
|
|
5392
|
+
* occurrences. Inner scopes shadow outer names on conflict.
|
|
5393
|
+
* @param {Node} node - The function or block node being checked.
|
|
5394
|
+
* @returns {Record<string, any>|undefined} Merged scope templates or undefined.
|
|
5395
|
+
*/
|
|
5396
|
+
}, {
|
|
5397
|
+
key: "getScopeTemplates",
|
|
5398
|
+
value: function getScopeTemplates(node) {
|
|
5399
|
+
var fnNode = node;
|
|
5400
|
+
if (node.type === 'BlockStatement') {
|
|
5401
|
+
fnNode = this.parent;
|
|
5402
|
+
}
|
|
5403
|
+
var anchorIdx = this.parents.findLastIndex(function (_) {
|
|
5404
|
+
return _ === node;
|
|
5405
|
+
});
|
|
5406
|
+
if (anchorIdx === -1) {
|
|
5407
|
+
return;
|
|
5408
|
+
}
|
|
5409
|
+
var merged;
|
|
5410
|
+
for (var i = 0; i <= anchorIdx; i++) {
|
|
5411
|
+
var ancestor = this.parents[i];
|
|
5412
|
+
if (!ancestor || ancestor === fnNode) {
|
|
5413
|
+
// Never inherit the node's own bindings: they merge separately and win.
|
|
5414
|
+
continue;
|
|
5415
|
+
}
|
|
5416
|
+
var templates = void 0;
|
|
5417
|
+
if (ancestor.type === 'ClassDeclaration' || ancestor.type === 'ClassExpression') {
|
|
5418
|
+
templates = this.classTemplatesOf(ancestor);
|
|
5419
|
+
} else if (nodeIsFunctionLike(ancestor)) {
|
|
5420
|
+
templates = this.functionTemplatesOf(ancestor);
|
|
5421
|
+
}
|
|
5422
|
+
if (templates) {
|
|
5423
|
+
merged = _objectSpread2(_objectSpread2({}, merged), templates);
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
return merged;
|
|
5427
|
+
}
|
|
5428
|
+
/**
|
|
5429
|
+
* Reads the `@template` bindings off one class node.
|
|
5430
|
+
* @param {Node} classDecl - The ClassDeclaration or ClassExpression node.
|
|
5431
|
+
* @returns {Record<string, any>|undefined} Its templates or undefined.
|
|
5432
|
+
*/
|
|
5433
|
+
}, {
|
|
5434
|
+
key: "classTemplatesOf",
|
|
5435
|
+
value: function classTemplatesOf(classDecl) {
|
|
5436
|
+
var _leadingComments;
|
|
5437
|
+
var leadingComments = classDecl.leadingComments;
|
|
5438
|
+
if (!leadingComments) {
|
|
5439
|
+
var exportNamed = this.findParentOfType(classDecl, 'ExportNamedDeclaration');
|
|
5440
|
+
leadingComments = exportNamed === null || exportNamed === void 0 ? void 0 : exportNamed.leadingComments;
|
|
5441
|
+
if (!leadingComments) {
|
|
5442
|
+
var exportDefault = this.findParentOfType(classDecl, 'ExportDefaultDeclaration');
|
|
5443
|
+
leadingComments = exportDefault === null || exportDefault === void 0 ? void 0 : exportDefault.leadingComments;
|
|
5444
|
+
}
|
|
5445
|
+
if (!leadingComments && classDecl.type === 'ClassExpression') {
|
|
5446
|
+
// `/** @template K */ const Box = class {...}`: the comment lives on
|
|
5447
|
+
// the declaration, mirroring function-expression handling.
|
|
5448
|
+
var varDecl = this.findParentOfType(classDecl, 'VariableDeclaration');
|
|
5449
|
+
leadingComments = varDecl === null || varDecl === void 0 ? void 0 : varDecl.leadingComments;
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
if (!((_leadingComments = leadingComments) !== null && _leadingComments !== void 0 && _leadingComments.length)) {
|
|
5453
|
+
return;
|
|
5454
|
+
}
|
|
5455
|
+
var lastComment = leadingComments[leadingComments.length - 1];
|
|
5456
|
+
if (lastComment.type !== 'CommentBlock') {
|
|
5457
|
+
return;
|
|
5458
|
+
}
|
|
5459
|
+
return parseJSDocTemplates(lastComment.value);
|
|
5460
|
+
}
|
|
5461
|
+
/**
|
|
5462
|
+
* Reads the `@template` bindings off one enclosing function: its own
|
|
5463
|
+
* leading comment, resolving the same `export`/declarator wrappers the
|
|
5464
|
+
* node's own JSDoc lookup uses.
|
|
5465
|
+
* @param {Node} fnNode - The enclosing function-like node.
|
|
5466
|
+
* @returns {Record<string, any>|undefined} Its templates or undefined.
|
|
5467
|
+
*/
|
|
5468
|
+
}, {
|
|
5469
|
+
key: "functionTemplatesOf",
|
|
5470
|
+
value: function functionTemplatesOf(fnNode) {
|
|
5471
|
+
var _leadingComments2;
|
|
5472
|
+
var leadingComments;
|
|
5473
|
+
if (fnNode.type === 'FunctionDeclaration') {
|
|
5474
|
+
var _fnNode$leadingCommen, _this$findParentOfTyp;
|
|
5475
|
+
leadingComments = (_fnNode$leadingCommen = fnNode.leadingComments) !== null && _fnNode$leadingCommen !== void 0 ? _fnNode$leadingCommen : (_this$findParentOfTyp = this.findParentOfType(fnNode, 'ExportNamedDeclaration')) === null || _this$findParentOfTyp === void 0 ? void 0 : _this$findParentOfTyp.leadingComments;
|
|
5476
|
+
} else if (fnNode.type === 'FunctionExpression') {
|
|
5477
|
+
var _this$getLeadingComme;
|
|
5478
|
+
leadingComments = (_this$getLeadingComme = this.getLeadingCommentsNodeForFunctionExpression(fnNode)) === null || _this$getLeadingComme === void 0 ? void 0 : _this$getLeadingComme.leadingComments;
|
|
5479
|
+
} else if (fnNode.type === 'ArrowFunctionExpression') {
|
|
5480
|
+
var _this$getLeadingComme2;
|
|
5481
|
+
leadingComments = (_this$getLeadingComme2 = this.getLeadingCommentsNodeForArrowFunctionExpression(fnNode)) === null || _this$getLeadingComme2 === void 0 ? void 0 : _this$getLeadingComme2.leadingComments;
|
|
5482
|
+
} else {
|
|
5483
|
+
// ObjectMethod, ClassMethod, ClassPrivateMethod: docs sit on the node.
|
|
5484
|
+
leadingComments = fnNode.leadingComments;
|
|
5485
|
+
}
|
|
5486
|
+
if (!((_leadingComments2 = leadingComments) !== null && _leadingComments2 !== void 0 && _leadingComments2.length)) {
|
|
5487
|
+
return;
|
|
5488
|
+
}
|
|
5489
|
+
var lastComment = leadingComments[leadingComments.length - 1];
|
|
5490
|
+
if (lastComment.type !== 'CommentBlock') {
|
|
5491
|
+
return;
|
|
5492
|
+
}
|
|
5493
|
+
return parseJSDocTemplates(lastComment.value);
|
|
5494
|
+
}
|
|
5353
5495
|
/**
|
|
5354
5496
|
* Retrieves the name of a parameter from a Babel AST node.
|
|
5355
5497
|
*
|
|
@@ -5497,7 +5639,7 @@
|
|
|
5497
5639
|
stat.checked++;
|
|
5498
5640
|
return this.emitDefaultChecks(node, inferred, true);
|
|
5499
5641
|
}
|
|
5500
|
-
var
|
|
5642
|
+
var ownTemplates = jsdoc.templates,
|
|
5501
5643
|
params = jsdoc.params;
|
|
5502
5644
|
if (!params) {
|
|
5503
5645
|
console.warn("This should never happen, please check your input code.", this.getLeadingComment(node), {
|
|
@@ -5506,6 +5648,11 @@
|
|
|
5506
5648
|
stat.unchecked++;
|
|
5507
5649
|
return '';
|
|
5508
5650
|
}
|
|
5651
|
+
// Lexically enclosing `@template`s (classes and functions) scope over
|
|
5652
|
+
// this node: merge them under method-local templates so `K` in
|
|
5653
|
+
// `@param {K}` resolves jointly. Inner scopes shadow outer ones.
|
|
5654
|
+
var scopeTemplates = this.getScopeTemplates(node);
|
|
5655
|
+
var templates = scopeTemplates ? _objectSpread2(_objectSpread2({}, scopeTemplates), ownTemplates) : ownTemplates;
|
|
5509
5656
|
stat.checked++;
|
|
5510
5657
|
var spaces = this.spaces;
|
|
5511
5658
|
var out = '';
|
|
@@ -6593,6 +6740,11 @@
|
|
|
6593
6740
|
argument: keyofArg
|
|
6594
6741
|
};
|
|
6595
6742
|
}
|
|
6743
|
+
if (node.operator === 'unique') {
|
|
6744
|
+
// `unique symbol` is a symbol at runtime; uniqueness refers to a
|
|
6745
|
+
// specific declaration which we cannot track here.
|
|
6746
|
+
return toSourceBabelTS(node.typeAnnotation);
|
|
6747
|
+
}
|
|
6596
6748
|
console.warn('unimplemented TSTypeOperator', node.operator);
|
|
6597
6749
|
return 'any';
|
|
6598
6750
|
case 'TSQualifiedName':
|
package/index.mjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { parse } from '@babel/parser';
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
|
|
4
|
+
function _extends() {
|
|
5
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
6
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
7
|
+
var source = arguments[i];
|
|
8
|
+
for (var key in source) {
|
|
9
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
10
|
+
target[key] = source[key];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return target;
|
|
15
|
+
};
|
|
16
|
+
return _extends.apply(this, arguments);
|
|
17
|
+
}
|
|
18
|
+
|
|
4
19
|
/**
|
|
5
20
|
* @typedef DocType
|
|
6
21
|
* @property {boolean} optional - Type is optional.
|
|
@@ -406,6 +421,11 @@ function toSourceTS(node) {
|
|
|
406
421
|
// readonly erased at runtime, same shape as the inner type.
|
|
407
422
|
return toSourceTS(node.type);
|
|
408
423
|
}
|
|
424
|
+
if (node.operator === UniqueKeyword) {
|
|
425
|
+
// `unique symbol` is a symbol at runtime; the uniqueness refers to
|
|
426
|
+
// a specific declaration which we cannot track here.
|
|
427
|
+
return toSourceTS(node.type);
|
|
428
|
+
}
|
|
409
429
|
console.warn("unimplemented TypeOperator", node);
|
|
410
430
|
return 'any';
|
|
411
431
|
case TypeReference:
|
|
@@ -1119,7 +1139,7 @@ function expandTypeDepFree(type) {
|
|
|
1119
1139
|
return expandTypeDepFree(type.slice(9).trim());
|
|
1120
1140
|
}
|
|
1121
1141
|
if (type === 'unique symbol') {
|
|
1122
|
-
return '
|
|
1142
|
+
return 'symbol';
|
|
1123
1143
|
}
|
|
1124
1144
|
// Conditionals before nullable: `A extends B ? C : D?` must keep the
|
|
1125
1145
|
// nullable on the false branch, not lift it over the whole condition.
|
|
@@ -1365,21 +1385,6 @@ function expandTypeDepFree(type) {
|
|
|
1365
1385
|
return type;
|
|
1366
1386
|
}
|
|
1367
1387
|
|
|
1368
|
-
function _extends() {
|
|
1369
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
1370
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
1371
|
-
var source = arguments[i];
|
|
1372
|
-
for (var key in source) {
|
|
1373
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1374
|
-
target[key] = source[key];
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
return target;
|
|
1379
|
-
};
|
|
1380
|
-
return _extends.apply(this, arguments);
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
1388
|
/**
|
|
1384
1389
|
* Extracts the parameter name and its optionality from a JSDoc parameter string.
|
|
1385
1390
|
*
|
|
@@ -2303,6 +2308,12 @@ function parseJSDocTemplates(src, expandType = expandTypeDepFree) {
|
|
|
2303
2308
|
const matches = [...src.matchAll(regexTemplateTyped)];
|
|
2304
2309
|
/** @type {Record<string, ExpandTypeReturnType>} */
|
|
2305
2310
|
const templates = Object.create(null);
|
|
2311
|
+
// `@template {Constraint} [Name=Default]` (or `[Name]`): constraint wins,
|
|
2312
|
+
// the default only matters when nothing is inferred.
|
|
2313
|
+
const regexTemplateConstrainedDefault = /@template \{(.*?)\}\s*\[([a-zA-Z0-9_$]+)(?:=([^\]]+))?\]/g;
|
|
2314
|
+
for (const match of src.matchAll(regexTemplateConstrainedDefault)) {
|
|
2315
|
+
templates[match[2]] = expandType(match[1].trim());
|
|
2316
|
+
}
|
|
2306
2317
|
matches.forEach(_ => {
|
|
2307
2318
|
const type = expandType(_[1].trim());
|
|
2308
2319
|
const name = _[2].trim();
|
|
@@ -4515,6 +4526,10 @@ class Stringifier {
|
|
|
4515
4526
|
* @property {string} [filename] - The name of a file to which the instance pertains.
|
|
4516
4527
|
* @property {boolean} [addHeader] - Whether to add import declarations headers. Defaults to true.
|
|
4517
4528
|
* @property {string[]} [ignoreLocations] - Ignore these locations because they are known false-positives.
|
|
4529
|
+
* @property {string} [projectVersion] - Host project version funneled into
|
|
4530
|
+
* the emitted header via `setProjectVersion(...)`, so `Download log` meta
|
|
4531
|
+
* identifies the app build. Bundler plugins resolve it from their own
|
|
4532
|
+
* option or the host package.json.
|
|
4518
4533
|
*/
|
|
4519
4534
|
class Asserter extends Stringifier {
|
|
4520
4535
|
/**
|
|
@@ -4527,7 +4542,8 @@ class Asserter extends Stringifier {
|
|
|
4527
4542
|
expandType = expandTypeDepFree,
|
|
4528
4543
|
filename,
|
|
4529
4544
|
addHeader = true,
|
|
4530
|
-
ignoreLocations = []
|
|
4545
|
+
ignoreLocations = [],
|
|
4546
|
+
projectVersion
|
|
4531
4547
|
} = {}) {
|
|
4532
4548
|
super();
|
|
4533
4549
|
/** @type {Record<string, Stat>} */
|
|
@@ -4592,6 +4608,7 @@ class Asserter extends Stringifier {
|
|
|
4592
4608
|
this.filename = filename;
|
|
4593
4609
|
this.addHeader = addHeader;
|
|
4594
4610
|
this.ignoreLocations = ignoreLocations;
|
|
4611
|
+
this.projectVersion = projectVersion;
|
|
4595
4612
|
}
|
|
4596
4613
|
/**
|
|
4597
4614
|
* We expand type-asserted ArrowFunctionExpressions in order to add type assertions.
|
|
@@ -4694,9 +4711,16 @@ class Asserter extends Stringifier {
|
|
|
4694
4711
|
if (this.validateDivision) {
|
|
4695
4712
|
header += ", validateDivision";
|
|
4696
4713
|
}
|
|
4697
|
-
header += ", registerTypedef, registerClass, registerImportNamespaceSpecifier
|
|
4714
|
+
header += ", registerTypedef, registerClass, registerImportNamespaceSpecifier";
|
|
4715
|
+
if (this.projectVersion !== undefined && this.projectVersion !== null) {
|
|
4716
|
+
header += ", setProjectVersion";
|
|
4717
|
+
}
|
|
4718
|
+
header += "} from '@runtime-type-inspector/runtime';\n";
|
|
4698
4719
|
// Prevent tree-shaking in UMD build so we can always "add a breakpoint here".
|
|
4699
4720
|
header += "export * from '@runtime-type-inspector/runtime';\n";
|
|
4721
|
+
if (this.projectVersion !== undefined && this.projectVersion !== null) {
|
|
4722
|
+
header += `setProjectVersion(${JSON.stringify(this.projectVersion)});\n`;
|
|
4723
|
+
}
|
|
4700
4724
|
return header;
|
|
4701
4725
|
}
|
|
4702
4726
|
/**
|
|
@@ -4903,6 +4927,107 @@ class Asserter extends Stringifier {
|
|
|
4903
4927
|
params
|
|
4904
4928
|
};
|
|
4905
4929
|
}
|
|
4930
|
+
/**
|
|
4931
|
+
* Reads `@template` bindings from every lexically enclosing scope, outer
|
|
4932
|
+
* to inner: classes (declaration or expression, incl. `export` wrappers)
|
|
4933
|
+
* and functions with their own `@template` tags. Class templates scope
|
|
4934
|
+
* over the constructor and methods, mirroring TypeScript:
|
|
4935
|
+
* `new Asset('x', ...)` infers `K` from the constructor's `@param {K}`
|
|
4936
|
+
* occurrences. Inner scopes shadow outer names on conflict.
|
|
4937
|
+
* @param {Node} node - The function or block node being checked.
|
|
4938
|
+
* @returns {Record<string, any>|undefined} Merged scope templates or undefined.
|
|
4939
|
+
*/
|
|
4940
|
+
getScopeTemplates(node) {
|
|
4941
|
+
let fnNode = node;
|
|
4942
|
+
if (node.type === 'BlockStatement') {
|
|
4943
|
+
fnNode = this.parent;
|
|
4944
|
+
}
|
|
4945
|
+
const anchorIdx = this.parents.findLastIndex(_ => _ === node);
|
|
4946
|
+
if (anchorIdx === -1) {
|
|
4947
|
+
return;
|
|
4948
|
+
}
|
|
4949
|
+
let merged;
|
|
4950
|
+
for (let i = 0; i <= anchorIdx; i++) {
|
|
4951
|
+
const ancestor = this.parents[i];
|
|
4952
|
+
if (!ancestor || ancestor === fnNode) {
|
|
4953
|
+
// Never inherit the node's own bindings: they merge separately and win.
|
|
4954
|
+
continue;
|
|
4955
|
+
}
|
|
4956
|
+
let templates;
|
|
4957
|
+
if (ancestor.type === 'ClassDeclaration' || ancestor.type === 'ClassExpression') {
|
|
4958
|
+
templates = this.classTemplatesOf(ancestor);
|
|
4959
|
+
} else if (nodeIsFunctionLike(ancestor)) {
|
|
4960
|
+
templates = this.functionTemplatesOf(ancestor);
|
|
4961
|
+
}
|
|
4962
|
+
if (templates) {
|
|
4963
|
+
merged = _extends({}, merged, templates);
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
return merged;
|
|
4967
|
+
}
|
|
4968
|
+
/**
|
|
4969
|
+
* Reads the `@template` bindings off one class node.
|
|
4970
|
+
* @param {Node} classDecl - The ClassDeclaration or ClassExpression node.
|
|
4971
|
+
* @returns {Record<string, any>|undefined} Its templates or undefined.
|
|
4972
|
+
*/
|
|
4973
|
+
classTemplatesOf(classDecl) {
|
|
4974
|
+
var _leadingComments;
|
|
4975
|
+
let leadingComments = classDecl.leadingComments;
|
|
4976
|
+
if (!leadingComments) {
|
|
4977
|
+
const exportNamed = this.findParentOfType(classDecl, 'ExportNamedDeclaration');
|
|
4978
|
+
leadingComments = exportNamed == null ? void 0 : exportNamed.leadingComments;
|
|
4979
|
+
if (!leadingComments) {
|
|
4980
|
+
const exportDefault = this.findParentOfType(classDecl, 'ExportDefaultDeclaration');
|
|
4981
|
+
leadingComments = exportDefault == null ? void 0 : exportDefault.leadingComments;
|
|
4982
|
+
}
|
|
4983
|
+
if (!leadingComments && classDecl.type === 'ClassExpression') {
|
|
4984
|
+
// `/** @template K */ const Box = class {...}`: the comment lives on
|
|
4985
|
+
// the declaration, mirroring function-expression handling.
|
|
4986
|
+
const varDecl = this.findParentOfType(classDecl, 'VariableDeclaration');
|
|
4987
|
+
leadingComments = varDecl == null ? void 0 : varDecl.leadingComments;
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
if (!((_leadingComments = leadingComments) != null && _leadingComments.length)) {
|
|
4991
|
+
return;
|
|
4992
|
+
}
|
|
4993
|
+
const lastComment = leadingComments[leadingComments.length - 1];
|
|
4994
|
+
if (lastComment.type !== 'CommentBlock') {
|
|
4995
|
+
return;
|
|
4996
|
+
}
|
|
4997
|
+
return parseJSDocTemplates(lastComment.value);
|
|
4998
|
+
}
|
|
4999
|
+
/**
|
|
5000
|
+
* Reads the `@template` bindings off one enclosing function: its own
|
|
5001
|
+
* leading comment, resolving the same `export`/declarator wrappers the
|
|
5002
|
+
* node's own JSDoc lookup uses.
|
|
5003
|
+
* @param {Node} fnNode - The enclosing function-like node.
|
|
5004
|
+
* @returns {Record<string, any>|undefined} Its templates or undefined.
|
|
5005
|
+
*/
|
|
5006
|
+
functionTemplatesOf(fnNode) {
|
|
5007
|
+
var _leadingComments2;
|
|
5008
|
+
let leadingComments;
|
|
5009
|
+
if (fnNode.type === 'FunctionDeclaration') {
|
|
5010
|
+
var _fnNode$leadingCommen, _this$findParentOfTyp;
|
|
5011
|
+
leadingComments = (_fnNode$leadingCommen = fnNode.leadingComments) != null ? _fnNode$leadingCommen : (_this$findParentOfTyp = this.findParentOfType(fnNode, 'ExportNamedDeclaration')) == null ? void 0 : _this$findParentOfTyp.leadingComments;
|
|
5012
|
+
} else if (fnNode.type === 'FunctionExpression') {
|
|
5013
|
+
var _this$getLeadingComme;
|
|
5014
|
+
leadingComments = (_this$getLeadingComme = this.getLeadingCommentsNodeForFunctionExpression(fnNode)) == null ? void 0 : _this$getLeadingComme.leadingComments;
|
|
5015
|
+
} else if (fnNode.type === 'ArrowFunctionExpression') {
|
|
5016
|
+
var _this$getLeadingComme2;
|
|
5017
|
+
leadingComments = (_this$getLeadingComme2 = this.getLeadingCommentsNodeForArrowFunctionExpression(fnNode)) == null ? void 0 : _this$getLeadingComme2.leadingComments;
|
|
5018
|
+
} else {
|
|
5019
|
+
// ObjectMethod, ClassMethod, ClassPrivateMethod: docs sit on the node.
|
|
5020
|
+
leadingComments = fnNode.leadingComments;
|
|
5021
|
+
}
|
|
5022
|
+
if (!((_leadingComments2 = leadingComments) != null && _leadingComments2.length)) {
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
5025
|
+
const lastComment = leadingComments[leadingComments.length - 1];
|
|
5026
|
+
if (lastComment.type !== 'CommentBlock') {
|
|
5027
|
+
return;
|
|
5028
|
+
}
|
|
5029
|
+
return parseJSDocTemplates(lastComment.value);
|
|
5030
|
+
}
|
|
4906
5031
|
/**
|
|
4907
5032
|
* Retrieves the name of a parameter from a Babel AST node.
|
|
4908
5033
|
*
|
|
@@ -5051,7 +5176,7 @@ class Asserter extends Stringifier {
|
|
|
5051
5176
|
return this.emitDefaultChecks(node, inferred, true);
|
|
5052
5177
|
}
|
|
5053
5178
|
const {
|
|
5054
|
-
templates,
|
|
5179
|
+
templates: ownTemplates,
|
|
5055
5180
|
params
|
|
5056
5181
|
} = jsdoc;
|
|
5057
5182
|
if (!params) {
|
|
@@ -5061,6 +5186,11 @@ class Asserter extends Stringifier {
|
|
|
5061
5186
|
stat.unchecked++;
|
|
5062
5187
|
return '';
|
|
5063
5188
|
}
|
|
5189
|
+
// Lexically enclosing `@template`s (classes and functions) scope over
|
|
5190
|
+
// this node: merge them under method-local templates so `K` in
|
|
5191
|
+
// `@param {K}` resolves jointly. Inner scopes shadow outer ones.
|
|
5192
|
+
const scopeTemplates = this.getScopeTemplates(node);
|
|
5193
|
+
const templates = scopeTemplates ? _extends({}, scopeTemplates, ownTemplates) : ownTemplates;
|
|
5064
5194
|
stat.checked++;
|
|
5065
5195
|
const {
|
|
5066
5196
|
spaces
|
|
@@ -6058,6 +6188,11 @@ function toSourceBabelTS(node) {
|
|
|
6058
6188
|
argument: keyofArg
|
|
6059
6189
|
};
|
|
6060
6190
|
}
|
|
6191
|
+
if (node.operator === 'unique') {
|
|
6192
|
+
// `unique symbol` is a symbol at runtime; uniqueness refers to a
|
|
6193
|
+
// specific declaration which we cannot track here.
|
|
6194
|
+
return toSourceBabelTS(node.typeAnnotation);
|
|
6195
|
+
}
|
|
6061
6196
|
console.warn('unimplemented TSTypeOperator', node.operator);
|
|
6062
6197
|
return 'any';
|
|
6063
6198
|
case 'TSQualifiedName':
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"ts2js": "ts2js.js"
|
|
5
5
|
},
|
|
6
6
|
"name": "@runtime-type-inspector/transpiler",
|
|
7
|
-
"version": "5.0.
|
|
7
|
+
"version": "5.0.5",
|
|
8
8
|
"description": "Validating JSDoc types at runtime for high-quality types - Trust is good, control is better.",
|
|
9
9
|
"main": "index.cjs",
|
|
10
10
|
"module": "index.mjs",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"homepage": "https://github.com/kungfooman/RuntimeTypeInspector.js#readme",
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@babel/parser": "^7.23.0",
|
|
25
|
-
"@runtime-type-inspector/runtime": "^5.0.
|
|
25
|
+
"@runtime-type-inspector/runtime": "^5.0.5",
|
|
26
26
|
"typescript": "^5.1.6"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|