@runtime-type-inspector/transpiler 5.0.1 → 5.0.2
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 +1509 -288
- package/index.mjs +1406 -280
- package/package.json +2 -2
package/index.cjs
CHANGED
|
@@ -427,6 +427,7 @@
|
|
|
427
427
|
PropertySignature = _ts$SyntaxKind.PropertySignature,
|
|
428
428
|
StringKeyword = _ts$SyntaxKind.StringKeyword,
|
|
429
429
|
StringLiteral = _ts$SyntaxKind.StringLiteral,
|
|
430
|
+
SymbolKeyword = _ts$SyntaxKind.SymbolKeyword,
|
|
430
431
|
ThisType = _ts$SyntaxKind.ThisType,
|
|
431
432
|
TupleType = _ts$SyntaxKind.TupleType,
|
|
432
433
|
TypeLiteral = _ts$SyntaxKind.TypeLiteral,
|
|
@@ -453,6 +454,8 @@
|
|
|
453
454
|
var ConstructorType = _ts$SyntaxKind.ConstructorType,
|
|
454
455
|
NamedTupleMember = _ts$SyntaxKind.NamedTupleMember,
|
|
455
456
|
MappedType = _ts$SyntaxKind.MappedType,
|
|
457
|
+
MinusToken = _ts$SyntaxKind.MinusToken,
|
|
458
|
+
PlusToken = _ts$SyntaxKind.PlusToken,
|
|
456
459
|
TypeParameter = _ts$SyntaxKind.TypeParameter,
|
|
457
460
|
QualifiedName = _ts$SyntaxKind.QualifiedName,
|
|
458
461
|
TemplateLiteralType = _ts$SyntaxKind.TemplateLiteralType,
|
|
@@ -565,12 +568,26 @@
|
|
|
565
568
|
// For example: {[K in TaskType]: InstanceType etc.
|
|
566
569
|
var iterable = toSourceTS(parameter.constraint); // TaskType
|
|
567
570
|
var element = toSourceTS(parameter.name); // K
|
|
568
|
-
|
|
571
|
+
var out = {
|
|
569
572
|
type: 'mapping',
|
|
570
573
|
iterable: iterable,
|
|
571
574
|
element: element,
|
|
572
575
|
result: result
|
|
573
576
|
};
|
|
577
|
+
if (node.nameType) {
|
|
578
|
+
// `as` key remapping, e.g. {[K in keyof T as K extends string ? K : never]: ...}
|
|
579
|
+
out.nameType = toSourceTS(node.nameType);
|
|
580
|
+
}
|
|
581
|
+
// Modifiers: `-?` strips optionality, `+?`/`?` force it;
|
|
582
|
+
// `-readonly` strips readonly, `+readonly`/`readonly` force it.
|
|
583
|
+
// Absent modifiers preserve the source behavior (see createTypeFromMapping).
|
|
584
|
+
if (node.questionToken) {
|
|
585
|
+
out.question = node.questionToken.kind === MinusToken ? '-' : node.questionToken.kind === PlusToken ? '+' : '?';
|
|
586
|
+
}
|
|
587
|
+
if (node.readonlyToken) {
|
|
588
|
+
out.readonly = node.readonlyToken.kind === MinusToken ? '-' : node.readonlyToken.kind === PlusToken ? '+' : 'readonly';
|
|
589
|
+
}
|
|
590
|
+
return out;
|
|
574
591
|
}
|
|
575
592
|
console.warn("MappedType: expected TypeParameter");
|
|
576
593
|
return 'transpiler-error';
|
|
@@ -797,6 +814,15 @@
|
|
|
797
814
|
optional: true
|
|
798
815
|
};
|
|
799
816
|
}
|
|
817
|
+
if (Array.isArray(member.modifiers) && member.modifiers.some(function (modifier) {
|
|
818
|
+
return modifier.kind === ReadonlyKeyword;
|
|
819
|
+
})) {
|
|
820
|
+
// Tracked for IfEquals-style comparisons; ignored by validation.
|
|
821
|
+
if (_type && _typeof(_type) === 'object') _type.readonly = true;else _type = {
|
|
822
|
+
type: _type,
|
|
823
|
+
readonly: true
|
|
824
|
+
};
|
|
825
|
+
}
|
|
800
826
|
properties[_name2] = _type;
|
|
801
827
|
} else {
|
|
802
828
|
console.warn('TypeLiteral: unhandled member', member);
|
|
@@ -856,6 +882,7 @@
|
|
|
856
882
|
case AnyKeyword:
|
|
857
883
|
case BooleanKeyword:
|
|
858
884
|
case StringKeyword:
|
|
885
|
+
case SymbolKeyword:
|
|
859
886
|
case NeverKeyword:
|
|
860
887
|
case NullKeyword:
|
|
861
888
|
case NumberKeyword:
|
|
@@ -936,6 +963,7 @@
|
|
|
936
963
|
*/
|
|
937
964
|
/**
|
|
938
965
|
* Splits a string by a delimiter, ignoring delimiters nested inside <>, {}, [], ().
|
|
966
|
+
* Quote-aware: delimiters inside '...', "..." or `...` never split.
|
|
939
967
|
* @param {string} str - The string to split.
|
|
940
968
|
* @param {string} delimiter - Single character delimiter.
|
|
941
969
|
* @returns {string[]} Top-level split parts.
|
|
@@ -946,28 +974,148 @@
|
|
|
946
974
|
var depthCurly = 0;
|
|
947
975
|
var depthSquare = 0;
|
|
948
976
|
var depthParen = 0;
|
|
977
|
+
var inSingle = false;
|
|
978
|
+
var inDouble = false;
|
|
979
|
+
var inBacktick = false;
|
|
949
980
|
var current = '';
|
|
950
|
-
var
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
981
|
+
for (var i = 0; i < str.length; i++) {
|
|
982
|
+
var c = str[i];
|
|
983
|
+
var prev = i > 0 ? str[i - 1] : '';
|
|
984
|
+
if (c === "'" && !inDouble && !inBacktick && prev !== '\\') inSingle = !inSingle;else if (c === '"' && !inSingle && !inBacktick && prev !== '\\') inDouble = !inDouble;else if (c === '`' && !inSingle && !inDouble && prev !== '\\') inBacktick = !inBacktick;
|
|
985
|
+
var inQuote = inSingle || inDouble || inBacktick;
|
|
986
|
+
if (!inQuote) {
|
|
955
987
|
if (c === '<') depthAngle++;else if (c === '>') depthAngle--;else if (c === '{') depthCurly++;else if (c === '}') depthCurly--;else if (c === '[') depthSquare++;else if (c === ']') depthSquare--;else if (c === '(') depthParen++;else if (c === ')') depthParen--;
|
|
956
|
-
if (c === delimiter && depthAngle === 0 && depthCurly === 0 && depthSquare === 0 && depthParen === 0) {
|
|
957
|
-
parts.push(current);
|
|
958
|
-
current = '';
|
|
959
|
-
} else {
|
|
960
|
-
current += c;
|
|
961
|
-
}
|
|
962
988
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
989
|
+
if (c === delimiter && !inQuote && depthAngle === 0 && depthCurly === 0 && depthSquare === 0 && depthParen === 0) {
|
|
990
|
+
parts.push(current);
|
|
991
|
+
current = '';
|
|
992
|
+
} else {
|
|
993
|
+
current += c;
|
|
994
|
+
}
|
|
967
995
|
}
|
|
968
996
|
parts.push(current);
|
|
969
997
|
return parts;
|
|
970
998
|
}
|
|
999
|
+
/**
|
|
1000
|
+
* Depth state at a given index, quote-aware.
|
|
1001
|
+
* @param {string} str - The string to scan.
|
|
1002
|
+
* @param {number} upto - Exclusive end index.
|
|
1003
|
+
* @returns {{angle: number, curly: number, square: number, paren: number, quote: boolean}} Depths.
|
|
1004
|
+
*/
|
|
1005
|
+
function depthsAt(str, upto) {
|
|
1006
|
+
var angle = 0;
|
|
1007
|
+
var curly = 0;
|
|
1008
|
+
var square = 0;
|
|
1009
|
+
var paren = 0;
|
|
1010
|
+
var inSingle = false;
|
|
1011
|
+
var inDouble = false;
|
|
1012
|
+
var inBacktick = false;
|
|
1013
|
+
for (var i = 0; i < upto; i++) {
|
|
1014
|
+
var c = str[i];
|
|
1015
|
+
var prev = i > 0 ? str[i - 1] : '';
|
|
1016
|
+
if (c === "'" && !inDouble && !inBacktick && prev !== '\\') inSingle = !inSingle;else if (c === '"' && !inSingle && !inBacktick && prev !== '\\') inDouble = !inDouble;else if (c === '`' && !inSingle && !inDouble && prev !== '\\') inBacktick = !inBacktick;
|
|
1017
|
+
var inQuote = inSingle || inDouble || inBacktick;
|
|
1018
|
+
if (inQuote) continue;
|
|
1019
|
+
if (c === '<') angle++;else if (c === '>') angle--;else if (c === '{') curly++;else if (c === '}') curly--;else if (c === '[') square++;else if (c === ']') square--;else if (c === '(') paren++;else if (c === ')') paren--;
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
angle: angle,
|
|
1023
|
+
curly: curly,
|
|
1024
|
+
square: square,
|
|
1025
|
+
paren: paren,
|
|
1026
|
+
quote: inSingle || inDouble || inBacktick
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Finds a keyword (e.g. `in`, `as`, `extends`) at top level, outside brackets/quotes.
|
|
1031
|
+
* @param {string} str - The string to search.
|
|
1032
|
+
* @param {string} keyword - Keyword without surrounding spaces.
|
|
1033
|
+
* @returns {number} Start index or -1.
|
|
1034
|
+
*/
|
|
1035
|
+
function findTopLevelKeyword(str, keyword) {
|
|
1036
|
+
var isWord = function isWord(c) {
|
|
1037
|
+
return /[A-Za-z0-9_$]/.test(c);
|
|
1038
|
+
};
|
|
1039
|
+
for (var i = 0; i <= str.length - keyword.length; i++) {
|
|
1040
|
+
if (str.slice(i, i + keyword.length) !== keyword) continue;
|
|
1041
|
+
var before = i > 0 ? str[i - 1] : ' ';
|
|
1042
|
+
var after = i + keyword.length < str.length ? str[i + keyword.length] : ' ';
|
|
1043
|
+
if (isWord(before) || isWord(after)) continue;
|
|
1044
|
+
var d = depthsAt(str, i);
|
|
1045
|
+
if (d.angle === 0 && d.curly === 0 && d.square === 0 && d.paren === 0 && !d.quote) {
|
|
1046
|
+
// Ensure remainder after keyword is also top-level (keyword itself not quoted).
|
|
1047
|
+
var d2 = depthsAt(str, i + keyword.length);
|
|
1048
|
+
if (!d2.quote) return i;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return -1;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Finds a single-char delimiter at top level, outside brackets/quotes.
|
|
1055
|
+
* @param {string} str - The string to search.
|
|
1056
|
+
* @param {string} delimiter - Single character.
|
|
1057
|
+
* @param {number} from - Start index.
|
|
1058
|
+
* @returns {number} Index or -1.
|
|
1059
|
+
*/
|
|
1060
|
+
function findTopLevelChar(str, delimiter) {
|
|
1061
|
+
var from = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
1062
|
+
var angle = 0;
|
|
1063
|
+
var curly = 0;
|
|
1064
|
+
var square = 0;
|
|
1065
|
+
var paren = 0;
|
|
1066
|
+
var inSingle = false;
|
|
1067
|
+
var inDouble = false;
|
|
1068
|
+
var inBacktick = false;
|
|
1069
|
+
for (var i = 0; i < str.length; i++) {
|
|
1070
|
+
var c = str[i];
|
|
1071
|
+
// Check at depths *before* the current char, so `[` itself is findable.
|
|
1072
|
+
var inQuoteBefore = inSingle || inDouble || inBacktick;
|
|
1073
|
+
if (i >= from && c === delimiter && !inQuoteBefore && angle === 0 && curly === 0 && square === 0 && paren === 0) {
|
|
1074
|
+
return i;
|
|
1075
|
+
}
|
|
1076
|
+
var prev = i > 0 ? str[i - 1] : '';
|
|
1077
|
+
if (c === "'" && !inDouble && !inBacktick && prev !== '\\') inSingle = !inSingle;else if (c === '"' && !inSingle && !inBacktick && prev !== '\\') inDouble = !inDouble;else if (c === '`' && !inSingle && !inDouble && prev !== '\\') inBacktick = !inBacktick;
|
|
1078
|
+
var inQuote = inSingle || inDouble || inBacktick;
|
|
1079
|
+
if (!inQuote) {
|
|
1080
|
+
if (c === '<') angle++;else if (c === '>') angle--;else if (c === '{') curly++;else if (c === '}') curly--;else if (c === '[') square++;else if (c === ']') square--;else if (c === '(') paren++;else if (c === ')') paren--;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
return -1;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Strips balanced outer parens, e.g. `(( T ))` -> `T`.
|
|
1087
|
+
* @param {string} type - Trimmed type string.
|
|
1088
|
+
* @returns {string} Unwrapped type.
|
|
1089
|
+
*/
|
|
1090
|
+
function stripOuterParens(type) {
|
|
1091
|
+
var changed = true;
|
|
1092
|
+
while (changed) {
|
|
1093
|
+
changed = false;
|
|
1094
|
+
if (type.length >= 2 && type[0] === '(' && type[type.length - 1] === ')') {
|
|
1095
|
+
var depth = 0;
|
|
1096
|
+
var balanced = true;
|
|
1097
|
+
var inSingle = false;
|
|
1098
|
+
var inDouble = false;
|
|
1099
|
+
for (var i = 0; i < type.length; i++) {
|
|
1100
|
+
var c = type[i];
|
|
1101
|
+
if (c === "'" && !inDouble && type[i - 1] !== '\\') inSingle = !inSingle;else if (c === '"' && !inSingle && type[i - 1] !== '\\') inDouble = !inDouble;else if (!inSingle && !inDouble) {
|
|
1102
|
+
if (c === '(') depth++;else if (c === ')') {
|
|
1103
|
+
depth--;
|
|
1104
|
+
if (depth === 0 && i !== type.length - 1) {
|
|
1105
|
+
balanced = false;
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (balanced && depth === 0) {
|
|
1112
|
+
type = type.slice(1, -1).trim();
|
|
1113
|
+
changed = true;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
return type;
|
|
1118
|
+
}
|
|
971
1119
|
/**
|
|
972
1120
|
* Parses `Name<A, B>` into name + raw arg strings, respecting nested brackets.
|
|
973
1121
|
* Returns undefined when input isn't a generic reference.
|
|
@@ -1012,6 +1160,190 @@
|
|
|
1012
1160
|
args: args
|
|
1013
1161
|
};
|
|
1014
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Parses `{[K in Iterable as NameType]?: Result}` mapped syntax.
|
|
1165
|
+
* Returns undefined when input isn't a mapped type.
|
|
1166
|
+
* @param {string} type - Trimmed type string starting with `{`.
|
|
1167
|
+
* @returns {object|undefined} Mapping struct with raw strings, or undefined.
|
|
1168
|
+
*/
|
|
1169
|
+
function parseMappedRaw(type) {
|
|
1170
|
+
if (type[0] !== '{' || type[type.length - 1] !== '}') {
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
var inner = type.slice(1, -1).trim();
|
|
1174
|
+
var readonly;
|
|
1175
|
+
if (inner.startsWith('-readonly') && (inner[9] === ' ' || inner[9] === '[')) {
|
|
1176
|
+
readonly = '-';
|
|
1177
|
+
inner = inner.slice(9).trim();
|
|
1178
|
+
} else if (inner.startsWith('+readonly') && (inner[9] === ' ' || inner[9] === '[')) {
|
|
1179
|
+
readonly = '+';
|
|
1180
|
+
inner = inner.slice(9).trim();
|
|
1181
|
+
} else if (inner.startsWith('readonly') && (inner[8] === ' ' || inner[8] === '[')) {
|
|
1182
|
+
readonly = 'readonly';
|
|
1183
|
+
inner = inner.slice(8).trim();
|
|
1184
|
+
}
|
|
1185
|
+
if (inner[0] !== '[') {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
// Find matching `]` for the opening `[`, quote-aware.
|
|
1189
|
+
var square = 0;
|
|
1190
|
+
var inSingle = false;
|
|
1191
|
+
var inDouble = false;
|
|
1192
|
+
var inBacktick = false;
|
|
1193
|
+
var close = -1;
|
|
1194
|
+
for (var i = 0; i < inner.length; i++) {
|
|
1195
|
+
var c = inner[i];
|
|
1196
|
+
var prev = i > 0 ? inner[i - 1] : '';
|
|
1197
|
+
if (c === "'" && !inDouble && !inBacktick && prev !== '\\') inSingle = !inSingle;else if (c === '"' && !inSingle && !inBacktick && prev !== '\\') inDouble = !inDouble;else if (c === '`' && !inSingle && !inDouble && prev !== '\\') inBacktick = !inBacktick;else if (!inSingle && !inDouble && !inBacktick) {
|
|
1198
|
+
if (c === '[') square++;else if (c === ']') {
|
|
1199
|
+
square--;
|
|
1200
|
+
if (square === 0) {
|
|
1201
|
+
close = i;
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
if (close === -1) {
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
var bracket = inner.slice(1, close);
|
|
1211
|
+
var rest = inner.slice(close + 1).trim();
|
|
1212
|
+
var question;
|
|
1213
|
+
if (rest.startsWith('-?')) {
|
|
1214
|
+
question = '-';
|
|
1215
|
+
rest = rest.slice(2).trim();
|
|
1216
|
+
} else if (rest.startsWith('+?')) {
|
|
1217
|
+
question = '+';
|
|
1218
|
+
rest = rest.slice(2).trim();
|
|
1219
|
+
} else if (rest.startsWith('?')) {
|
|
1220
|
+
question = '?';
|
|
1221
|
+
rest = rest.slice(1).trim();
|
|
1222
|
+
}
|
|
1223
|
+
if (!rest.startsWith(':')) {
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
var resultRaw = rest.slice(1).trim();
|
|
1227
|
+
if (!resultRaw) {
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
var inIdx = findTopLevelKeyword(bracket, 'in');
|
|
1231
|
+
if (inIdx === -1) {
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
var element = bracket.slice(0, inIdx).trim();
|
|
1235
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(element)) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
var afterIn = bracket.slice(inIdx + 2).trim();
|
|
1239
|
+
if (!afterIn) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
var asIdx = findTopLevelKeyword(afterIn, 'as');
|
|
1243
|
+
var iterableRaw = afterIn;
|
|
1244
|
+
var nameRaw;
|
|
1245
|
+
if (asIdx !== -1) {
|
|
1246
|
+
iterableRaw = afterIn.slice(0, asIdx).trim();
|
|
1247
|
+
nameRaw = afterIn.slice(asIdx + 2).trim();
|
|
1248
|
+
if (!iterableRaw || !nameRaw) {
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return {
|
|
1253
|
+
element: element,
|
|
1254
|
+
iterableRaw: iterableRaw,
|
|
1255
|
+
nameRaw: nameRaw,
|
|
1256
|
+
resultRaw: resultRaw,
|
|
1257
|
+
question: question,
|
|
1258
|
+
readonly: readonly
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Splits `Check extends Extends ? True : False` at top level.
|
|
1263
|
+
* Returns undefined when input isn't a conditional type.
|
|
1264
|
+
* @param {string} type - Trimmed type string.
|
|
1265
|
+
* @returns {{check: string, extends_: string, true_: string, false_: string}|undefined} Raw parts.
|
|
1266
|
+
*/
|
|
1267
|
+
function parseConditionRaw(type) {
|
|
1268
|
+
var qIdx = findTopLevelChar(type, '?');
|
|
1269
|
+
if (qIdx === -1) {
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
var beforeQ = type.slice(0, qIdx);
|
|
1273
|
+
var afterQ = type.slice(qIdx + 1);
|
|
1274
|
+
var extIdx = findTopLevelKeyword(beforeQ, 'extends');
|
|
1275
|
+
if (extIdx === -1) {
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
var colonIdx = findTopLevelChar(afterQ, ':');
|
|
1279
|
+
if (colonIdx === -1) {
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
var check = beforeQ.slice(0, extIdx).trim();
|
|
1283
|
+
var extends_ = beforeQ.slice(extIdx + 7).trim();
|
|
1284
|
+
var true_ = afterQ.slice(0, colonIdx).trim();
|
|
1285
|
+
var false_ = afterQ.slice(colonIdx + 1).trim();
|
|
1286
|
+
if (!check || !extends_ || !true_ || !false_) {
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
// Guard against `?.` optional chaining and `??` nullish coalescing.
|
|
1290
|
+
if (type[qIdx + 1] === '.' || type[qIdx + 1] === '?') {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1294
|
+
check: check,
|
|
1295
|
+
extends_: extends_,
|
|
1296
|
+
true_: true_,
|
|
1297
|
+
false_: false_
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Splits `Object[Index]` at top level. Excludes tuples (`[...]`) and
|
|
1302
|
+
* empty-index arrays (`T[]`, handled earlier).
|
|
1303
|
+
* @param {string} type - Trimmed type string.
|
|
1304
|
+
* @returns {{objectRaw: string, indexRaw: string}|undefined} Raw parts.
|
|
1305
|
+
*/
|
|
1306
|
+
function parseIndexedAccessRaw(type) {
|
|
1307
|
+
if (!type.endsWith(']') || type.endsWith('[]')) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (type[0] === '[') {
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
var openIdx = findTopLevelChar(type, '[');
|
|
1314
|
+
if (openIdx === -1) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
// Ensure the `[` at openIdx closes at the very end.
|
|
1318
|
+
var square = 0;
|
|
1319
|
+
var inSingle = false;
|
|
1320
|
+
var inDouble = false;
|
|
1321
|
+
var inBacktick = false;
|
|
1322
|
+
for (var i = openIdx; i < type.length; i++) {
|
|
1323
|
+
var c = type[i];
|
|
1324
|
+
var prev = i > 0 ? type[i - 1] : '';
|
|
1325
|
+
if (c === "'" && !inDouble && !inBacktick && prev !== '\\') inSingle = !inSingle;else if (c === '"' && !inSingle && !inBacktick && prev !== '\\') inDouble = !inDouble;else if (c === '`' && !inSingle && !inDouble && prev !== '\\') inBacktick = !inBacktick;else if (!inSingle && !inDouble && !inBacktick) {
|
|
1326
|
+
if (c === '[') square++;else if (c === ']') {
|
|
1327
|
+
square--;
|
|
1328
|
+
if (square === 0 && i !== type.length - 1) {
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
if (square !== 0) {
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
var objectRaw = type.slice(0, openIdx).trim();
|
|
1338
|
+
var indexRaw = type.slice(openIdx + 1, -1).trim();
|
|
1339
|
+
if (!objectRaw || !indexRaw) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
return {
|
|
1343
|
+
objectRaw: objectRaw,
|
|
1344
|
+
indexRaw: indexRaw
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1015
1347
|
/**
|
|
1016
1348
|
* 'DepFree' refers to the fact that this function has no dependencies,
|
|
1017
1349
|
* while `expandType` depends on TypeScript itself for maximum compatibility.
|
|
@@ -1027,6 +1359,33 @@
|
|
|
1027
1359
|
*/
|
|
1028
1360
|
function expandTypeDepFree(type) {
|
|
1029
1361
|
type = type.trim();
|
|
1362
|
+
// '(123)' -> '123': strip balanced outer parens first so `(cond)?`
|
|
1363
|
+
// nullable and `(A|B)` unions see through them.
|
|
1364
|
+
var stripped = stripOuterParens(type);
|
|
1365
|
+
if (stripped !== type) {
|
|
1366
|
+
return expandTypeDepFree(stripped);
|
|
1367
|
+
}
|
|
1368
|
+
// `readonly T` erased at runtime, same shape as the inner type.
|
|
1369
|
+
if (type.startsWith('readonly ') && type.length > 9) {
|
|
1370
|
+
return expandTypeDepFree(type.slice(9).trim());
|
|
1371
|
+
}
|
|
1372
|
+
if (type === 'unique symbol') {
|
|
1373
|
+
return 'any';
|
|
1374
|
+
}
|
|
1375
|
+
// Conditionals before nullable: `A extends B ? C : D?` must keep the
|
|
1376
|
+
// nullable on the false branch, not lift it over the whole condition.
|
|
1377
|
+
// (`(cond)?` has no top-level `?` due to parens, so it falls through
|
|
1378
|
+
// to nullable below.)
|
|
1379
|
+
var earlyCond = parseConditionRaw(type);
|
|
1380
|
+
if (earlyCond) {
|
|
1381
|
+
return {
|
|
1382
|
+
type: 'condition',
|
|
1383
|
+
checkType: expandTypeDepFree(earlyCond.check),
|
|
1384
|
+
extendsType: expandTypeDepFree(earlyCond.extends_),
|
|
1385
|
+
trueType: expandTypeDepFree(earlyCond.true_),
|
|
1386
|
+
falseType: expandTypeDepFree(earlyCond.false_)
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1030
1389
|
// JSDocNullableType (`T?` / `?T`): union with null, matching expandType().
|
|
1031
1390
|
if (type.endsWith('?') && type.length > 1) {
|
|
1032
1391
|
return {
|
|
@@ -1040,20 +1399,9 @@
|
|
|
1040
1399
|
members: [expandTypeDepFree(type.slice(1).trim()), 'null']
|
|
1041
1400
|
};
|
|
1042
1401
|
}
|
|
1043
|
-
// `readonly T` erased at runtime, same shape as the inner type.
|
|
1044
|
-
if (type.startsWith('readonly ') && type.length > 9) {
|
|
1045
|
-
return expandTypeDepFree(type.slice(9).trim());
|
|
1046
|
-
}
|
|
1047
|
-
if (type === 'unique symbol') {
|
|
1048
|
-
return 'any';
|
|
1049
|
-
}
|
|
1050
|
-
// '(123)' -> '123'
|
|
1051
|
-
while (!type.includes('|') && type[0] === '(' && type[type.length - 1] === ')') {
|
|
1052
|
-
type = type.slice(1, -1).trim();
|
|
1053
|
-
}
|
|
1054
1402
|
// (1) Rest parameters like ...string
|
|
1055
1403
|
if (type[0] === '.' && type[1] === '.' && type[2] === '.') {
|
|
1056
|
-
var elementType = type.slice(3);
|
|
1404
|
+
var elementType = expandTypeDepFree(type.slice(3).trim());
|
|
1057
1405
|
return {
|
|
1058
1406
|
type: 'array',
|
|
1059
1407
|
elementType: elementType
|
|
@@ -1081,17 +1429,18 @@
|
|
|
1081
1429
|
// (3) Object<...> or Record<...>
|
|
1082
1430
|
if ((type.startsWith("Object<") || type.startsWith("Record<")) && type.endsWith('>')) {
|
|
1083
1431
|
var recordSlice = type.slice(7, -1);
|
|
1084
|
-
var
|
|
1085
|
-
if (
|
|
1432
|
+
var commaIdx = findTopLevelChar(recordSlice, ',');
|
|
1433
|
+
if (commaIdx === -1) {
|
|
1086
1434
|
console.warn("expandTypeDepFree> invalid Object/Record");
|
|
1435
|
+
} else {
|
|
1436
|
+
var key = recordSlice.slice(0, commaIdx).trim();
|
|
1437
|
+
var val = recordSlice.slice(commaIdx + 1).trim();
|
|
1438
|
+
return {
|
|
1439
|
+
type: "record",
|
|
1440
|
+
key: expandTypeDepFree(key),
|
|
1441
|
+
val: expandTypeDepFree(val)
|
|
1442
|
+
};
|
|
1087
1443
|
}
|
|
1088
|
-
var key = recordSlice.slice(0, firstComma).trim();
|
|
1089
|
-
var val = recordSlice.slice(firstComma + 1).trim();
|
|
1090
|
-
return {
|
|
1091
|
-
type: "record",
|
|
1092
|
-
key: expandTypeDepFree(key),
|
|
1093
|
-
val: expandTypeDepFree(val)
|
|
1094
|
-
};
|
|
1095
1444
|
}
|
|
1096
1445
|
// (3b) Map<...> / Set<...' for dep-free parity with expandType()
|
|
1097
1446
|
if (type.startsWith("Map<") && type.endsWith('>')) {
|
|
@@ -1124,40 +1473,102 @@
|
|
|
1124
1473
|
args: args.map(expandTypeDepFree)
|
|
1125
1474
|
};
|
|
1126
1475
|
}
|
|
1127
|
-
// (4) {
|
|
1476
|
+
// (4) Mapped types `{[K in X as Y]?: Z}` before the object-literal fallback.
|
|
1128
1477
|
if (type[0] === '{' && type[type.length - 1] === '}') {
|
|
1129
|
-
var
|
|
1478
|
+
var mapped = parseMappedRaw(type);
|
|
1479
|
+
if (mapped) {
|
|
1480
|
+
var out = {
|
|
1481
|
+
type: 'mapping',
|
|
1482
|
+
iterable: expandTypeDepFree(mapped.iterableRaw),
|
|
1483
|
+
element: mapped.element,
|
|
1484
|
+
result: expandTypeDepFree(mapped.resultRaw)
|
|
1485
|
+
};
|
|
1486
|
+
if (mapped.nameRaw !== undefined) {
|
|
1487
|
+
out.nameType = expandTypeDepFree(mapped.nameRaw);
|
|
1488
|
+
}
|
|
1489
|
+
if (mapped.question !== undefined) {
|
|
1490
|
+
out.question = mapped.question;
|
|
1491
|
+
}
|
|
1492
|
+
if (mapped.readonly !== undefined) {
|
|
1493
|
+
out.readonly = mapped.readonly;
|
|
1494
|
+
}
|
|
1495
|
+
return out;
|
|
1496
|
+
}
|
|
1497
|
+
var propertiesArray = splitTopLevel(type.slice(1, -1), ','); // ['entity: Entity', ' app: AppBase']
|
|
1130
1498
|
var properties = {};
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1499
|
+
var _iterator = _createForOfIteratorHelper(propertiesArray),
|
|
1500
|
+
_step;
|
|
1501
|
+
try {
|
|
1502
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1503
|
+
var entry = _step.value;
|
|
1504
|
+
var colonIdx = findTopLevelChar(entry, ':');
|
|
1505
|
+
if (colonIdx === -1) {
|
|
1506
|
+
// Empty `{}` yields one empty entry: the empty object type.
|
|
1507
|
+
if (entry.trim() === '') {
|
|
1508
|
+
continue;
|
|
1509
|
+
}
|
|
1510
|
+
console.warn('expandTypeDepFree> unexpected type format, fix');
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
var propName = entry.slice(0, colonIdx).trim();
|
|
1514
|
+
var propTypeRaw = entry.slice(colonIdx + 1).trim();
|
|
1515
|
+
if (!propName || !propTypeRaw) {
|
|
1516
|
+
console.warn('expandTypeDepFree> unexpected type format, fix');
|
|
1517
|
+
continue;
|
|
1518
|
+
}
|
|
1519
|
+
properties[propName] = expandTypeDepFree(propTypeRaw);
|
|
1141
1520
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1521
|
+
} catch (err) {
|
|
1522
|
+
_iterator.e(err);
|
|
1523
|
+
} finally {
|
|
1524
|
+
_iterator.f();
|
|
1525
|
+
}
|
|
1144
1526
|
return {
|
|
1145
1527
|
type: 'object',
|
|
1146
1528
|
properties: properties
|
|
1147
1529
|
};
|
|
1148
1530
|
}
|
|
1149
|
-
// (5)
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
});
|
|
1531
|
+
// (5) Unions and intersections via top-level splits (`&` binds tighter, so `|` first).
|
|
1532
|
+
// Note: conditionals already handled up front (before nullable) so `D?`
|
|
1533
|
+
// false branches keep their nullability; this slot is intentionally union-only.
|
|
1534
|
+
var unionParts = splitTopLevel(type, "|");
|
|
1535
|
+
if (unionParts.length >= 2) {
|
|
1155
1536
|
return {
|
|
1156
1537
|
type: 'union',
|
|
1157
|
-
members:
|
|
1538
|
+
members: unionParts.map(function (_) {
|
|
1539
|
+
return expandTypeDepFree(_.trim());
|
|
1540
|
+
})
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
var interParts = splitTopLevel(type, "&");
|
|
1544
|
+
if (interParts.length >= 2) {
|
|
1545
|
+
return {
|
|
1546
|
+
type: 'intersection',
|
|
1547
|
+
members: interParts.map(function (_) {
|
|
1548
|
+
return expandTypeDepFree(_.trim());
|
|
1549
|
+
})
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
// (7) `keyof T` before typeof so `keyof typeof X` nests correctly.
|
|
1553
|
+
if (type.startsWith('keyof ') || type.startsWith('keyof(')) {
|
|
1554
|
+
var after = type.startsWith('keyof(') ? type.slice(5).trim() : type.slice(6).trim();
|
|
1555
|
+
if (after) {
|
|
1556
|
+
return {
|
|
1557
|
+
type: 'keyof',
|
|
1558
|
+
argument: expandTypeDepFree(after)
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
// (8) Indexed access `T[K]` (arrays `T[]` handled below, tuples above start with `[`).
|
|
1563
|
+
var indexed = parseIndexedAccessRaw(type);
|
|
1564
|
+
if (indexed) {
|
|
1565
|
+
return {
|
|
1566
|
+
type: 'indexedAccess',
|
|
1567
|
+
index: expandTypeDepFree(indexed.indexRaw),
|
|
1568
|
+
object: expandTypeDepFree(indexed.objectRaw)
|
|
1158
1569
|
};
|
|
1159
1570
|
}
|
|
1160
|
-
// (
|
|
1571
|
+
// (9) expand [] Arrays
|
|
1161
1572
|
// Test arrays: new pc.Mat3().set([1, 2, 3, "asd"])
|
|
1162
1573
|
if (type.endsWith("[]")) {
|
|
1163
1574
|
var _typeSlice2 = type.slice(0, -2);
|
|
@@ -1166,17 +1577,26 @@
|
|
|
1166
1577
|
elementType: expandTypeDepFree(_typeSlice2)
|
|
1167
1578
|
};
|
|
1168
1579
|
}
|
|
1169
|
-
// (
|
|
1580
|
+
// (10) expand tuples
|
|
1170
1581
|
if (type[0] === '[' && type[type.length - 1] === ']') {
|
|
1171
|
-
var
|
|
1582
|
+
var _inner2 = type.slice(1, -1);
|
|
1583
|
+
if (_inner2.trim() === '') {
|
|
1584
|
+
return {
|
|
1585
|
+
type: 'tuple',
|
|
1586
|
+
elements: []
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
var elements = splitTopLevel(_inner2, ','); // ['null', ' Texture', ...]
|
|
1172
1590
|
return {
|
|
1173
1591
|
type: 'tuple',
|
|
1174
|
-
elements: elements.map(
|
|
1592
|
+
elements: elements.map(function (_) {
|
|
1593
|
+
return expandTypeDepFree(_.trim());
|
|
1594
|
+
})
|
|
1175
1595
|
};
|
|
1176
1596
|
}
|
|
1177
|
-
// (
|
|
1597
|
+
// (11) expand typeof expressions
|
|
1178
1598
|
if (type.startsWith('typeof ')) {
|
|
1179
|
-
var argument = expandTypeDepFree(type.substring(7));
|
|
1599
|
+
var argument = expandTypeDepFree(type.substring(7).trim());
|
|
1180
1600
|
return {
|
|
1181
1601
|
type: 'typeof',
|
|
1182
1602
|
argument: argument
|
|
@@ -1202,79 +1622,6 @@
|
|
|
1202
1622
|
return type;
|
|
1203
1623
|
}
|
|
1204
1624
|
|
|
1205
|
-
/**
|
|
1206
|
-
* Infers a parameter type from its default value AST node.
|
|
1207
|
-
* Returns widened types like TypeScript does (`= 0` means `number`, not
|
|
1208
|
-
* literal `0`; `= null` widens to `any`).
|
|
1209
|
-
* Returns `undefined` when nothing useful can be inferred — the caller then
|
|
1210
|
-
* emits no check, exactly like an undocumented parameter today.
|
|
1211
|
-
* Shapes match what `expandType` produces so they can be embedded as-is.
|
|
1212
|
-
* @param {import('@babel/types').Node} node - The default value AST node.
|
|
1213
|
-
* @returns {string | object | undefined} Inferred type or `undefined` to skip.
|
|
1214
|
-
*/
|
|
1215
|
-
function inferTypeFromDefault$1(node) {
|
|
1216
|
-
if (!node) {
|
|
1217
|
-
return;
|
|
1218
|
-
}
|
|
1219
|
-
switch (node.type) {
|
|
1220
|
-
case 'NumericLiteral':
|
|
1221
|
-
return 'number';
|
|
1222
|
-
case 'StringLiteral':
|
|
1223
|
-
return 'string';
|
|
1224
|
-
case 'BooleanLiteral':
|
|
1225
|
-
return 'boolean';
|
|
1226
|
-
case 'BigIntLiteral':
|
|
1227
|
-
return {
|
|
1228
|
-
type: 'bigint'
|
|
1229
|
-
};
|
|
1230
|
-
case 'RegExpLiteral':
|
|
1231
|
-
return 'RegExp';
|
|
1232
|
-
case 'TemplateLiteral':
|
|
1233
|
-
return 'string';
|
|
1234
|
-
case 'ArrayExpression':
|
|
1235
|
-
return {
|
|
1236
|
-
type: 'array',
|
|
1237
|
-
elementType: 'any'
|
|
1238
|
-
};
|
|
1239
|
-
case 'ObjectExpression':
|
|
1240
|
-
return {
|
|
1241
|
-
type: 'object',
|
|
1242
|
-
properties: {}
|
|
1243
|
-
};
|
|
1244
|
-
case 'ArrowFunctionExpression':
|
|
1245
|
-
case 'FunctionExpression':
|
|
1246
|
-
return 'Function';
|
|
1247
|
-
case 'NewExpression':
|
|
1248
|
-
{
|
|
1249
|
-
var callee = node.callee;
|
|
1250
|
-
if (callee.type === 'Identifier') {
|
|
1251
|
-
return callee.name;
|
|
1252
|
-
}
|
|
1253
|
-
break;
|
|
1254
|
-
}
|
|
1255
|
-
case 'UnaryExpression':
|
|
1256
|
-
{
|
|
1257
|
-
var operator = node.operator,
|
|
1258
|
-
argument = node.argument;
|
|
1259
|
-
if (operator === '!') {
|
|
1260
|
-
return 'boolean';
|
|
1261
|
-
}
|
|
1262
|
-
if (operator === 'void' || operator === 'typeof') {
|
|
1263
|
-
return operator === 'void' ? 'undefined' : 'string';
|
|
1264
|
-
}
|
|
1265
|
-
if ((operator === '-' || operator === '+') && argument.type === 'NumericLiteral') {
|
|
1266
|
-
return 'number';
|
|
1267
|
-
}
|
|
1268
|
-
if ((operator === '-' || operator === '+') && argument.type === 'BigIntLiteral') {
|
|
1269
|
-
return {
|
|
1270
|
-
type: 'bigint'
|
|
1271
|
-
};
|
|
1272
|
-
}
|
|
1273
|
-
break;
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
1625
|
/**
|
|
1279
1626
|
* Extracts the parameter name and its optionality from a JSDoc parameter string.
|
|
1280
1627
|
*
|
|
@@ -1339,73 +1686,863 @@
|
|
|
1339
1686
|
*
|
|
1340
1687
|
* It iterates through the lines of a `CommentBlock` from the Babel AST, looking for `@typedef` and `@property`
|
|
1341
1688
|
* annotations. When it finds a typedef, it stores it in the `typedefs` record. When it finds a property,
|
|
1342
|
-
* it adds it to the last found typedef if it is an object type.
|
|
1689
|
+
* it adds it to the last found typedef if it is an object type. `@template` names preceding a
|
|
1690
|
+
* typedef are recorded in `typedefTemplates` so generic references can instantiate.
|
|
1343
1691
|
* @param {Record<string, object>} typedefs - An object to store typedefs, mapping type names to their expanded definitions.
|
|
1692
|
+
* @param {Record<string, string[]>} typedefTemplates - An object to store template parameter names per generic typedef.
|
|
1344
1693
|
* @param {Console["warn"]} warn - A warn function used for emitting warnings about non-extensible types.
|
|
1345
1694
|
* @param {import("@babel/types").Comment} comment - A comment extracted from Babel's AST, expected to be a CommentBlock containing type definitions.
|
|
1346
1695
|
* @param {Function} expandType - A function that takes a type expression as a string and returns a structured representation of the type.
|
|
1347
1696
|
*/
|
|
1348
|
-
function parseJSDocTypedef(typedefs, warn, comment, expandType) {
|
|
1349
|
-
var type = comment.type,
|
|
1350
|
-
value = comment.value;
|
|
1351
|
-
if (type !== 'CommentBlock') {
|
|
1697
|
+
function parseJSDocTypedef(typedefs, typedefTemplates, warn, comment, expandType) {
|
|
1698
|
+
var type = comment.type,
|
|
1699
|
+
value = comment.value;
|
|
1700
|
+
if (type !== 'CommentBlock') {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
var lines = value.split('\n');
|
|
1704
|
+
var lastTypedef;
|
|
1705
|
+
var pendingTemplates = [];
|
|
1706
|
+
/**
|
|
1707
|
+
* @param {string} line - The trimmed JSDoc line.
|
|
1708
|
+
* @returns {boolean} True when the line held a template tag.
|
|
1709
|
+
*/
|
|
1710
|
+
function harvestTemplate(line) {
|
|
1711
|
+
var match = line.match(/@template \{(.*?)\} ([a-zA-Z0-9_$]+)/);
|
|
1712
|
+
if (match) {
|
|
1713
|
+
pendingTemplates.push(match[2]);
|
|
1714
|
+
return true;
|
|
1715
|
+
}
|
|
1716
|
+
match = line.match(/@template (?:\{.*?\} )?\[([a-zA-Z0-9_$]+)=/);
|
|
1717
|
+
if (match) {
|
|
1718
|
+
pendingTemplates.push(match[1]);
|
|
1719
|
+
return true;
|
|
1720
|
+
}
|
|
1721
|
+
match = line.match(/@template ([a-zA-Z0-9_$]+)(?![a-zA-Z0-9_$])/);
|
|
1722
|
+
if (match) {
|
|
1723
|
+
pendingTemplates.push(match[1]);
|
|
1724
|
+
return true;
|
|
1725
|
+
}
|
|
1726
|
+
return false;
|
|
1727
|
+
}
|
|
1728
|
+
var _iterator = _createForOfIteratorHelper(lines),
|
|
1729
|
+
_step;
|
|
1730
|
+
try {
|
|
1731
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1732
|
+
var line = _step.value;
|
|
1733
|
+
line = line.trim();
|
|
1734
|
+
if (line[0] === '*') {
|
|
1735
|
+
line = line.slice(1).trim();
|
|
1736
|
+
}
|
|
1737
|
+
if (line.startsWith('@template')) {
|
|
1738
|
+
harvestTemplate(line);
|
|
1739
|
+
} else if (line.startsWith('@typedef')) {
|
|
1740
|
+
var _extractCurlyContent = extractCurlyContent(line),
|
|
1741
|
+
def = _extractCurlyContent.content,
|
|
1742
|
+
nextIndex = _extractCurlyContent.nextIndex;
|
|
1743
|
+
var name = line.substring(nextIndex).trim();
|
|
1744
|
+
// Drop description
|
|
1745
|
+
name = name.split(' ')[0];
|
|
1746
|
+
lastTypedef = expandType(def);
|
|
1747
|
+
// Ignore @typedef's that only refer to themselves in another file (see typedef-overwrite test)
|
|
1748
|
+
if (lastTypedef !== name) {
|
|
1749
|
+
typedefs[name] = lastTypedef;
|
|
1750
|
+
if (pendingTemplates.length) {
|
|
1751
|
+
typedefTemplates[name] = _toConsumableArray(pendingTemplates);
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
pendingTemplates = [];
|
|
1755
|
+
} else if (line.startsWith('@property')) {
|
|
1756
|
+
var _lastTypedef;
|
|
1757
|
+
// class @property
|
|
1758
|
+
if (!lastTypedef) {
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
var _extractCurlyContent2 = extractCurlyContent(line),
|
|
1762
|
+
content = _extractCurlyContent2.content,
|
|
1763
|
+
_nextIndex = _extractCurlyContent2.nextIndex;
|
|
1764
|
+
var rest = line.substring(_nextIndex);
|
|
1765
|
+
var propType = expandType(content);
|
|
1766
|
+
var _extractNameAndOption = extractNameAndOptionality(rest),
|
|
1767
|
+
_extractNameAndOption2 = _slicedToArray(_extractNameAndOption, 2),
|
|
1768
|
+
_name = _extractNameAndOption2[0],
|
|
1769
|
+
optional = _extractNameAndOption2[1];
|
|
1770
|
+
// console.log({name, optional, propType});
|
|
1771
|
+
var finalType = annotateOptional(propType, optional);
|
|
1772
|
+
if (((_lastTypedef = lastTypedef) === null || _lastTypedef === void 0 ? void 0 : _lastTypedef.type) === 'object') {
|
|
1773
|
+
lastTypedef.properties[_name] = finalType;
|
|
1774
|
+
} else {
|
|
1775
|
+
warn("not an extensible type", lastTypedef);
|
|
1776
|
+
}
|
|
1777
|
+
} else if (line.startsWith('@callback')) {
|
|
1778
|
+
var _name2 = line.substring(9).trim();
|
|
1779
|
+
typedefs[_name2] = 'Function';
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
} catch (err) {
|
|
1783
|
+
_iterator.e(err);
|
|
1784
|
+
} finally {
|
|
1785
|
+
_iterator.f();
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
* @typedef {ReturnType<typeof parseJSDoc>} ParseJSDocReturnType
|
|
1791
|
+
*/
|
|
1792
|
+
/**
|
|
1793
|
+
* @typedef {typeof expandTypeDepFree} ExpandType
|
|
1794
|
+
* @typedef {ReturnType<ExpandType>} ExpandTypeReturnType
|
|
1795
|
+
*/
|
|
1796
|
+
/**
|
|
1797
|
+
* Parses JSDoc comments to extract parameter type information.
|
|
1798
|
+
*
|
|
1799
|
+
* @param {string} src - The JSDoc comment string to parse.
|
|
1800
|
+
* @param {ExpandType} [expandType] - An optional function to process the types found in the JSDoc.
|
|
1801
|
+
* @returns {Record<string, ExpandTypeReturnType> | undefined} An object mapping parameter names to their parsed types, or undefined if no parameters are found.
|
|
1802
|
+
*/
|
|
1803
|
+
function parseJSDoc(src) {
|
|
1804
|
+
var expandType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : expandTypeDepFree;
|
|
1805
|
+
// Parse something like: @param {Object} [kwargs={}] Optional arguments.
|
|
1806
|
+
var regex = /@param \{(.*?)\} ([\[\]a-zA-Z0-9_$=\-\{\}\.'" ]+)/g;
|
|
1807
|
+
var matches = _toConsumableArray(src.matchAll(regex));
|
|
1808
|
+
/** @type {Record<string, ExpandTypeReturnType>} */
|
|
1809
|
+
var params = Object.create(null);
|
|
1810
|
+
matches.forEach(function (_) {
|
|
1811
|
+
var type = expandType(_[1].trim());
|
|
1812
|
+
var name = _[2].trim();
|
|
1813
|
+
var optional = false;
|
|
1814
|
+
// Examples:
|
|
1815
|
+
// name: [kwargs={}] The configuration parameters.
|
|
1816
|
+
// name: [d = 1.0] Sample spacing
|
|
1817
|
+
if (name[0] === '[') {
|
|
1818
|
+
// Counting opening/closing brackets for perfect match
|
|
1819
|
+
var openCloseCount = 1;
|
|
1820
|
+
var i = 1;
|
|
1821
|
+
for (; i < name.length; i++) {
|
|
1822
|
+
var c = name[i];
|
|
1823
|
+
if (c === '[') {
|
|
1824
|
+
openCloseCount++;
|
|
1825
|
+
} else if (c === ']') {
|
|
1826
|
+
openCloseCount--;
|
|
1827
|
+
}
|
|
1828
|
+
if (openCloseCount === 0) {
|
|
1829
|
+
break;
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
// Afterwards name will be: d = 1.0
|
|
1833
|
+
name = name.substring(1, i);
|
|
1834
|
+
// mark it for the type:
|
|
1835
|
+
optional = true;
|
|
1836
|
+
}
|
|
1837
|
+
// Strip the rest (either leftover of optional value or description)
|
|
1838
|
+
name = name.split(' ')[0].split('=')[0].trim();
|
|
1839
|
+
var annotatedType = annotateOptional(type, optional);
|
|
1840
|
+
// Turn "options.stats[].unitsName" into ['options', 'stats', 'unitsName'].
|
|
1841
|
+
var parts = name.split(/[\[\]]*\./);
|
|
1842
|
+
var properties = params;
|
|
1843
|
+
var _iterator = _createForOfIteratorHelper(parts),
|
|
1844
|
+
_step;
|
|
1845
|
+
try {
|
|
1846
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1847
|
+
var part = _step.value;
|
|
1848
|
+
var toptype = properties[part];
|
|
1849
|
+
if (!toptype) {
|
|
1850
|
+
// No toptype means we resolved as far as possible, now we can add `annotatedType`.
|
|
1851
|
+
console.assert(part === parts.at(-1), 'Current part and last part should be the same.');
|
|
1852
|
+
properties[part] = annotatedType;
|
|
1853
|
+
} else if (toptype.type === "union") {
|
|
1854
|
+
var typeObject = toptype.members.find(function (_) {
|
|
1855
|
+
return (_ === null || _ === void 0 ? void 0 : _.type) === 'object';
|
|
1856
|
+
});
|
|
1857
|
+
properties = typeObject.properties;
|
|
1858
|
+
} else if (toptype.type === "array") {
|
|
1859
|
+
properties = toptype.elementType.properties;
|
|
1860
|
+
} else if (toptype.type === "object") {
|
|
1861
|
+
toptype.properties = toptype.properties || Object.create(null);
|
|
1862
|
+
properties = toptype.properties;
|
|
1863
|
+
} else {
|
|
1864
|
+
console.warn("parseJSDoc> Skipping @param, unseen syntax detected. Please check if your JSDoc is valid or open an issue about this!", {
|
|
1865
|
+
src: src,
|
|
1866
|
+
toptype: toptype,
|
|
1867
|
+
parts: parts,
|
|
1868
|
+
annotatedType: annotatedType
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
} catch (err) {
|
|
1873
|
+
_iterator.e(err);
|
|
1874
|
+
} finally {
|
|
1875
|
+
_iterator.f();
|
|
1876
|
+
}
|
|
1877
|
+
});
|
|
1878
|
+
if (Object.keys(params).length === 0) {
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
return params;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
/**
|
|
1885
|
+
* Infers a parameter type from its default value AST node.
|
|
1886
|
+
* Returns widened types like TypeScript does (`= 0` means `number`, not
|
|
1887
|
+
* literal `0`; `= null` widens to `any`).
|
|
1888
|
+
* Returns `undefined` when nothing useful can be inferred — the caller then
|
|
1889
|
+
* emits no check, exactly like an undocumented parameter today.
|
|
1890
|
+
* Shapes match what `expandType` produces so they can be embedded as-is.
|
|
1891
|
+
* @param {import('@babel/types').Node} node - The default value AST node.
|
|
1892
|
+
* @returns {string | object | undefined} Inferred type or `undefined` to skip.
|
|
1893
|
+
*/
|
|
1894
|
+
function inferTypeFromDefault$1(node) {
|
|
1895
|
+
if (!node) {
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
switch (node.type) {
|
|
1899
|
+
case 'NumericLiteral':
|
|
1900
|
+
return 'number';
|
|
1901
|
+
case 'StringLiteral':
|
|
1902
|
+
return 'string';
|
|
1903
|
+
case 'BooleanLiteral':
|
|
1904
|
+
return 'boolean';
|
|
1905
|
+
case 'BigIntLiteral':
|
|
1906
|
+
return {
|
|
1907
|
+
type: 'bigint'
|
|
1908
|
+
};
|
|
1909
|
+
case 'RegExpLiteral':
|
|
1910
|
+
return 'RegExp';
|
|
1911
|
+
case 'TemplateLiteral':
|
|
1912
|
+
return 'string';
|
|
1913
|
+
case 'ArrayExpression':
|
|
1914
|
+
return {
|
|
1915
|
+
type: 'array',
|
|
1916
|
+
elementType: 'any'
|
|
1917
|
+
};
|
|
1918
|
+
case 'ObjectExpression':
|
|
1919
|
+
return {
|
|
1920
|
+
type: 'object',
|
|
1921
|
+
properties: {}
|
|
1922
|
+
};
|
|
1923
|
+
case 'ArrowFunctionExpression':
|
|
1924
|
+
case 'FunctionExpression':
|
|
1925
|
+
return 'Function';
|
|
1926
|
+
case 'NewExpression':
|
|
1927
|
+
{
|
|
1928
|
+
var callee = node.callee;
|
|
1929
|
+
if (callee.type === 'Identifier') {
|
|
1930
|
+
return callee.name;
|
|
1931
|
+
}
|
|
1932
|
+
break;
|
|
1933
|
+
}
|
|
1934
|
+
case 'UnaryExpression':
|
|
1935
|
+
{
|
|
1936
|
+
var operator = node.operator,
|
|
1937
|
+
argument = node.argument;
|
|
1938
|
+
if (operator === '!') {
|
|
1939
|
+
return 'boolean';
|
|
1940
|
+
}
|
|
1941
|
+
if (operator === 'void' || operator === 'typeof') {
|
|
1942
|
+
return operator === 'void' ? 'undefined' : 'string';
|
|
1943
|
+
}
|
|
1944
|
+
if ((operator === '-' || operator === '+') && argument.type === 'NumericLiteral') {
|
|
1945
|
+
return 'number';
|
|
1946
|
+
}
|
|
1947
|
+
if ((operator === '-' || operator === '+') && argument.type === 'BigIntLiteral') {
|
|
1948
|
+
return {
|
|
1949
|
+
type: 'bigint'
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1952
|
+
break;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
// Declaration-site ranks: the field always beats constructor assignments,
|
|
1958
|
+
// like TSC where the declared type wins over assigned values.
|
|
1959
|
+
var FIELD_JSDOC = 3;
|
|
1960
|
+
var CTOR_JSDOC = 2;
|
|
1961
|
+
var FIELD_INFER = 1;
|
|
1962
|
+
var CTOR_INFER = 0;
|
|
1963
|
+
/**
|
|
1964
|
+
* Reads the last block comment attached to a node.
|
|
1965
|
+
* @param {*} node - Babel AST node.
|
|
1966
|
+
* @returns {string|undefined} Comment text or undefined.
|
|
1967
|
+
*/
|
|
1968
|
+
function lastBlockComment(node) {
|
|
1969
|
+
var list = node === null || node === void 0 ? void 0 : node.leadingComments;
|
|
1970
|
+
if (!list) {
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
for (var i = list.length - 1; i >= 0; i--) {
|
|
1974
|
+
if (list[i].type === 'CommentBlock') {
|
|
1975
|
+
return list[i].value;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Extracts a `{...}`-typed JSDoc tag (`@type`, `@returns`) from a comment.
|
|
1981
|
+
* @param {string|undefined} comment - Comment text.
|
|
1982
|
+
* @param {string} tag - Tag name including `@`.
|
|
1983
|
+
* @param {Function} expandType - String type to structured type.
|
|
1984
|
+
* @returns {{type: *, raw: string}|undefined} Expanded type plus raw text.
|
|
1985
|
+
*/
|
|
1986
|
+
function tagType(comment, tag, expandType) {
|
|
1987
|
+
if (!comment) {
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
var idx = comment.search(new RegExp("".concat(tag, "(?=[\\s{])")));
|
|
1991
|
+
if (idx === -1) {
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
var slice = comment.slice(idx);
|
|
1995
|
+
if (!slice.includes('{')) {
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
try {
|
|
1999
|
+
var _extractCurlyContent = extractCurlyContent(slice),
|
|
2000
|
+
content = _extractCurlyContent.content;
|
|
2001
|
+
if (!content || !content.trim()) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
return {
|
|
2005
|
+
type: expandType(content.trim()),
|
|
2006
|
+
raw: content.trim()
|
|
2007
|
+
};
|
|
2008
|
+
} catch (_unused) {
|
|
2009
|
+
// Unparseable annotation: fail open, harvest continues.
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* Reads a static property name: identifiers and string literals, including
|
|
2014
|
+
* computed `['name']` forms. Anything dynamic yields undefined.
|
|
2015
|
+
* @param {*} key - Babel key node.
|
|
2016
|
+
* @param {boolean} computed - Whether the key position is computed.
|
|
2017
|
+
* @returns {string|undefined} Property name or undefined.
|
|
2018
|
+
*/
|
|
2019
|
+
function keyName(key, computed) {
|
|
2020
|
+
if (!key) {
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
if (key.type === 'Identifier' && !computed) {
|
|
2024
|
+
return key.name;
|
|
2025
|
+
}
|
|
2026
|
+
if (key.type === 'StringLiteral') {
|
|
2027
|
+
return key.value;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Unwraps parenthesized and TS `as`/`satisfies` nodes.
|
|
2032
|
+
* @param {*} node - Babel AST node.
|
|
2033
|
+
* @returns {*} Unwrapped node.
|
|
2034
|
+
*/
|
|
2035
|
+
function unwrap(node) {
|
|
2036
|
+
while (node && (node.type === 'ParenthesizedExpression' || node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression')) {
|
|
2037
|
+
node = node.expression;
|
|
2038
|
+
}
|
|
2039
|
+
return node;
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Merges a harvested entry: higher rank wins the type, flags accumulate
|
|
2043
|
+
* (`optional` reflects runtime reality, `@readonly` anywhere counts).
|
|
2044
|
+
* Two disagreeing humans (JSDoc vs JSDoc) warn, like a TSC error.
|
|
2045
|
+
* @param {Record<string, object>} fields - Collected entries by name.
|
|
2046
|
+
* @param {string} name - Property name.
|
|
2047
|
+
* @param {object} entry - Entry with type, rank, raw, readonly, optional.
|
|
2048
|
+
* @param {Function} warn - Transpile-time warning function.
|
|
2049
|
+
* @param {string} className - Class name for messages.
|
|
2050
|
+
*/
|
|
2051
|
+
function record(fields, name, entry, warn, className) {
|
|
2052
|
+
var existing = fields[name];
|
|
2053
|
+
if (!existing) {
|
|
2054
|
+
fields[name] = entry;
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
if (entry.jsdoc && existing.jsdoc && entry.raw !== existing.raw) {
|
|
2058
|
+
warn("harvestClassShape: ".concat(className, ".").concat(name, " has conflicting JSDoc types (").concat(existing.raw, " vs ").concat(entry.raw, ")"));
|
|
2059
|
+
}
|
|
2060
|
+
var winner = entry.rank >= existing.rank ? entry : existing;
|
|
2061
|
+
winner.readonly = existing.readonly || entry.readonly;
|
|
2062
|
+
winner.optional = existing.optional || entry.optional;
|
|
2063
|
+
fields[name] = winner;
|
|
2064
|
+
}
|
|
2065
|
+
/**
|
|
2066
|
+
* Turns a collected entry into a type struct, applying flags.
|
|
2067
|
+
* @param {object} entry - Collected entry.
|
|
2068
|
+
* @returns {*} Type struct or name.
|
|
2069
|
+
*/
|
|
2070
|
+
function entryToType(entry) {
|
|
2071
|
+
var _entry$type;
|
|
2072
|
+
var t = (_entry$type = entry.type) !== null && _entry$type !== void 0 ? _entry$type : 'any';
|
|
2073
|
+
if (!entry.readonly && !entry.optional) {
|
|
2074
|
+
return t;
|
|
2075
|
+
}
|
|
2076
|
+
if (t && _typeof(t) === 'object') {
|
|
2077
|
+
return _objectSpread2(_objectSpread2(_objectSpread2({}, t), entry.readonly ? {
|
|
2078
|
+
readonly: true
|
|
2079
|
+
} : {}), entry.optional ? {
|
|
2080
|
+
optional: true
|
|
2081
|
+
} : {});
|
|
2082
|
+
}
|
|
2083
|
+
var out = {
|
|
2084
|
+
type: t
|
|
2085
|
+
};
|
|
2086
|
+
if (entry.readonly) {
|
|
2087
|
+
out.readonly = true;
|
|
2088
|
+
}
|
|
2089
|
+
if (entry.optional) {
|
|
2090
|
+
out.optional = true;
|
|
2091
|
+
}
|
|
2092
|
+
return out;
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
2095
|
+
* Records `this.x = ...` (or `+=`, `++`) assignments.
|
|
2096
|
+
* @param {*} left - Assignment target.
|
|
2097
|
+
* @param {*} right - Assigned value or undefined for op-assign/update.
|
|
2098
|
+
* @param {string|undefined} comment - Leading comment text.
|
|
2099
|
+
* @param {boolean} conditional - True inside conditionals (counts as optional).
|
|
2100
|
+
* @param {object} ctx - Harvest context with fields, expandType, warn, className.
|
|
2101
|
+
*/
|
|
2102
|
+
function recordThisAssign(left, right, comment, conditional, ctx) {
|
|
2103
|
+
var _declared$type;
|
|
2104
|
+
var fields = ctx.fields,
|
|
2105
|
+
expandType = ctx.expandType,
|
|
2106
|
+
warn = ctx.warn,
|
|
2107
|
+
className = ctx.className;
|
|
2108
|
+
left = unwrap(left);
|
|
2109
|
+
if (!left || left.type !== 'MemberExpression' || left.computed) {
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
if (!left.object || left.object.type !== 'ThisExpression') {
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
var name = keyName(left.property, false);
|
|
2116
|
+
if (name === undefined) {
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
var declared = tagType(comment, '@type', expandType);
|
|
2120
|
+
if (right === undefined) {
|
|
2121
|
+
// Op-assign/update (`+=`, `++`): exists, type unknown.
|
|
2122
|
+
record(fields, name, {
|
|
2123
|
+
type: 'any',
|
|
2124
|
+
rank: CTOR_INFER,
|
|
2125
|
+
jsdoc: false,
|
|
2126
|
+
optional: conditional
|
|
2127
|
+
}, warn, className);
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
var inferred = inferTypeFromDefault$1(unwrap(right));
|
|
2131
|
+
var type = (_declared$type = declared === null || declared === void 0 ? void 0 : declared.type) !== null && _declared$type !== void 0 ? _declared$type : inferred;
|
|
2132
|
+
if (type === undefined) {
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
record(fields, name, {
|
|
2136
|
+
type: type,
|
|
2137
|
+
rank: declared ? CTOR_JSDOC : CTOR_INFER,
|
|
2138
|
+
jsdoc: declared !== undefined,
|
|
2139
|
+
raw: declared === null || declared === void 0 ? void 0 : declared.raw,
|
|
2140
|
+
optional: conditional
|
|
2141
|
+
}, warn, className);
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Handles `Object.assign(this, {...})` with inline object literals.
|
|
2145
|
+
* @param {*} node - CallExpression node.
|
|
2146
|
+
* @param {boolean} conditional - True inside conditionals.
|
|
2147
|
+
* @param {object} ctx - Harvest context.
|
|
2148
|
+
* @returns {boolean} True when the call was `Object.assign` on `this`.
|
|
2149
|
+
*/
|
|
2150
|
+
function recordObjectAssign(node, conditional, ctx) {
|
|
2151
|
+
var _callee$object, _callee$property;
|
|
2152
|
+
var fields = ctx.fields,
|
|
2153
|
+
expandType = ctx.expandType,
|
|
2154
|
+
warn = ctx.warn,
|
|
2155
|
+
className = ctx.className;
|
|
2156
|
+
var callee = node.callee,
|
|
2157
|
+
args = node.arguments;
|
|
2158
|
+
if (!callee || callee.type !== 'MemberExpression' || callee.computed) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
if (((_callee$object = callee.object) === null || _callee$object === void 0 ? void 0 : _callee$object.type) !== 'Identifier' || callee.object.name !== 'Object') {
|
|
2162
|
+
return false;
|
|
2163
|
+
}
|
|
2164
|
+
if (((_callee$property = callee.property) === null || _callee$property === void 0 ? void 0 : _callee$property.type) !== 'Identifier' || callee.property.name !== 'assign') {
|
|
2165
|
+
return false;
|
|
2166
|
+
}
|
|
2167
|
+
if (!args.length || args[0].type !== 'ThisExpression') {
|
|
2168
|
+
return false;
|
|
2169
|
+
}
|
|
2170
|
+
var _iterator = _createForOfIteratorHelper(args.slice(1)),
|
|
2171
|
+
_step;
|
|
2172
|
+
try {
|
|
2173
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
2174
|
+
var arg = _step.value;
|
|
2175
|
+
if (!arg || arg.type !== 'ObjectExpression') {
|
|
2176
|
+
continue;
|
|
2177
|
+
}
|
|
2178
|
+
var _iterator2 = _createForOfIteratorHelper(arg.properties),
|
|
2179
|
+
_step2;
|
|
2180
|
+
try {
|
|
2181
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
2182
|
+
var _declared$type2;
|
|
2183
|
+
var prop = _step2.value;
|
|
2184
|
+
if (!prop || prop.type !== 'ObjectProperty') {
|
|
2185
|
+
continue;
|
|
2186
|
+
}
|
|
2187
|
+
var name = keyName(prop.key, prop.computed);
|
|
2188
|
+
if (name === undefined) {
|
|
2189
|
+
continue;
|
|
2190
|
+
}
|
|
2191
|
+
var comment = lastBlockComment(prop);
|
|
2192
|
+
var declared = tagType(comment, '@type', expandType);
|
|
2193
|
+
var type = (_declared$type2 = declared === null || declared === void 0 ? void 0 : declared.type) !== null && _declared$type2 !== void 0 ? _declared$type2 : inferTypeFromDefault$1(unwrap(prop.value));
|
|
2194
|
+
if (type === undefined) {
|
|
2195
|
+
continue;
|
|
2196
|
+
}
|
|
2197
|
+
record(fields, name, {
|
|
2198
|
+
type: type,
|
|
2199
|
+
rank: declared ? CTOR_JSDOC : CTOR_INFER,
|
|
2200
|
+
jsdoc: declared !== undefined,
|
|
2201
|
+
raw: declared === null || declared === void 0 ? void 0 : declared.raw,
|
|
2202
|
+
optional: conditional
|
|
2203
|
+
}, warn, className);
|
|
2204
|
+
}
|
|
2205
|
+
} catch (err) {
|
|
2206
|
+
_iterator2.e(err);
|
|
2207
|
+
} finally {
|
|
2208
|
+
_iterator2.f();
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
} catch (err) {
|
|
2212
|
+
_iterator.e(err);
|
|
2213
|
+
} finally {
|
|
2214
|
+
_iterator.f();
|
|
2215
|
+
}
|
|
2216
|
+
return true;
|
|
2217
|
+
}
|
|
2218
|
+
/**
|
|
2219
|
+
* Walks an expression for `this.x` writes. Stops at function boundaries:
|
|
2220
|
+
* deferred writes (callbacks) are out of scope.
|
|
2221
|
+
* @param {*} expr - Babel expression node.
|
|
2222
|
+
* @param {boolean} conditional - True inside conditionals.
|
|
2223
|
+
* @param {object} ctx - Harvest context.
|
|
2224
|
+
* @param {*} stmt - Enclosing statement carrying leading comments.
|
|
2225
|
+
*/
|
|
2226
|
+
function walkExpression(expr, conditional, ctx, stmt) {
|
|
2227
|
+
if (!expr) {
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
switch (expr.type) {
|
|
2231
|
+
case 'AssignmentExpression':
|
|
2232
|
+
{
|
|
2233
|
+
var comment = lastBlockComment(stmt);
|
|
2234
|
+
if (expr.operator === '=') {
|
|
2235
|
+
recordThisAssign(expr.left, expr.right, comment, conditional, ctx);
|
|
2236
|
+
walkExpression(expr.right, conditional, ctx, stmt);
|
|
2237
|
+
} else {
|
|
2238
|
+
recordThisAssign(expr.left, undefined, comment, conditional, ctx);
|
|
2239
|
+
}
|
|
2240
|
+
break;
|
|
2241
|
+
}
|
|
2242
|
+
case 'UpdateExpression':
|
|
2243
|
+
recordThisAssign(expr.argument, undefined, lastBlockComment(stmt), conditional, ctx);
|
|
2244
|
+
break;
|
|
2245
|
+
case 'SequenceExpression':
|
|
2246
|
+
var _iterator3 = _createForOfIteratorHelper(expr.expressions),
|
|
2247
|
+
_step3;
|
|
2248
|
+
try {
|
|
2249
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
2250
|
+
var each = _step3.value;
|
|
2251
|
+
walkExpression(each, conditional, ctx, stmt);
|
|
2252
|
+
}
|
|
2253
|
+
} catch (err) {
|
|
2254
|
+
_iterator3.e(err);
|
|
2255
|
+
} finally {
|
|
2256
|
+
_iterator3.f();
|
|
2257
|
+
}
|
|
2258
|
+
break;
|
|
2259
|
+
case 'LogicalExpression':
|
|
2260
|
+
walkExpression(expr.right, true, ctx, stmt);
|
|
2261
|
+
break;
|
|
2262
|
+
case 'ConditionalExpression':
|
|
2263
|
+
walkExpression(expr.consequent, true, ctx, stmt);
|
|
2264
|
+
walkExpression(expr.alternate, true, ctx, stmt);
|
|
2265
|
+
break;
|
|
2266
|
+
case 'CallExpression':
|
|
2267
|
+
recordObjectAssign(expr, conditional, ctx);
|
|
2268
|
+
break;
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
/**
|
|
2272
|
+
* Walks a statement for `this.x` writes. Conditional wrappers mark entries
|
|
2273
|
+
* optional; nested functions are boundaries.
|
|
2274
|
+
* @param {*} st - Babel statement node.
|
|
2275
|
+
* @param {boolean} conditional - True inside conditionals.
|
|
2276
|
+
* @param {object} ctx - Harvest context.
|
|
2277
|
+
*/
|
|
2278
|
+
function walkStatement(st, conditional, ctx) {
|
|
2279
|
+
if (!st) {
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
switch (st.type) {
|
|
2283
|
+
case 'BlockStatement':
|
|
2284
|
+
var _iterator4 = _createForOfIteratorHelper(st.body),
|
|
2285
|
+
_step4;
|
|
2286
|
+
try {
|
|
2287
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
2288
|
+
var each = _step4.value;
|
|
2289
|
+
walkStatement(each, conditional, ctx);
|
|
2290
|
+
}
|
|
2291
|
+
} catch (err) {
|
|
2292
|
+
_iterator4.e(err);
|
|
2293
|
+
} finally {
|
|
2294
|
+
_iterator4.f();
|
|
2295
|
+
}
|
|
2296
|
+
break;
|
|
2297
|
+
case 'ExpressionStatement':
|
|
2298
|
+
walkExpression(st.expression, conditional, ctx, st);
|
|
2299
|
+
break;
|
|
2300
|
+
case 'ReturnStatement':
|
|
2301
|
+
walkExpression(st.argument, conditional, ctx, st);
|
|
2302
|
+
break;
|
|
2303
|
+
case 'IfStatement':
|
|
2304
|
+
walkStatement(st.consequent, true, ctx);
|
|
2305
|
+
walkStatement(st.alternate, true, ctx);
|
|
2306
|
+
break;
|
|
2307
|
+
case 'WhileStatement':
|
|
2308
|
+
case 'ForStatement':
|
|
2309
|
+
case 'ForInStatement':
|
|
2310
|
+
case 'ForOfStatement':
|
|
2311
|
+
walkStatement(st.body, true, ctx);
|
|
2312
|
+
break;
|
|
2313
|
+
case 'DoWhileStatement':
|
|
2314
|
+
walkStatement(st.body, conditional, ctx);
|
|
2315
|
+
break;
|
|
2316
|
+
case 'SwitchStatement':
|
|
2317
|
+
var _iterator5 = _createForOfIteratorHelper(st.cases),
|
|
2318
|
+
_step5;
|
|
2319
|
+
try {
|
|
2320
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
2321
|
+
var _each = _step5.value;
|
|
2322
|
+
var _iterator6 = _createForOfIteratorHelper(_each.consequent),
|
|
2323
|
+
_step6;
|
|
2324
|
+
try {
|
|
2325
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
2326
|
+
var consequent = _step6.value;
|
|
2327
|
+
walkStatement(consequent, true, ctx);
|
|
2328
|
+
}
|
|
2329
|
+
} catch (err) {
|
|
2330
|
+
_iterator6.e(err);
|
|
2331
|
+
} finally {
|
|
2332
|
+
_iterator6.f();
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
} catch (err) {
|
|
2336
|
+
_iterator5.e(err);
|
|
2337
|
+
} finally {
|
|
2338
|
+
_iterator5.f();
|
|
2339
|
+
}
|
|
2340
|
+
break;
|
|
2341
|
+
case 'TryStatement':
|
|
2342
|
+
walkStatement(st.block, conditional, ctx);
|
|
2343
|
+
if (st.handler) {
|
|
2344
|
+
walkStatement(st.handler.body, true, ctx);
|
|
2345
|
+
}
|
|
2346
|
+
if (st.finalizer) {
|
|
2347
|
+
walkStatement(st.finalizer, conditional, ctx);
|
|
2348
|
+
}
|
|
2349
|
+
break;
|
|
2350
|
+
case 'LabeledStatement':
|
|
2351
|
+
walkStatement(st.body, conditional, ctx);
|
|
2352
|
+
break;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
/**
|
|
2356
|
+
* Reads the single parameter name of a setter.
|
|
2357
|
+
* @param {*} param - Babel parameter node.
|
|
2358
|
+
* @returns {string|undefined} Name or undefined.
|
|
2359
|
+
*/
|
|
2360
|
+
function setterParamName(param) {
|
|
2361
|
+
if (!param) {
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
if (param.type === 'Identifier') {
|
|
2365
|
+
return param.name;
|
|
2366
|
+
}
|
|
2367
|
+
if (param.type === 'AssignmentPattern' && param.left.type === 'Identifier') {
|
|
2368
|
+
return param.left.name;
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
/**
|
|
2372
|
+
* Reads a setter's value type: its `@param` JSDoc first, `@type` fallback.
|
|
2373
|
+
* @param {*} set - Babel ClassMethod (kind set) node.
|
|
2374
|
+
* @param {Function} expandType - String type to structured type.
|
|
2375
|
+
* @returns {{type: *, raw: string|undefined, jsdoc: boolean}} Type plus metadata.
|
|
2376
|
+
*/
|
|
2377
|
+
function setterType(set, expandType) {
|
|
2378
|
+
var setComment = lastBlockComment(set);
|
|
2379
|
+
var paramName = setterParamName(set.params[0]);
|
|
2380
|
+
var params = parseJSDoc(setComment !== null && setComment !== void 0 ? setComment : '', expandType);
|
|
2381
|
+
if (paramName && params && params[paramName] !== undefined) {
|
|
2382
|
+
return {
|
|
2383
|
+
type: params[paramName],
|
|
2384
|
+
raw: undefined,
|
|
2385
|
+
jsdoc: true
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2388
|
+
var tagged = tagType(setComment, '@type', expandType);
|
|
2389
|
+
if (tagged) {
|
|
2390
|
+
return {
|
|
2391
|
+
type: tagged.type,
|
|
2392
|
+
raw: tagged.raw,
|
|
2393
|
+
jsdoc: true
|
|
2394
|
+
};
|
|
2395
|
+
}
|
|
2396
|
+
return {
|
|
2397
|
+
type: 'any',
|
|
2398
|
+
raw: undefined,
|
|
2399
|
+
jsdoc: false
|
|
2400
|
+
};
|
|
2401
|
+
}
|
|
2402
|
+
/**
|
|
2403
|
+
* Harvests the instance shape of a class: field declarations (JSDoc wins,
|
|
2404
|
+
* else inferred), constructor `this.x` writes (field site wins conflicts),
|
|
2405
|
+
* methods as `Function`, getter/setter pairs as writable and getter-only as
|
|
2406
|
+
* readonly. Statics, privates and dynamic keys are skipped.
|
|
2407
|
+
* @param {*} node - Babel ClassDeclaration node.
|
|
2408
|
+
* @param {object} opts - Options with expandType and warn.
|
|
2409
|
+
* @param {Function} opts.expandType - String type to structured type.
|
|
2410
|
+
* @param {Function} opts.warn - Transpile-time warning function.
|
|
2411
|
+
* @returns {{name: string, shape: object}|undefined} Class name plus object shape.
|
|
2412
|
+
*/
|
|
2413
|
+
function harvestClassShape(node, _ref) {
|
|
2414
|
+
var expandType = _ref.expandType,
|
|
2415
|
+
warn = _ref.warn;
|
|
2416
|
+
var id = node === null || node === void 0 ? void 0 : node.id;
|
|
2417
|
+
if (!id || id.type !== 'Identifier' || !id.name) {
|
|
1352
2418
|
return;
|
|
1353
2419
|
}
|
|
1354
|
-
var
|
|
1355
|
-
var
|
|
1356
|
-
|
|
1357
|
-
|
|
2420
|
+
var className = id.name;
|
|
2421
|
+
var ctx = {
|
|
2422
|
+
fields: {},
|
|
2423
|
+
gets: {},
|
|
2424
|
+
sets: {},
|
|
2425
|
+
expandType: expandType,
|
|
2426
|
+
warn: warn,
|
|
2427
|
+
className: className
|
|
2428
|
+
};
|
|
2429
|
+
var ctor = null;
|
|
2430
|
+
var _iterator7 = _createForOfIteratorHelper(node.body.body),
|
|
2431
|
+
_step7;
|
|
1358
2432
|
try {
|
|
1359
|
-
for (
|
|
1360
|
-
var
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
line = line.slice(1).trim();
|
|
2433
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
2434
|
+
var el = _step7.value;
|
|
2435
|
+
if (el.type === 'ClassPrivateProperty' || el.type === 'ClassPrivateMethod') {
|
|
2436
|
+
continue;
|
|
1364
2437
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
// Ignore @typedef's that only refer to themselves in another file (see typedef-overwrite test)
|
|
1374
|
-
if (lastTypedef !== name) {
|
|
1375
|
-
typedefs[name] = lastTypedef;
|
|
2438
|
+
var _name3 = keyName(el.key, el.computed);
|
|
2439
|
+
if (_name3 === undefined) {
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
if (el.type === 'ClassProperty' || el.type === 'PropertyDefinition') {
|
|
2443
|
+
var _declared$type3;
|
|
2444
|
+
if (el.static || el.declare) {
|
|
2445
|
+
continue;
|
|
1376
2446
|
}
|
|
1377
|
-
|
|
1378
|
-
var
|
|
1379
|
-
|
|
1380
|
-
|
|
2447
|
+
var comment = lastBlockComment(el);
|
|
2448
|
+
var declared = tagType(comment, '@type', expandType);
|
|
2449
|
+
var inferred = el.value ? inferTypeFromDefault$1(unwrap(el.value)) : undefined;
|
|
2450
|
+
var _type = (_declared$type3 = declared === null || declared === void 0 ? void 0 : declared.type) !== null && _declared$type3 !== void 0 ? _declared$type3 : inferred;
|
|
2451
|
+
if (_type === undefined) {
|
|
1381
2452
|
continue;
|
|
1382
2453
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
2454
|
+
record(ctx.fields, _name3, {
|
|
2455
|
+
type: _type,
|
|
2456
|
+
rank: declared ? FIELD_JSDOC : FIELD_INFER,
|
|
2457
|
+
jsdoc: declared !== undefined,
|
|
2458
|
+
raw: declared === null || declared === void 0 ? void 0 : declared.raw,
|
|
2459
|
+
readonly: el.readonly === true || (comment ? /@readonly(?![\w])/.test(comment) : false),
|
|
2460
|
+
optional: el.optional === true
|
|
2461
|
+
}, warn, className);
|
|
2462
|
+
} else if (el.type === 'ClassMethod' || el.type === 'ClassPrivateMethod') {
|
|
2463
|
+
if (el.static) {
|
|
2464
|
+
continue;
|
|
2465
|
+
}
|
|
2466
|
+
if (el.kind === 'constructor') {
|
|
2467
|
+
ctor = el;
|
|
2468
|
+
} else if (el.kind === 'method') {
|
|
2469
|
+
var _ctx$fields$_name;
|
|
2470
|
+
ctx.fields[_name3] = (_ctx$fields$_name = ctx.fields[_name3]) !== null && _ctx$fields$_name !== void 0 ? _ctx$fields$_name : {
|
|
2471
|
+
type: 'Function',
|
|
2472
|
+
rank: FIELD_INFER,
|
|
2473
|
+
jsdoc: false
|
|
2474
|
+
};
|
|
2475
|
+
} else if (el.kind === 'get') {
|
|
2476
|
+
ctx.gets[_name3] = el;
|
|
2477
|
+
} else if (el.kind === 'set') {
|
|
2478
|
+
ctx.sets[_name3] = el;
|
|
1398
2479
|
}
|
|
1399
|
-
} else if (line.startsWith('@callback')) {
|
|
1400
|
-
var _name2 = line.substring(9).trim();
|
|
1401
|
-
typedefs[_name2] = 'Function';
|
|
1402
2480
|
}
|
|
1403
2481
|
}
|
|
1404
2482
|
} catch (err) {
|
|
1405
|
-
|
|
2483
|
+
_iterator7.e(err);
|
|
1406
2484
|
} finally {
|
|
1407
|
-
|
|
2485
|
+
_iterator7.f();
|
|
2486
|
+
}
|
|
2487
|
+
for (var _i = 0, _Object$keys = Object.keys(ctx.gets); _i < _Object$keys.length; _i++) {
|
|
2488
|
+
var _tagType, _ref2, _getType$type, _getType$raw;
|
|
2489
|
+
var name = _Object$keys[_i];
|
|
2490
|
+
var get = ctx.gets[name];
|
|
2491
|
+
var set = ctx.sets[name];
|
|
2492
|
+
var getComment = lastBlockComment(get);
|
|
2493
|
+
var getType = (_tagType = tagType(getComment, '@type', expandType)) !== null && _tagType !== void 0 ? _tagType : tagType(getComment, '@returns', expandType);
|
|
2494
|
+
var setInfo = set ? setterType(set, expandType) : undefined;
|
|
2495
|
+
var type = (_ref2 = (_getType$type = getType === null || getType === void 0 ? void 0 : getType.type) !== null && _getType$type !== void 0 ? _getType$type : setInfo === null || setInfo === void 0 ? void 0 : setInfo.type) !== null && _ref2 !== void 0 ? _ref2 : 'any';
|
|
2496
|
+
record(ctx.fields, name, {
|
|
2497
|
+
type: type,
|
|
2498
|
+
rank: getType || setInfo !== null && setInfo !== void 0 && setInfo.jsdoc ? FIELD_JSDOC : FIELD_INFER,
|
|
2499
|
+
jsdoc: Boolean(getType || (setInfo === null || setInfo === void 0 ? void 0 : setInfo.jsdoc)),
|
|
2500
|
+
raw: (_getType$raw = getType === null || getType === void 0 ? void 0 : getType.raw) !== null && _getType$raw !== void 0 ? _getType$raw : setInfo === null || setInfo === void 0 ? void 0 : setInfo.raw,
|
|
2501
|
+
readonly: !set
|
|
2502
|
+
}, warn, className);
|
|
2503
|
+
}
|
|
2504
|
+
for (var _i2 = 0, _Object$keys2 = Object.keys(ctx.sets); _i2 < _Object$keys2.length; _i2++) {
|
|
2505
|
+
var _name = _Object$keys2[_i2];
|
|
2506
|
+
if (ctx.gets[_name]) {
|
|
2507
|
+
continue;
|
|
2508
|
+
}
|
|
2509
|
+
var _setInfo = setterType(ctx.sets[_name], expandType);
|
|
2510
|
+
record(ctx.fields, _name, {
|
|
2511
|
+
type: _setInfo.type,
|
|
2512
|
+
rank: _setInfo.jsdoc ? FIELD_JSDOC : FIELD_INFER,
|
|
2513
|
+
jsdoc: _setInfo.jsdoc,
|
|
2514
|
+
raw: _setInfo.raw
|
|
2515
|
+
}, warn, className);
|
|
2516
|
+
}
|
|
2517
|
+
if (ctor && ctor.body) {
|
|
2518
|
+
var _iterator8 = _createForOfIteratorHelper(ctor.body.body),
|
|
2519
|
+
_step8;
|
|
2520
|
+
try {
|
|
2521
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
2522
|
+
var st = _step8.value;
|
|
2523
|
+
walkStatement(st, false, ctx);
|
|
2524
|
+
}
|
|
2525
|
+
} catch (err) {
|
|
2526
|
+
_iterator8.e(err);
|
|
2527
|
+
} finally {
|
|
2528
|
+
_iterator8.f();
|
|
2529
|
+
}
|
|
1408
2530
|
}
|
|
2531
|
+
var properties = {};
|
|
2532
|
+
for (var _i3 = 0, _Object$keys3 = Object.keys(ctx.fields); _i3 < _Object$keys3.length; _i3++) {
|
|
2533
|
+
var _name2 = _Object$keys3[_i3];
|
|
2534
|
+
properties[_name2] = entryToType(ctx.fields[_name2]);
|
|
2535
|
+
}
|
|
2536
|
+
if (!Object.keys(properties).length) {
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
return {
|
|
2540
|
+
name: className,
|
|
2541
|
+
shape: {
|
|
2542
|
+
type: 'object',
|
|
2543
|
+
properties: properties
|
|
2544
|
+
}
|
|
2545
|
+
};
|
|
1409
2546
|
}
|
|
1410
2547
|
|
|
1411
2548
|
/**
|
|
@@ -1454,101 +2591,6 @@
|
|
|
1454
2591
|
return false;
|
|
1455
2592
|
}
|
|
1456
2593
|
|
|
1457
|
-
/**
|
|
1458
|
-
* @typedef {ReturnType<typeof parseJSDoc>} ParseJSDocReturnType
|
|
1459
|
-
*/
|
|
1460
|
-
/**
|
|
1461
|
-
* @typedef {typeof expandTypeDepFree} ExpandType
|
|
1462
|
-
* @typedef {ReturnType<ExpandType>} ExpandTypeReturnType
|
|
1463
|
-
*/
|
|
1464
|
-
/**
|
|
1465
|
-
* Parses JSDoc comments to extract parameter type information.
|
|
1466
|
-
*
|
|
1467
|
-
* @param {string} src - The JSDoc comment string to parse.
|
|
1468
|
-
* @param {ExpandType} [expandType] - An optional function to process the types found in the JSDoc.
|
|
1469
|
-
* @returns {Record<string, ExpandTypeReturnType> | undefined} An object mapping parameter names to their parsed types, or undefined if no parameters are found.
|
|
1470
|
-
*/
|
|
1471
|
-
function parseJSDoc(src) {
|
|
1472
|
-
var expandType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : expandTypeDepFree;
|
|
1473
|
-
// Parse something like: @param {Object} [kwargs={}] Optional arguments.
|
|
1474
|
-
var regex = /@param \{(.*?)\} ([\[\]a-zA-Z0-9_$=\-\{\}\.'" ]+)/g;
|
|
1475
|
-
var matches = _toConsumableArray(src.matchAll(regex));
|
|
1476
|
-
/** @type {Record<string, ExpandTypeReturnType>} */
|
|
1477
|
-
var params = Object.create(null);
|
|
1478
|
-
matches.forEach(function (_) {
|
|
1479
|
-
var type = expandType(_[1].trim());
|
|
1480
|
-
var name = _[2].trim();
|
|
1481
|
-
var optional = false;
|
|
1482
|
-
// Examples:
|
|
1483
|
-
// name: [kwargs={}] The configuration parameters.
|
|
1484
|
-
// name: [d = 1.0] Sample spacing
|
|
1485
|
-
if (name[0] === '[') {
|
|
1486
|
-
// Counting opening/closing brackets for perfect match
|
|
1487
|
-
var openCloseCount = 1;
|
|
1488
|
-
var i = 1;
|
|
1489
|
-
for (; i < name.length; i++) {
|
|
1490
|
-
var c = name[i];
|
|
1491
|
-
if (c === '[') {
|
|
1492
|
-
openCloseCount++;
|
|
1493
|
-
} else if (c === ']') {
|
|
1494
|
-
openCloseCount--;
|
|
1495
|
-
}
|
|
1496
|
-
if (openCloseCount === 0) {
|
|
1497
|
-
break;
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
// Afterwards name will be: d = 1.0
|
|
1501
|
-
name = name.substring(1, i);
|
|
1502
|
-
// mark it for the type:
|
|
1503
|
-
optional = true;
|
|
1504
|
-
}
|
|
1505
|
-
// Strip the rest (either leftover of optional value or description)
|
|
1506
|
-
name = name.split(' ')[0].split('=')[0].trim();
|
|
1507
|
-
var annotatedType = annotateOptional(type, optional);
|
|
1508
|
-
// Turn "options.stats[].unitsName" into ['options', 'stats', 'unitsName'].
|
|
1509
|
-
var parts = name.split(/[\[\]]*\./);
|
|
1510
|
-
var properties = params;
|
|
1511
|
-
var _iterator = _createForOfIteratorHelper(parts),
|
|
1512
|
-
_step;
|
|
1513
|
-
try {
|
|
1514
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1515
|
-
var part = _step.value;
|
|
1516
|
-
var toptype = properties[part];
|
|
1517
|
-
if (!toptype) {
|
|
1518
|
-
// No toptype means we resolved as far as possible, now we can add `annotatedType`.
|
|
1519
|
-
console.assert(part === parts.at(-1), 'Current part and last part should be the same.');
|
|
1520
|
-
properties[part] = annotatedType;
|
|
1521
|
-
} else if (toptype.type === "union") {
|
|
1522
|
-
var typeObject = toptype.members.find(function (_) {
|
|
1523
|
-
return (_ === null || _ === void 0 ? void 0 : _.type) === 'object';
|
|
1524
|
-
});
|
|
1525
|
-
properties = typeObject.properties;
|
|
1526
|
-
} else if (toptype.type === "array") {
|
|
1527
|
-
properties = toptype.elementType.properties;
|
|
1528
|
-
} else if (toptype.type === "object") {
|
|
1529
|
-
toptype.properties = toptype.properties || Object.create(null);
|
|
1530
|
-
properties = toptype.properties;
|
|
1531
|
-
} else {
|
|
1532
|
-
console.warn("parseJSDoc> Skipping @param, unseen syntax detected. Please check if your JSDoc is valid or open an issue about this!", {
|
|
1533
|
-
src: src,
|
|
1534
|
-
toptype: toptype,
|
|
1535
|
-
parts: parts,
|
|
1536
|
-
annotatedType: annotatedType
|
|
1537
|
-
});
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
} catch (err) {
|
|
1541
|
-
_iterator.e(err);
|
|
1542
|
-
} finally {
|
|
1543
|
-
_iterator.f();
|
|
1544
|
-
}
|
|
1545
|
-
});
|
|
1546
|
-
if (Object.keys(params).length === 0) {
|
|
1547
|
-
return;
|
|
1548
|
-
}
|
|
1549
|
-
return params;
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
2594
|
/**
|
|
1553
2595
|
* @param {string} src - JSDoc comment of the setter.
|
|
1554
2596
|
* @param {Function} expandType - The expandType function.
|
|
@@ -1583,9 +2625,6 @@
|
|
|
1583
2625
|
var expandType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : expandTypeDepFree;
|
|
1584
2626
|
var regexTemplateTyped = /@template \{(.*?)\} ([a-zA-Z0-9_$=]+)/g;
|
|
1585
2627
|
var matches = _toConsumableArray(src.matchAll(regexTemplateTyped));
|
|
1586
|
-
if (!matches.length) {
|
|
1587
|
-
return;
|
|
1588
|
-
}
|
|
1589
2628
|
/** @type {Record<string, ExpandTypeReturnType>} */
|
|
1590
2629
|
var templates = Object.create(null);
|
|
1591
2630
|
matches.forEach(function (_) {
|
|
@@ -1593,6 +2632,40 @@
|
|
|
1593
2632
|
var name = _[2].trim();
|
|
1594
2633
|
templates[name] = type;
|
|
1595
2634
|
});
|
|
2635
|
+
// `@template [A=X]` defaults: constraint X under name A.
|
|
2636
|
+
var regexTemplateDefault = /@template \[([a-zA-Z0-9_$]+)=([^\]]+)\]/g;
|
|
2637
|
+
var _iterator = _createForOfIteratorHelper(src.matchAll(regexTemplateDefault)),
|
|
2638
|
+
_step;
|
|
2639
|
+
try {
|
|
2640
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
2641
|
+
var match = _step.value;
|
|
2642
|
+
templates[match[1]] = expandType(match[2].trim());
|
|
2643
|
+
}
|
|
2644
|
+
// Bare `@template T`: unconstrained, stands in as any.
|
|
2645
|
+
} catch (err) {
|
|
2646
|
+
_iterator.e(err);
|
|
2647
|
+
} finally {
|
|
2648
|
+
_iterator.f();
|
|
2649
|
+
}
|
|
2650
|
+
var regexTemplateBare = /@template ([a-zA-Z0-9_$]+)(?![a-zA-Z0-9_$])/g;
|
|
2651
|
+
var _iterator2 = _createForOfIteratorHelper(src.matchAll(regexTemplateBare)),
|
|
2652
|
+
_step2;
|
|
2653
|
+
try {
|
|
2654
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
2655
|
+
var _match = _step2.value;
|
|
2656
|
+
var name = _match[1];
|
|
2657
|
+
if (!(name in templates)) {
|
|
2658
|
+
templates[name] = 'any';
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
} catch (err) {
|
|
2662
|
+
_iterator2.e(err);
|
|
2663
|
+
} finally {
|
|
2664
|
+
_iterator2.f();
|
|
2665
|
+
}
|
|
2666
|
+
if (!Object.keys(templates).length) {
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
1596
2669
|
return templates;
|
|
1597
2670
|
}
|
|
1598
2671
|
|
|
@@ -3934,6 +5007,8 @@
|
|
|
3934
5007
|
});
|
|
3935
5008
|
/** @type {Record<string, object>} */
|
|
3936
5009
|
_defineProperty(_assertThisInitialized(_this), "typedefs", {});
|
|
5010
|
+
/** @type {Record<string, string[]>} */
|
|
5011
|
+
_defineProperty(_assertThisInitialized(_this), "typedefTemplates", {});
|
|
3937
5012
|
/** @type {string[]} */
|
|
3938
5013
|
_defineProperty(_assertThisInitialized(_this), "addLaterImportNamespaceSpecifier", []);
|
|
3939
5014
|
_this.forceCurly = forceCurly;
|
|
@@ -3996,6 +5071,21 @@
|
|
|
3996
5071
|
var id_ = this.toSource(id);
|
|
3997
5072
|
var out = _get(_getPrototypeOf(Asserter.prototype), "ClassDeclaration", this).call(this, node);
|
|
3998
5073
|
out += "".concat(this.spaces, "registerClass(").concat(id_, ");");
|
|
5074
|
+
var harvested = harvestClassShape(node, {
|
|
5075
|
+
expandType: this.expandType,
|
|
5076
|
+
warn: this.warn.bind(this)
|
|
5077
|
+
});
|
|
5078
|
+
if (harvested) {
|
|
5079
|
+
// Hand-written typedefs win: emitting a second registerTypedef for the
|
|
5080
|
+
// same name would be last-wins deterministic but noisy, so the harvest
|
|
5081
|
+
// step skips names already present in this.typedefs (populated in File).
|
|
5082
|
+
if (this.typedefs[harvested.name]) {
|
|
5083
|
+
this.warn("harvestClassShape: skipping harvested shape for '".concat(harvested.name, "', hand-written typedef wins"));
|
|
5084
|
+
} else {
|
|
5085
|
+
var json = simplifyTypeToSource(harvested.shape);
|
|
5086
|
+
out += "\n".concat(this.spaces, "registerTypedef('").concat(harvested.name, "', ").concat(json, ");");
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
3999
5089
|
return out;
|
|
4000
5090
|
}
|
|
4001
5091
|
/**
|
|
@@ -4910,7 +6000,7 @@
|
|
|
4910
6000
|
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
4911
6001
|
var comment = _step5.value;
|
|
4912
6002
|
var warn = this.warn.bind(this);
|
|
4913
|
-
parseJSDocTypedef(this.typedefs, warn, comment, this.expandType);
|
|
6003
|
+
parseJSDocTypedef(this.typedefs, this.typedefTemplates, warn, comment, this.expandType);
|
|
4914
6004
|
}
|
|
4915
6005
|
} catch (err) {
|
|
4916
6006
|
_iterator5.e(err);
|
|
@@ -4923,7 +6013,8 @@
|
|
|
4923
6013
|
for (var name in this.typedefs) {
|
|
4924
6014
|
var typedef = this.typedefs[name];
|
|
4925
6015
|
var json = simplifyTypeToSource(typedef);
|
|
4926
|
-
|
|
6016
|
+
var params = this.typedefTemplates[name];
|
|
6017
|
+
out += params !== null && params !== void 0 && params.length ? "registerTypedef('".concat(name, "', ").concat(json, ", ").concat(JSON.stringify(params), ");\n") : "registerTypedef('".concat(name, "', ").concat(json, ");\n");
|
|
4927
6018
|
}
|
|
4928
6019
|
var code = this.toSource(program) + '\n';
|
|
4929
6020
|
out += code;
|
|
@@ -5214,7 +6305,13 @@
|
|
|
5214
6305
|
{
|
|
5215
6306
|
var name = toSourceBabelTS(node.typeName);
|
|
5216
6307
|
if (!node.typeParameters) {
|
|
5217
|
-
//
|
|
6308
|
+
// Bare `Object` is the empty object type, matching expandType().
|
|
6309
|
+
if (name === 'Object') {
|
|
6310
|
+
return {
|
|
6311
|
+
type: 'object',
|
|
6312
|
+
properties: {}
|
|
6313
|
+
};
|
|
6314
|
+
}
|
|
5218
6315
|
// Bare reference: Identifier gives name, TSQualifiedName gives dotted path.
|
|
5219
6316
|
return name;
|
|
5220
6317
|
}
|
|
@@ -5275,6 +6372,8 @@
|
|
|
5275
6372
|
}
|
|
5276
6373
|
case 'TSStringKeyword':
|
|
5277
6374
|
return 'string';
|
|
6375
|
+
case 'TSSymbolKeyword':
|
|
6376
|
+
return 'symbol';
|
|
5278
6377
|
case 'TSNumberKeyword':
|
|
5279
6378
|
return 'number';
|
|
5280
6379
|
case 'TSIntersectionType':
|
|
@@ -5356,6 +6455,8 @@
|
|
|
5356
6455
|
case 'ParenthesizedType':
|
|
5357
6456
|
// fall-through for parentheses
|
|
5358
6457
|
return toSourceBabelTS(node.type);
|
|
6458
|
+
case 'TSParenthesizedType':
|
|
6459
|
+
return toSourceBabelTS(node.typeAnnotation);
|
|
5359
6460
|
case 'LastTypeNode':
|
|
5360
6461
|
return toSourceBabelTS(node.qualifier);
|
|
5361
6462
|
case 'TSTypeQuery':
|
|
@@ -5364,11 +6465,129 @@
|
|
|
5364
6465
|
type: 'typeof',
|
|
5365
6466
|
argument: argument
|
|
5366
6467
|
};
|
|
6468
|
+
case 'TSConditionalType':
|
|
6469
|
+
{
|
|
6470
|
+
var checkType = toSourceBabelTS(node.checkType);
|
|
6471
|
+
var extendsType = toSourceBabelTS(node.extendsType);
|
|
6472
|
+
var trueType = toSourceBabelTS(node.trueType);
|
|
6473
|
+
var falseType = toSourceBabelTS(node.falseType);
|
|
6474
|
+
return {
|
|
6475
|
+
type: 'condition',
|
|
6476
|
+
checkType: checkType,
|
|
6477
|
+
extendsType: extendsType,
|
|
6478
|
+
trueType: trueType,
|
|
6479
|
+
falseType: falseType
|
|
6480
|
+
};
|
|
6481
|
+
}
|
|
6482
|
+
case 'TSIndexedAccessType':
|
|
6483
|
+
{
|
|
6484
|
+
var index = toSourceBabelTS(node.indexType);
|
|
6485
|
+
var object = toSourceBabelTS(node.objectType);
|
|
6486
|
+
return {
|
|
6487
|
+
type: 'indexedAccess',
|
|
6488
|
+
index: index,
|
|
6489
|
+
object: object
|
|
6490
|
+
};
|
|
6491
|
+
}
|
|
6492
|
+
case 'TSMappedType':
|
|
6493
|
+
{
|
|
6494
|
+
var param = node.typeParameter;
|
|
6495
|
+
var nameNode = param === null || param === void 0 ? void 0 : param.name;
|
|
6496
|
+
var element = typeof nameNode === 'string' ? nameNode : toSourceBabelTS(nameNode);
|
|
6497
|
+
var iterable = toSourceBabelTS(param === null || param === void 0 ? void 0 : param.constraint);
|
|
6498
|
+
var result = toSourceBabelTS(node.typeAnnotation);
|
|
6499
|
+
var out = {
|
|
6500
|
+
type: 'mapping',
|
|
6501
|
+
iterable: iterable,
|
|
6502
|
+
element: element,
|
|
6503
|
+
result: result
|
|
6504
|
+
};
|
|
6505
|
+
if (node.nameType) {
|
|
6506
|
+
out.nameType = toSourceBabelTS(node.nameType);
|
|
6507
|
+
}
|
|
6508
|
+
if (node.optional !== undefined && node.optional !== false && node.optional !== null) {
|
|
6509
|
+
out.question = node.optional === '-' ? '-' : node.optional === '+' ? '+' : '?';
|
|
6510
|
+
}
|
|
6511
|
+
if (node.readonly !== undefined && node.readonly !== false && node.readonly !== null) {
|
|
6512
|
+
out.readonly = node.readonly === '-' ? '-' : node.readonly === '+' ? '+' : 'readonly';
|
|
6513
|
+
}
|
|
6514
|
+
return out;
|
|
6515
|
+
}
|
|
6516
|
+
case 'TSTypeAnnotation':
|
|
6517
|
+
return toSourceBabelTS(node.typeAnnotation);
|
|
6518
|
+
case 'TSTypeLiteral':
|
|
6519
|
+
{
|
|
6520
|
+
var _node$members;
|
|
6521
|
+
var _properties = {};
|
|
6522
|
+
var indexSignatures;
|
|
6523
|
+
var _iterator = _createForOfIteratorHelper((_node$members = node.members) !== null && _node$members !== void 0 ? _node$members : []),
|
|
6524
|
+
_step;
|
|
6525
|
+
try {
|
|
6526
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
6527
|
+
var member = _step.value;
|
|
6528
|
+
if (member.type === 'TSIndexSignature') {
|
|
6529
|
+
var _indexSignatures;
|
|
6530
|
+
indexSignatures = (_indexSignatures = indexSignatures) !== null && _indexSignatures !== void 0 ? _indexSignatures : [];
|
|
6531
|
+
indexSignatures.push(toSourceBabelTS(member));
|
|
6532
|
+
} else if (member.type === 'TSPropertySignature') {
|
|
6533
|
+
var _name = toSourceBabelTS(member.key);
|
|
6534
|
+
var type = toSourceBabelTS(member.typeAnnotation);
|
|
6535
|
+
if (member.optional) {
|
|
6536
|
+
if (type && _typeof(type) === 'object') type.optional = true;else type = {
|
|
6537
|
+
type: type,
|
|
6538
|
+
optional: true
|
|
6539
|
+
};
|
|
6540
|
+
}
|
|
6541
|
+
if (member.readonly) {
|
|
6542
|
+
if (type && _typeof(type) === 'object') type.readonly = true;else type = {
|
|
6543
|
+
type: type,
|
|
6544
|
+
readonly: true
|
|
6545
|
+
};
|
|
6546
|
+
}
|
|
6547
|
+
_properties[_name] = type;
|
|
6548
|
+
} else {
|
|
6549
|
+
console.warn('TSTypeLiteral: unhandled member', member.type);
|
|
6550
|
+
}
|
|
6551
|
+
}
|
|
6552
|
+
} catch (err) {
|
|
6553
|
+
_iterator.e(err);
|
|
6554
|
+
} finally {
|
|
6555
|
+
_iterator.f();
|
|
6556
|
+
}
|
|
6557
|
+
var ret = {
|
|
6558
|
+
type: 'object'
|
|
6559
|
+
};
|
|
6560
|
+
if (Object.keys(_properties).length) {
|
|
6561
|
+
ret.properties = _properties;
|
|
6562
|
+
}
|
|
6563
|
+
if (indexSignatures) {
|
|
6564
|
+
ret.indexSignatures = indexSignatures;
|
|
6565
|
+
}
|
|
6566
|
+
return ret;
|
|
6567
|
+
}
|
|
6568
|
+
case 'TSIndexSignature':
|
|
6569
|
+
{
|
|
6570
|
+
var _node$parameters;
|
|
6571
|
+
var indexType = toSourceBabelTS(node.typeAnnotation);
|
|
6572
|
+
var indexParameters = ((_node$parameters = node.parameters) !== null && _node$parameters !== void 0 ? _node$parameters : []).map(toSourceBabelTS);
|
|
6573
|
+
return {
|
|
6574
|
+
type: 'indexSignature',
|
|
6575
|
+
indexType: indexType,
|
|
6576
|
+
indexParameters: indexParameters
|
|
6577
|
+
};
|
|
6578
|
+
}
|
|
5367
6579
|
case 'TSTypeOperator':
|
|
5368
6580
|
if (node.operator === 'readonly') {
|
|
5369
6581
|
// readonly erased at runtime, same shape as the inner type.
|
|
5370
6582
|
return toSourceBabelTS(node.typeAnnotation);
|
|
5371
6583
|
}
|
|
6584
|
+
if (node.operator === 'keyof') {
|
|
6585
|
+
var keyofArg = toSourceBabelTS(node.typeAnnotation);
|
|
6586
|
+
return {
|
|
6587
|
+
type: 'keyof',
|
|
6588
|
+
argument: keyofArg
|
|
6589
|
+
};
|
|
6590
|
+
}
|
|
5372
6591
|
console.warn('unimplemented TSTypeOperator', node.operator);
|
|
5373
6592
|
return 'any';
|
|
5374
6593
|
case 'TSQualifiedName':
|
|
@@ -5501,6 +6720,8 @@
|
|
|
5501
6720
|
_defineProperty(this, "parents", []);
|
|
5502
6721
|
/** @type {Record<string, object>} */
|
|
5503
6722
|
_defineProperty(this, "typedefs", {});
|
|
6723
|
+
/** @type {Record<string, string[]>} */
|
|
6724
|
+
_defineProperty(this, "typedefTemplates", {});
|
|
5504
6725
|
/** @type {import('./parseJSDoc.js').ExpandType} */
|
|
5505
6726
|
this.expandType = options.expandType || expandTypeDepFree;
|
|
5506
6727
|
}
|
|
@@ -5521,7 +6742,7 @@
|
|
|
5521
6742
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
5522
6743
|
var comment = _step.value;
|
|
5523
6744
|
var warn = console.warn.bind(console);
|
|
5524
|
-
parseJSDocTypedef(this.typedefs, warn, comment, this.expandType);
|
|
6745
|
+
parseJSDocTypedef(this.typedefs, this.typedefTemplates, warn, comment, this.expandType);
|
|
5525
6746
|
}
|
|
5526
6747
|
} catch (err) {
|
|
5527
6748
|
_iterator.e(err);
|