jsii 5.8.22-dev.9 → 5.8.23-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/assembler.d.ts +24 -1
- package/lib/assembler.js +268 -38
- package/lib/assembler.js.map +1 -1
- package/lib/helpers.d.ts +37 -3
- package/lib/helpers.js +27 -6
- package/lib/helpers.js.map +1 -1
- package/lib/jsii-diagnostic.d.ts +5 -0
- package/lib/jsii-diagnostic.js +25 -0
- package/lib/jsii-diagnostic.js.map +1 -1
- package/lib/project-info.js +2 -1
- package/lib/project-info.js.map +1 -1
- package/lib/sets.d.ts +16 -0
- package/lib/sets.js +41 -0
- package/lib/sets.js.map +1 -0
- package/lib/type-analysis.d.ts +11 -0
- package/lib/type-analysis.js +123 -0
- package/lib/type-analysis.js.map +1 -0
- package/lib/type-reference.d.ts +20 -0
- package/lib/type-reference.js +75 -0
- package/lib/type-reference.js.map +1 -0
- package/lib/type-visitor.d.ts +19 -0
- package/lib/type-visitor.js +51 -0
- package/lib/type-visitor.js.map +1 -0
- package/lib/validator.d.ts +6 -2
- package/lib/validator.js +62 -34
- package/lib/validator.js.map +1 -1
- package/lib/version.d.ts +2 -2
- package/lib/version.js +2 -2
- package/lib/version.js.map +1 -1
- package/package.json +4 -4
- package/testspee/.eslintrc.js +3 -0
- package/testspee/LICENSE +201 -0
- package/testspee/NOTICE +406 -0
- package/testspee/README.md +1305 -0
- package/testspee/scripts/minify-sources.sh +26 -0
- package/testspee/scripts/verify-imports-resolve-same.ts +142 -0
- package/testspee/scripts/verify-imports-shielded.ts +57 -0
- package/testspee/scripts/verify-stripped-exp.ts +158 -0
package/lib/assembler.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare class Assembler implements Emitter {
|
|
|
15
15
|
private readonly mainFile;
|
|
16
16
|
private readonly tscRootDir?;
|
|
17
17
|
private readonly compressAssembly?;
|
|
18
|
+
private readonly usedFeatures;
|
|
18
19
|
private readonly _typeChecker;
|
|
19
20
|
private _diagnostics;
|
|
20
21
|
private _deferred;
|
|
@@ -56,7 +57,7 @@ export declare class Assembler implements Emitter {
|
|
|
56
57
|
*
|
|
57
58
|
* @param fqn FQN of the current type (the type that has a dependency on baseTypes)
|
|
58
59
|
* @param baseTypes Array of type references to be looked up
|
|
59
|
-
* @param referencingNode Node to report a diagnostic on if we fail to look up a
|
|
60
|
+
* @param referencingNode Node to report a diagnostic on if we fail to look up a type
|
|
60
61
|
* @param cb Callback to be invoked with the Types corresponding to the TypeReferences in baseTypes
|
|
61
62
|
*/
|
|
62
63
|
private _deferUntilTypesAvailable;
|
|
@@ -164,11 +165,26 @@ export declare class Assembler implements Emitter {
|
|
|
164
165
|
private _toParameter;
|
|
165
166
|
private _typeReference;
|
|
166
167
|
private _optionalValue;
|
|
168
|
+
/**
|
|
169
|
+
* Validate the restrictions on an intersection type reference
|
|
170
|
+
*
|
|
171
|
+
* - Type only consists of (behavioral) interface types
|
|
172
|
+
* - For all types referenced in the intersection, the definitions of all shared
|
|
173
|
+
* members must match exactly.
|
|
174
|
+
*/
|
|
175
|
+
private validateIntersectionType;
|
|
176
|
+
private comparePropForIntersection;
|
|
177
|
+
private compareMethodForIntersection;
|
|
167
178
|
private callDeferredsInOrder;
|
|
168
179
|
/**
|
|
169
180
|
* Return the set of all (inherited) properties of an interface
|
|
170
181
|
*/
|
|
171
182
|
private allProperties;
|
|
183
|
+
/**
|
|
184
|
+
* Return the set of all (inherited) methods of an interface
|
|
185
|
+
*/
|
|
186
|
+
private allMethods;
|
|
187
|
+
private allInterfacesRecursively;
|
|
172
188
|
private _verifyConsecutiveOptionals;
|
|
173
189
|
/**
|
|
174
190
|
* Updates the runtime type info with the fully-qualified name for the current class definition.
|
|
@@ -181,6 +197,13 @@ export declare class Assembler implements Emitter {
|
|
|
181
197
|
*/
|
|
182
198
|
private mySubmodules;
|
|
183
199
|
private findPackageInfo;
|
|
200
|
+
/**
|
|
201
|
+
* Validate types against input/output positions in functions and APIs
|
|
202
|
+
*
|
|
203
|
+
* Currently used to validate that intersection types are only used in input position,
|
|
204
|
+
* not output position
|
|
205
|
+
*/
|
|
206
|
+
private validateTypesAgainstPositions;
|
|
184
207
|
}
|
|
185
208
|
export interface AssemblerOptions {
|
|
186
209
|
/**
|
package/lib/assembler.js
CHANGED
|
@@ -19,10 +19,13 @@ const jsii_diagnostic_1 = require("./jsii-diagnostic");
|
|
|
19
19
|
const literate = require("./literate");
|
|
20
20
|
const bindings = require("./node-bindings");
|
|
21
21
|
const reserved_words_1 = require("./reserved-words");
|
|
22
|
+
const sets_1 = require("./sets");
|
|
22
23
|
const deprecated_remover_1 = require("./transforms/deprecated-remover");
|
|
23
24
|
const deprecation_warnings_1 = require("./transforms/deprecation-warnings");
|
|
24
25
|
const runtime_info_1 = require("./transforms/runtime-info");
|
|
25
26
|
const utils_1 = require("./transforms/utils");
|
|
27
|
+
const type_reference_1 = require("./type-reference");
|
|
28
|
+
const type_visitor_1 = require("./type-visitor");
|
|
26
29
|
const utils_2 = require("./utils");
|
|
27
30
|
const validator_1 = require("./validator");
|
|
28
31
|
const version_1 = require("./version");
|
|
@@ -44,6 +47,7 @@ class Assembler {
|
|
|
44
47
|
this.system = system;
|
|
45
48
|
this.program = program;
|
|
46
49
|
this.stdlib = stdlib;
|
|
50
|
+
this.usedFeatures = new Set();
|
|
47
51
|
this._diagnostics = new Array();
|
|
48
52
|
this._deferred = new Array();
|
|
49
53
|
this._types = new Map();
|
|
@@ -135,6 +139,7 @@ class Assembler {
|
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
this.callDeferredsInOrder();
|
|
142
|
+
this.validateTypesAgainstPositions();
|
|
138
143
|
// Skip emitting if any diagnostic message is an error
|
|
139
144
|
if (this._diagnostics.find((diag) => diag.category === ts.DiagnosticCategory.Error) != null) {
|
|
140
145
|
LOG.debug('Skipping emit due to errors.');
|
|
@@ -178,6 +183,7 @@ class Assembler {
|
|
|
178
183
|
jsiiVersion,
|
|
179
184
|
bin: this.projectInfo.bin,
|
|
180
185
|
fingerprint: '<TBD>',
|
|
186
|
+
usedFeatures: _assemblyFeatures(this.usedFeatures), // might be appended later
|
|
181
187
|
};
|
|
182
188
|
if (this.deprecatedRemover) {
|
|
183
189
|
this._diagnostics.push(...this.deprecatedRemover.removeFrom(assembly));
|
|
@@ -197,6 +203,13 @@ class Assembler {
|
|
|
197
203
|
}
|
|
198
204
|
const validator = new validator_1.Validator(this.projectInfo, assembly);
|
|
199
205
|
const validationResult = validator.emit();
|
|
206
|
+
// Inject detected features
|
|
207
|
+
if (validationResult.usedFeatures) {
|
|
208
|
+
for (const item of validationResult.usedFeatures) {
|
|
209
|
+
this.usedFeatures.add(item);
|
|
210
|
+
}
|
|
211
|
+
assembly.usedFeatures = _assemblyFeatures(this.usedFeatures);
|
|
212
|
+
}
|
|
200
213
|
if (!validationResult.emitSkipped) {
|
|
201
214
|
const zipped = (0, spec_1.writeAssembly)(this.projectInfo.projectRoot, _fingerprint(assembly), {
|
|
202
215
|
compress: this.compressAssembly ?? false,
|
|
@@ -212,6 +225,9 @@ class Assembler {
|
|
|
212
225
|
finally {
|
|
213
226
|
this._afterEmit();
|
|
214
227
|
}
|
|
228
|
+
function _assemblyFeatures(usedFeatures) {
|
|
229
|
+
return usedFeatures.size > 0 ? Array.from(usedFeatures).sort() : undefined;
|
|
230
|
+
}
|
|
215
231
|
function _loadReadme() {
|
|
216
232
|
// Search for `README.md` in a case-insensitive way
|
|
217
233
|
const fileName = fs
|
|
@@ -251,7 +267,7 @@ class Assembler {
|
|
|
251
267
|
*
|
|
252
268
|
* @param fqn FQN of the current type (the type that has a dependency on baseTypes)
|
|
253
269
|
* @param baseTypes Array of type references to be looked up
|
|
254
|
-
* @param referencingNode Node to report a diagnostic on if we fail to look up a
|
|
270
|
+
* @param referencingNode Node to report a diagnostic on if we fail to look up a type
|
|
255
271
|
* @param cb Callback to be invoked with the Types corresponding to the TypeReferences in baseTypes
|
|
256
272
|
*/
|
|
257
273
|
_deferUntilTypesAvailable(fqn, baseTypes, referencingNode, cb) {
|
|
@@ -260,9 +276,19 @@ class Assembler {
|
|
|
260
276
|
cb();
|
|
261
277
|
return;
|
|
262
278
|
}
|
|
263
|
-
const baseFqns = baseTypes.
|
|
279
|
+
const baseFqns = baseTypes.flatMap((bt) => {
|
|
280
|
+
if (typeof bt === 'string') {
|
|
281
|
+
return [bt];
|
|
282
|
+
}
|
|
283
|
+
if (spec.isNamedTypeReference(bt)) {
|
|
284
|
+
return [bt.fqn];
|
|
285
|
+
}
|
|
286
|
+
return [];
|
|
287
|
+
});
|
|
264
288
|
this._defer(fqn, baseFqns, () => {
|
|
265
|
-
const resolved = baseFqns
|
|
289
|
+
const resolved = baseFqns
|
|
290
|
+
.map((x) => this._dereference(x, referencingNode, 'used-in-syntax'))
|
|
291
|
+
.filter((x) => x !== undefined);
|
|
266
292
|
if (resolved.length > 0) {
|
|
267
293
|
cb(...resolved);
|
|
268
294
|
}
|
|
@@ -290,7 +316,7 @@ class Assembler {
|
|
|
290
316
|
*
|
|
291
317
|
* @returns the de-referenced type, if it was found, otherwise ``undefined``.
|
|
292
318
|
*/
|
|
293
|
-
_dereference(ref, referencingNode) {
|
|
319
|
+
_dereference(ref, referencingNode, usedInSyntax) {
|
|
294
320
|
if (typeof ref !== 'string') {
|
|
295
321
|
ref = ref.fqn;
|
|
296
322
|
}
|
|
@@ -311,7 +337,7 @@ class Assembler {
|
|
|
311
337
|
}
|
|
312
338
|
}
|
|
313
339
|
}
|
|
314
|
-
if (!type) {
|
|
340
|
+
if (!type && usedInSyntax === 'used-in-syntax') {
|
|
315
341
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_9002_UNRESOLVEABLE_TYPE.create(referencingNode, // Cheating here for now, until the referencingNode can be made required
|
|
316
342
|
ref));
|
|
317
343
|
}
|
|
@@ -390,7 +416,7 @@ class Assembler {
|
|
|
390
416
|
assembly: dep,
|
|
391
417
|
});
|
|
392
418
|
const fqn = (dep && symbolId ? symbolIdIndex(dep)[symbolId] : undefined) ?? fallbackFqn;
|
|
393
|
-
if (!fqn || !this._dereference({ fqn }, sym.valueDeclaration)) {
|
|
419
|
+
if (!fqn || !this._dereference({ fqn }, sym.valueDeclaration, 'used-in-syntax')) {
|
|
394
420
|
if (!hasError) {
|
|
395
421
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_3002_USE_OF_UNEXPORTED_FOREIGN_TYPE.create(typeAnnotationNode, fqn ?? tsName, typeUse, pkg).addRelatedInformationIf(typeDeclaration, 'The referenced type is declared here'));
|
|
396
422
|
hasError = true;
|
|
@@ -1003,9 +1029,12 @@ class Assembler {
|
|
|
1003
1029
|
if (signature) {
|
|
1004
1030
|
for (const param of signature.getParameters()) {
|
|
1005
1031
|
jsiiType.initializer.parameters = jsiiType.initializer.parameters ?? [];
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1032
|
+
const jsiiParam = // eslint-disable-next-line no-await-in-loop
|
|
1033
|
+
this._toParameter(param, ctx.replaceStability(jsiiType.docs?.stability));
|
|
1034
|
+
if (containsIntersection(jsiiParam.type)) {
|
|
1035
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1010_INTERSECTION_NOT_IN_CTOR.create(param.declarations?.[0]));
|
|
1036
|
+
}
|
|
1037
|
+
jsiiType.initializer.parameters.push(jsiiParam);
|
|
1009
1038
|
jsiiType.initializer.variadic = jsiiType.initializer?.parameters?.some((p) => !!p.variadic) || undefined;
|
|
1010
1039
|
jsiiType.initializer.protected =
|
|
1011
1040
|
(ts.getCombinedModifierFlags(ctorDeclaration) & ts.ModifierFlags.Protected) !== 0 || undefined;
|
|
@@ -1067,7 +1096,7 @@ class Assembler {
|
|
|
1067
1096
|
.filter((x) => !x.static)
|
|
1068
1097
|
.map((x) => x.name));
|
|
1069
1098
|
// Intersect
|
|
1070
|
-
for (const member of intersect(statics, nonStatics)) {
|
|
1099
|
+
for (const member of sets_1.Sets.intersect(statics, nonStatics)) {
|
|
1071
1100
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_5013_STATIC_INSTANCE_CONFLICT.create(decl, member, klass));
|
|
1072
1101
|
}
|
|
1073
1102
|
// Check against base classes. They will not contain duplicate member names so we can load
|
|
@@ -1433,7 +1462,7 @@ class Assembler {
|
|
|
1433
1462
|
// Liftable datatype, make sure no parameter names match any of the properties in the datatype
|
|
1434
1463
|
const propNames = this.allProperties(lastParamType);
|
|
1435
1464
|
const paramNames = new Set(parameters.slice(0, parameters.length - 1).map((x) => x.name));
|
|
1436
|
-
const sharedNames = intersection(propNames, paramNames);
|
|
1465
|
+
const sharedNames = sets_1.Sets.intersection(propNames, paramNames);
|
|
1437
1466
|
for (const badName of sharedNames) {
|
|
1438
1467
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_5017_POSITIONAL_KEYWORD_CONFLICT.create(declaration, badName));
|
|
1439
1468
|
}
|
|
@@ -1568,7 +1597,18 @@ class Assembler {
|
|
|
1568
1597
|
return { type: primitiveType };
|
|
1569
1598
|
}
|
|
1570
1599
|
if (type.isUnion() && !_isEnumLike(type)) {
|
|
1571
|
-
return
|
|
1600
|
+
return _setType.call(this, 'union');
|
|
1601
|
+
}
|
|
1602
|
+
if (type.isIntersection()) {
|
|
1603
|
+
this.usedFeatures.add('intersection-types');
|
|
1604
|
+
const ret = _setType.call(this, 'intersection');
|
|
1605
|
+
const intersectionType = ret.type;
|
|
1606
|
+
this.validateIntersectionType(intersectionType, declaration);
|
|
1607
|
+
return ret;
|
|
1608
|
+
}
|
|
1609
|
+
if ((type.getFlags() & ts.TypeFlags.Never) !== 0) {
|
|
1610
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1007_NEVER_TYPE.create(declaration));
|
|
1611
|
+
return { type: spec.CANONICAL_ANY };
|
|
1572
1612
|
}
|
|
1573
1613
|
if (!type.symbol) {
|
|
1574
1614
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1001_TYPE_HAS_NO_SYMBOL.create(declaration));
|
|
@@ -1674,7 +1714,7 @@ class Assembler {
|
|
|
1674
1714
|
// Not a primitive type!
|
|
1675
1715
|
return undefined;
|
|
1676
1716
|
}
|
|
1677
|
-
function
|
|
1717
|
+
function _setType(field) {
|
|
1678
1718
|
const types = new Array();
|
|
1679
1719
|
let optional;
|
|
1680
1720
|
for (const subType of type.types) {
|
|
@@ -1689,16 +1729,112 @@ class Assembler {
|
|
|
1689
1729
|
}
|
|
1690
1730
|
types.push(resolvedType);
|
|
1691
1731
|
}
|
|
1692
|
-
|
|
1732
|
+
const returnedType = {
|
|
1733
|
+
[field]: { types },
|
|
1734
|
+
};
|
|
1735
|
+
return types.length === 1 ? { optional, type: types[0] } : { optional, type: returnedType };
|
|
1693
1736
|
}
|
|
1694
1737
|
}
|
|
1738
|
+
/**
|
|
1739
|
+
* Validate the restrictions on an intersection type reference
|
|
1740
|
+
*
|
|
1741
|
+
* - Type only consists of (behavioral) interface types
|
|
1742
|
+
* - For all types referenced in the intersection, the definitions of all shared
|
|
1743
|
+
* members must match exactly.
|
|
1744
|
+
*/
|
|
1745
|
+
validateIntersectionType(intersectionType, declaration) {
|
|
1746
|
+
// Validate that this intersection type only consists of interface types
|
|
1747
|
+
this._deferUntilTypesAvailable('', intersectionType.intersection.types, declaration, (...elementTypes) => {
|
|
1748
|
+
const requestedFqns = new Set(intersectionType.intersection.types.map(type_reference_1.typeReferenceToString));
|
|
1749
|
+
const resolvedFqns = new Set(elementTypes.map((t) => t.fqn));
|
|
1750
|
+
const unresolved = sets_1.Sets.diff(requestedFqns, resolvedFqns);
|
|
1751
|
+
if (unresolved.size > 0) {
|
|
1752
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1008_ONLY_INTERFACE_INTERSECTION.create(declaration, Array.from(unresolved).join(', ')));
|
|
1753
|
+
}
|
|
1754
|
+
const nonBehavioral = elementTypes.filter((t) => !(0, type_visitor_1.isBehavioralInterfaceType)(t));
|
|
1755
|
+
if (nonBehavioral.length > 0) {
|
|
1756
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1008_ONLY_INTERFACE_INTERSECTION.create(declaration, nonBehavioral.map((t) => t.fqn).join(', ')));
|
|
1757
|
+
}
|
|
1758
|
+
// Check that shared members are the same
|
|
1759
|
+
const interfaces = elementTypes.filter(type_visitor_1.isBehavioralInterfaceType);
|
|
1760
|
+
const allProps = sets_1.Sets.union(...interfaces.map((int) => this.allProperties(int)));
|
|
1761
|
+
const allMethods = sets_1.Sets.union(...interfaces.map((int) => this.allMethods(int)));
|
|
1762
|
+
for (let i = 1; i < interfaces.length; i++) {
|
|
1763
|
+
let int0 = interfaces[0];
|
|
1764
|
+
let int1 = interfaces[i];
|
|
1765
|
+
for (const prop of allProps) {
|
|
1766
|
+
const p1 = int0.properties?.find((p) => p.name === prop);
|
|
1767
|
+
const p2 = int1.properties?.find((p) => p.name === prop);
|
|
1768
|
+
const diff = this.comparePropForIntersection(p1, p2);
|
|
1769
|
+
if (diff) {
|
|
1770
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1011_INTERSECTION_MEMBER_DIFFERENT.create(declaration, prop, int0.name, diff[0], int1.name, diff[1]));
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
for (const meth of allMethods) {
|
|
1774
|
+
const m1 = int0.methods?.find((p) => p.name === meth);
|
|
1775
|
+
const m2 = int1.methods?.find((p) => p.name === meth);
|
|
1776
|
+
const diff = this.compareMethodForIntersection(m1, m2);
|
|
1777
|
+
if (diff) {
|
|
1778
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1011_INTERSECTION_MEMBER_DIFFERENT.create(declaration, meth, int0.name, diff[0], int1.name, diff[1]));
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
comparePropForIntersection(a, b) {
|
|
1785
|
+
if (!a || !b) {
|
|
1786
|
+
return undefined;
|
|
1787
|
+
}
|
|
1788
|
+
if (!(0, type_reference_1.typeReferenceEqual)(a.type, b.type)) {
|
|
1789
|
+
return [(0, type_reference_1.typeReferenceToString)(a.type), (0, type_reference_1.typeReferenceToString)(b.type)];
|
|
1790
|
+
}
|
|
1791
|
+
return (cmpDesc(a.static, b.static, (s) => (s ? 'static' : 'instance member')) ??
|
|
1792
|
+
cmpDesc(a.optional, b.optional, (o) => (o ? 'optional' : 'required')) ??
|
|
1793
|
+
cmpDesc(a.abstract, b.abstract, (s) => (s ? 'abstract' : 'concrete')));
|
|
1794
|
+
}
|
|
1795
|
+
compareMethodForIntersection(a, b) {
|
|
1796
|
+
if (!a || !b) {
|
|
1797
|
+
return undefined;
|
|
1798
|
+
}
|
|
1799
|
+
if (a.returns && b.returns) {
|
|
1800
|
+
if (!(0, type_reference_1.typeReferenceEqual)(a.returns.type, b.returns.type)) {
|
|
1801
|
+
return [(0, type_reference_1.typeReferenceToString)(a.returns.type), (0, type_reference_1.typeReferenceToString)(b.returns.type)];
|
|
1802
|
+
}
|
|
1803
|
+
const x = cmpDesc(a.returns.optional, b.returns.optional, (o) => o ? 'return type optional' : 'return type required');
|
|
1804
|
+
if (x) {
|
|
1805
|
+
return x;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
const paramsA = a.parameters ?? [];
|
|
1809
|
+
const paramsB = b.parameters ?? [];
|
|
1810
|
+
if (paramsA.length !== paramsB.length) {
|
|
1811
|
+
return [`${paramsA.length} parameters`, `${paramsB.length} parameters`];
|
|
1812
|
+
}
|
|
1813
|
+
for (let i = 0; i < paramsA.length; i++) {
|
|
1814
|
+
const p1 = paramsA[i];
|
|
1815
|
+
const p2 = paramsB[i];
|
|
1816
|
+
if (!(0, type_reference_1.typeReferenceEqual)(p1.type, p2.type)) {
|
|
1817
|
+
return [(0, type_reference_1.typeReferenceToString)(p1.type), (0, type_reference_1.typeReferenceToString)(p2.type)];
|
|
1818
|
+
}
|
|
1819
|
+
const x = cmpDesc(p1.optional, p2.optional, (o) => (o ? `parameter ${i + 1} optional` : `parameter ${i + 1} required`)) ??
|
|
1820
|
+
cmpDesc(p1.variadic, p2.variadic, (v) => v ? `parameter ${i + 1} variadic` : `parameter ${i + 1} not variadic`);
|
|
1821
|
+
if (x) {
|
|
1822
|
+
return x;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
return (cmpDesc(a.abstract, b.abstract, (s) => (s ? 'abstract' : 'concrete')) ??
|
|
1826
|
+
cmpDesc(a.async, b.async, (s) => (s ? 'async' : 'async')) ??
|
|
1827
|
+
cmpDesc(a.protected, b.protected, (p) => (p ? 'protected' : 'public')) ??
|
|
1828
|
+
cmpDesc(a.variadic, b.variadic, (v) => (v ? 'variadic' : 'non-variadic')) ??
|
|
1829
|
+
cmpDesc(a.static, b.static, (s) => (s ? 'static' : 'instance member')));
|
|
1830
|
+
}
|
|
1695
1831
|
callDeferredsInOrder() {
|
|
1696
1832
|
// Do a topological call order of all deferreds.
|
|
1697
1833
|
while (this._deferred.length > 0) {
|
|
1698
1834
|
// All fqns in dependency lists that don't have any pending
|
|
1699
1835
|
// deferreds themselves can be executed now, so are removed from
|
|
1700
1836
|
// dependency lists.
|
|
1701
|
-
const pendingFqns = new Set(this._deferred.map((x) => x.fqn));
|
|
1837
|
+
const pendingFqns = new Set(this._deferred.map((x) => x.fqn).filter((x) => x));
|
|
1702
1838
|
for (const deferred of this._deferred) {
|
|
1703
1839
|
restrictDependenciesTo(deferred, pendingFqns);
|
|
1704
1840
|
}
|
|
@@ -1727,20 +1863,33 @@ class Assembler {
|
|
|
1727
1863
|
* Return the set of all (inherited) properties of an interface
|
|
1728
1864
|
*/
|
|
1729
1865
|
allProperties(root) {
|
|
1866
|
+
return this.allInterfacesRecursively(root, (int) => {
|
|
1867
|
+
return (int.properties ?? []).map((p) => p.name);
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Return the set of all (inherited) methods of an interface
|
|
1872
|
+
*/
|
|
1873
|
+
allMethods(root) {
|
|
1874
|
+
return this.allInterfacesRecursively(root, (int) => {
|
|
1875
|
+
return (int.methods ?? []).map((p) => p.name);
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
allInterfacesRecursively(root, cb) {
|
|
1730
1879
|
const ret = new Set();
|
|
1731
1880
|
recurse.call(this, root);
|
|
1732
1881
|
return ret;
|
|
1733
1882
|
function recurse(int) {
|
|
1734
|
-
for (const
|
|
1735
|
-
ret.add(
|
|
1883
|
+
for (const x of cb(int)) {
|
|
1884
|
+
ret.add(x);
|
|
1736
1885
|
}
|
|
1737
1886
|
for (const baseRef of int.interfaces ?? []) {
|
|
1738
|
-
const base = this._dereference(baseRef, undefined);
|
|
1887
|
+
const base = this._dereference(baseRef, undefined, 'used-in-syntax');
|
|
1739
1888
|
if (!base) {
|
|
1740
|
-
throw new Error('Impossible to have unresolvable base in
|
|
1889
|
+
throw new Error('Impossible to have unresolvable base in allInterfacesRecursively()');
|
|
1741
1890
|
}
|
|
1742
1891
|
if (!spec.isInterfaceType(base)) {
|
|
1743
|
-
throw new Error('Impossible to have non-interface base in
|
|
1892
|
+
throw new Error('Impossible to have non-interface base in allInterfacesRecursively()');
|
|
1744
1893
|
}
|
|
1745
1894
|
recurse.call(this, base);
|
|
1746
1895
|
}
|
|
@@ -1796,6 +1945,89 @@ class Assembler {
|
|
|
1796
1945
|
return this.findPackageInfo(parent);
|
|
1797
1946
|
}
|
|
1798
1947
|
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Validate types against input/output positions in functions and APIs
|
|
1950
|
+
*
|
|
1951
|
+
* Currently used to validate that intersection types are only used in input position,
|
|
1952
|
+
* not output position
|
|
1953
|
+
*/
|
|
1954
|
+
validateTypesAgainstPositions() {
|
|
1955
|
+
const self = this;
|
|
1956
|
+
const validatedFqns = {
|
|
1957
|
+
in: new Set(),
|
|
1958
|
+
out: new Set(),
|
|
1959
|
+
};
|
|
1960
|
+
for (const type of this._types.values()) {
|
|
1961
|
+
if (spec.isClassType(type)) {
|
|
1962
|
+
for (const ctorParam of type.initializer?.parameters ?? []) {
|
|
1963
|
+
validateRefFor.call(this, 'in', ctorParam.type, `a constructor parameter of ${type.name}`);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
if (spec.isClassType(type) || (0, type_visitor_1.isBehavioralInterfaceType)(type)) {
|
|
1967
|
+
for (const property of type.properties ?? []) {
|
|
1968
|
+
validateRefFor.call(this, 'out', property.type, `type of property ${type.name}.${property.name}`);
|
|
1969
|
+
}
|
|
1970
|
+
for (const method of type.methods ?? []) {
|
|
1971
|
+
for (const param of method.parameters ?? []) {
|
|
1972
|
+
validateRefFor.call(this, 'in', param.type, `a parameter of method ${type.name}.${method.name}()`);
|
|
1973
|
+
}
|
|
1974
|
+
if (method.returns) {
|
|
1975
|
+
validateRefFor.call(this, 'out', method.returns.type, `return type of method ${type.name}.${method.name}()`);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
function validateRefFor(dir, typeRef, reason) {
|
|
1981
|
+
(0, type_visitor_1.visitTypeReference)(typeRef, {
|
|
1982
|
+
named: (ref) => {
|
|
1983
|
+
// Named types we'll only validate once for every direction
|
|
1984
|
+
if (validatedFqns[dir].has(ref.fqn)) {
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
validatedFqns[dir].add(ref.fqn);
|
|
1988
|
+
const type = self._dereference(ref, undefined, 'just-validating');
|
|
1989
|
+
if (!type) {
|
|
1990
|
+
// Maybe this is an unexported type.
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
validateTypeFor(dir, type, reason);
|
|
1994
|
+
},
|
|
1995
|
+
primitive: () => { },
|
|
1996
|
+
collection: (ref) => {
|
|
1997
|
+
validateRefFor(dir, ref.collection.elementtype, reason);
|
|
1998
|
+
},
|
|
1999
|
+
union: (ref) => {
|
|
2000
|
+
for (const t of ref.union.types) {
|
|
2001
|
+
validateRefFor(dir, t, reason);
|
|
2002
|
+
}
|
|
2003
|
+
},
|
|
2004
|
+
intersection: (ref) => {
|
|
2005
|
+
if (dir === 'out') {
|
|
2006
|
+
self._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1009_INTERSECTION_ONLY_INPUT.createDetached(reason));
|
|
2007
|
+
}
|
|
2008
|
+
for (const t of ref.intersection.types) {
|
|
2009
|
+
validateRefFor(dir, t, reason);
|
|
2010
|
+
}
|
|
2011
|
+
},
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
function validateTypeFor(dir, type, reason) {
|
|
2015
|
+
(0, type_visitor_1.visitType)(type, {
|
|
2016
|
+
dataType: (t) => {
|
|
2017
|
+
// We only need to validate data types, because classes and interfaces
|
|
2018
|
+
// are done as part of the main loop.
|
|
2019
|
+
//
|
|
2020
|
+
// Recurse.
|
|
2021
|
+
for (const prop of t.properties ?? []) {
|
|
2022
|
+
validateRefFor(dir, prop.type, `type of property ${t.name}.${prop.name}, ${reason}`);
|
|
2023
|
+
}
|
|
2024
|
+
},
|
|
2025
|
+
classType: () => { },
|
|
2026
|
+
interfaceType: () => { },
|
|
2027
|
+
enumType: () => { },
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
1799
2031
|
}
|
|
1800
2032
|
exports.Assembler = Assembler;
|
|
1801
2033
|
function _fingerprint(assembly) {
|
|
@@ -1929,18 +2161,6 @@ function last(xs) {
|
|
|
1929
2161
|
function apply(x, fn) {
|
|
1930
2162
|
return x !== undefined ? fn(x) : undefined;
|
|
1931
2163
|
}
|
|
1932
|
-
/**
|
|
1933
|
-
* Return the intersection of two sets
|
|
1934
|
-
*/
|
|
1935
|
-
function intersection(xs, ys) {
|
|
1936
|
-
const ret = new Set();
|
|
1937
|
-
for (const x of xs) {
|
|
1938
|
-
if (ys.has(x)) {
|
|
1939
|
-
ret.add(x);
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
return ret;
|
|
1943
|
-
}
|
|
1944
2164
|
/**
|
|
1945
2165
|
* Return all members names of a JSII interface type
|
|
1946
2166
|
*
|
|
@@ -1971,12 +2191,10 @@ function isInterfaceName(name) {
|
|
|
1971
2191
|
function getConstructor(type) {
|
|
1972
2192
|
return type.symbol.members?.get(ts.InternalSymbolName.Constructor);
|
|
1973
2193
|
}
|
|
1974
|
-
function
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
2194
|
+
function cmpDesc(a, b, desc) {
|
|
2195
|
+
const desc1 = desc(a);
|
|
2196
|
+
const desc2 = desc(b);
|
|
2197
|
+
return desc1 !== desc2 ? [desc1, desc2] : undefined;
|
|
1980
2198
|
}
|
|
1981
2199
|
function noEmptyDict(xs) {
|
|
1982
2200
|
if (xs == null || Object.keys(xs).length === 0) {
|
|
@@ -2160,6 +2378,18 @@ function _findHint(decl, hint) {
|
|
|
2160
2378
|
const [node] = ts.getAllJSDocTags(decl, (tag) => tag.tagName.text === hint);
|
|
2161
2379
|
return node;
|
|
2162
2380
|
}
|
|
2381
|
+
function containsIntersection(type) {
|
|
2382
|
+
if (spec.isIntersectionTypeReference(type)) {
|
|
2383
|
+
return true;
|
|
2384
|
+
}
|
|
2385
|
+
if (spec.isUnionTypeReference(type)) {
|
|
2386
|
+
return type.union.types.some(containsIntersection);
|
|
2387
|
+
}
|
|
2388
|
+
if (spec.isCollectionTypeReference(type)) {
|
|
2389
|
+
return containsIntersection(type.collection.elementtype);
|
|
2390
|
+
}
|
|
2391
|
+
return false;
|
|
2392
|
+
}
|
|
2163
2393
|
/**
|
|
2164
2394
|
* Resolve a Type to Symbol, taking into account single-valued enums which have a bug
|
|
2165
2395
|
*
|