jsii 5.9.5-dev.3 → 5.9.5-dev.4
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 +258 -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 +28 -3
- 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/transforms/deprecated-remover.js +11 -1
- package/lib/transforms/deprecated-remover.js.map +1 -1
- package/lib/type-reference.d.ts +10 -0
- package/lib/type-reference.js +52 -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.js +6 -131
- 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 +2 -2
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: this.usedFeatures.size > 0 ? Array.from(this.usedFeatures) : undefined,
|
181
187
|
};
|
182
188
|
if (this.deprecatedRemover) {
|
183
189
|
this._diagnostics.push(...this.deprecatedRemover.removeFrom(assembly));
|
@@ -251,7 +257,7 @@ class Assembler {
|
|
251
257
|
*
|
252
258
|
* @param fqn FQN of the current type (the type that has a dependency on baseTypes)
|
253
259
|
* @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
|
260
|
+
* @param referencingNode Node to report a diagnostic on if we fail to look up a type
|
255
261
|
* @param cb Callback to be invoked with the Types corresponding to the TypeReferences in baseTypes
|
256
262
|
*/
|
257
263
|
_deferUntilTypesAvailable(fqn, baseTypes, referencingNode, cb) {
|
@@ -260,9 +266,19 @@ class Assembler {
|
|
260
266
|
cb();
|
261
267
|
return;
|
262
268
|
}
|
263
|
-
const baseFqns = baseTypes.
|
269
|
+
const baseFqns = baseTypes.flatMap((bt) => {
|
270
|
+
if (typeof bt === 'string') {
|
271
|
+
return [bt];
|
272
|
+
}
|
273
|
+
if (spec.isNamedTypeReference(bt)) {
|
274
|
+
return [bt.fqn];
|
275
|
+
}
|
276
|
+
return [];
|
277
|
+
});
|
264
278
|
this._defer(fqn, baseFqns, () => {
|
265
|
-
const resolved = baseFqns
|
279
|
+
const resolved = baseFqns
|
280
|
+
.map((x) => this._dereference(x, referencingNode, 'used-in-syntax'))
|
281
|
+
.filter((x) => x !== undefined);
|
266
282
|
if (resolved.length > 0) {
|
267
283
|
cb(...resolved);
|
268
284
|
}
|
@@ -290,7 +306,7 @@ class Assembler {
|
|
290
306
|
*
|
291
307
|
* @returns the de-referenced type, if it was found, otherwise ``undefined``.
|
292
308
|
*/
|
293
|
-
_dereference(ref, referencingNode) {
|
309
|
+
_dereference(ref, referencingNode, usedInSyntax) {
|
294
310
|
if (typeof ref !== 'string') {
|
295
311
|
ref = ref.fqn;
|
296
312
|
}
|
@@ -311,7 +327,7 @@ class Assembler {
|
|
311
327
|
}
|
312
328
|
}
|
313
329
|
}
|
314
|
-
if (!type) {
|
330
|
+
if (!type && usedInSyntax === 'used-in-syntax') {
|
315
331
|
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
332
|
ref));
|
317
333
|
}
|
@@ -390,7 +406,7 @@ class Assembler {
|
|
390
406
|
assembly: dep,
|
391
407
|
});
|
392
408
|
const fqn = (dep && symbolId ? symbolIdIndex(dep)[symbolId] : undefined) ?? fallbackFqn;
|
393
|
-
if (!fqn || !this._dereference({ fqn }, sym.valueDeclaration)) {
|
409
|
+
if (!fqn || !this._dereference({ fqn }, sym.valueDeclaration, 'used-in-syntax')) {
|
394
410
|
if (!hasError) {
|
395
411
|
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
412
|
hasError = true;
|
@@ -1003,9 +1019,12 @@ class Assembler {
|
|
1003
1019
|
if (signature) {
|
1004
1020
|
for (const param of signature.getParameters()) {
|
1005
1021
|
jsiiType.initializer.parameters = jsiiType.initializer.parameters ?? [];
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1022
|
+
const jsiiParam = // eslint-disable-next-line no-await-in-loop
|
1023
|
+
this._toParameter(param, ctx.replaceStability(jsiiType.docs?.stability));
|
1024
|
+
if (containsIntersection(jsiiParam.type)) {
|
1025
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1010_INTERSECTION_NOT_IN_CTOR.create(param.declarations?.[0]));
|
1026
|
+
}
|
1027
|
+
jsiiType.initializer.parameters.push(jsiiParam);
|
1009
1028
|
jsiiType.initializer.variadic = jsiiType.initializer?.parameters?.some((p) => !!p.variadic) || undefined;
|
1010
1029
|
jsiiType.initializer.protected =
|
1011
1030
|
(ts.getCombinedModifierFlags(ctorDeclaration) & ts.ModifierFlags.Protected) !== 0 || undefined;
|
@@ -1067,7 +1086,7 @@ class Assembler {
|
|
1067
1086
|
.filter((x) => !x.static)
|
1068
1087
|
.map((x) => x.name));
|
1069
1088
|
// Intersect
|
1070
|
-
for (const member of intersect(statics, nonStatics)) {
|
1089
|
+
for (const member of sets_1.Sets.intersect(statics, nonStatics)) {
|
1071
1090
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_5013_STATIC_INSTANCE_CONFLICT.create(decl, member, klass));
|
1072
1091
|
}
|
1073
1092
|
// Check against base classes. They will not contain duplicate member names so we can load
|
@@ -1433,7 +1452,7 @@ class Assembler {
|
|
1433
1452
|
// Liftable datatype, make sure no parameter names match any of the properties in the datatype
|
1434
1453
|
const propNames = this.allProperties(lastParamType);
|
1435
1454
|
const paramNames = new Set(parameters.slice(0, parameters.length - 1).map((x) => x.name));
|
1436
|
-
const sharedNames = intersection(propNames, paramNames);
|
1455
|
+
const sharedNames = sets_1.Sets.intersection(propNames, paramNames);
|
1437
1456
|
for (const badName of sharedNames) {
|
1438
1457
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_5017_POSITIONAL_KEYWORD_CONFLICT.create(declaration, badName));
|
1439
1458
|
}
|
@@ -1568,7 +1587,18 @@ class Assembler {
|
|
1568
1587
|
return { type: primitiveType };
|
1569
1588
|
}
|
1570
1589
|
if (type.isUnion() && !_isEnumLike(type)) {
|
1571
|
-
return
|
1590
|
+
return _setType.call(this, 'union');
|
1591
|
+
}
|
1592
|
+
if (type.isIntersection()) {
|
1593
|
+
this.usedFeatures.add('intersection-types');
|
1594
|
+
const ret = _setType.call(this, 'intersection');
|
1595
|
+
const intersectionType = ret.type;
|
1596
|
+
this.validateIntersectionType(intersectionType, declaration);
|
1597
|
+
return ret;
|
1598
|
+
}
|
1599
|
+
if ((type.getFlags() & ts.TypeFlags.Never) !== 0) {
|
1600
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1007_NEVER_TYPE.create(declaration));
|
1601
|
+
return { type: spec.CANONICAL_ANY };
|
1572
1602
|
}
|
1573
1603
|
if (!type.symbol) {
|
1574
1604
|
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1001_TYPE_HAS_NO_SYMBOL.create(declaration));
|
@@ -1674,7 +1704,7 @@ class Assembler {
|
|
1674
1704
|
// Not a primitive type!
|
1675
1705
|
return undefined;
|
1676
1706
|
}
|
1677
|
-
function
|
1707
|
+
function _setType(field) {
|
1678
1708
|
const types = new Array();
|
1679
1709
|
let optional;
|
1680
1710
|
for (const subType of type.types) {
|
@@ -1689,16 +1719,112 @@ class Assembler {
|
|
1689
1719
|
}
|
1690
1720
|
types.push(resolvedType);
|
1691
1721
|
}
|
1692
|
-
|
1722
|
+
const returnedType = {
|
1723
|
+
[field]: { types },
|
1724
|
+
};
|
1725
|
+
return types.length === 1 ? { optional, type: types[0] } : { optional, type: returnedType };
|
1693
1726
|
}
|
1694
1727
|
}
|
1728
|
+
/**
|
1729
|
+
* Validate the restrictions on an intersection type reference
|
1730
|
+
*
|
1731
|
+
* - Type only consists of (behavioral) interface types
|
1732
|
+
* - For all types referenced in the intersection, the definitions of all shared
|
1733
|
+
* members must match exactly.
|
1734
|
+
*/
|
1735
|
+
validateIntersectionType(intersectionType, declaration) {
|
1736
|
+
// Validate that this intersection type only consists of interface types
|
1737
|
+
this._deferUntilTypesAvailable('', intersectionType.intersection.types, declaration, (...elementTypes) => {
|
1738
|
+
const requestedFqns = new Set(intersectionType.intersection.types.map(type_reference_1.typeReferenceToString));
|
1739
|
+
const resolvedFqns = new Set(elementTypes.map((t) => t.fqn));
|
1740
|
+
const unresolved = sets_1.Sets.diff(requestedFqns, resolvedFqns);
|
1741
|
+
if (unresolved.size > 0) {
|
1742
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1008_ONLY_INTERFACE_INTERSECTION.create(declaration, Array.from(unresolved).join(', ')));
|
1743
|
+
}
|
1744
|
+
const nonBehavioral = elementTypes.filter((t) => !(0, type_visitor_1.isBehavioralInterfaceType)(t));
|
1745
|
+
if (nonBehavioral.length > 0) {
|
1746
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1008_ONLY_INTERFACE_INTERSECTION.create(declaration, nonBehavioral.map((t) => t.fqn).join(', ')));
|
1747
|
+
}
|
1748
|
+
// Check that shared members are the same
|
1749
|
+
const interfaces = elementTypes.filter(type_visitor_1.isBehavioralInterfaceType);
|
1750
|
+
const allProps = sets_1.Sets.union(...interfaces.map((int) => this.allProperties(int)));
|
1751
|
+
const allMethods = sets_1.Sets.union(...interfaces.map((int) => this.allMethods(int)));
|
1752
|
+
for (let i = 1; i < interfaces.length; i++) {
|
1753
|
+
let int0 = interfaces[0];
|
1754
|
+
let int1 = interfaces[i];
|
1755
|
+
for (const prop of allProps) {
|
1756
|
+
const p1 = int0.properties?.find((p) => p.name === prop);
|
1757
|
+
const p2 = int1.properties?.find((p) => p.name === prop);
|
1758
|
+
const diff = this.comparePropForIntersection(p1, p2);
|
1759
|
+
if (diff) {
|
1760
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1011_INTERSECTION_MEMBER_DIFFERENT.create(declaration, prop, int0.name, diff[0], int1.name, diff[1]));
|
1761
|
+
}
|
1762
|
+
}
|
1763
|
+
for (const meth of allMethods) {
|
1764
|
+
const m1 = int0.methods?.find((p) => p.name === meth);
|
1765
|
+
const m2 = int1.methods?.find((p) => p.name === meth);
|
1766
|
+
const diff = this.compareMethodForIntersection(m1, m2);
|
1767
|
+
if (diff) {
|
1768
|
+
this._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1011_INTERSECTION_MEMBER_DIFFERENT.create(declaration, meth, int0.name, diff[0], int1.name, diff[1]));
|
1769
|
+
}
|
1770
|
+
}
|
1771
|
+
}
|
1772
|
+
});
|
1773
|
+
}
|
1774
|
+
comparePropForIntersection(a, b) {
|
1775
|
+
if (!a || !b) {
|
1776
|
+
return undefined;
|
1777
|
+
}
|
1778
|
+
if (!(0, type_reference_1.typeReferenceEqual)(a.type, b.type)) {
|
1779
|
+
return [(0, type_reference_1.typeReferenceToString)(a.type), (0, type_reference_1.typeReferenceToString)(b.type)];
|
1780
|
+
}
|
1781
|
+
return (cmpDesc(a.static, b.static, (s) => (s ? 'static' : 'instance member')) ??
|
1782
|
+
cmpDesc(a.optional, b.optional, (o) => (o ? 'optional' : 'required')) ??
|
1783
|
+
cmpDesc(a.abstract, b.abstract, (s) => (s ? 'abstract' : 'concrete')));
|
1784
|
+
}
|
1785
|
+
compareMethodForIntersection(a, b) {
|
1786
|
+
if (!a || !b) {
|
1787
|
+
return undefined;
|
1788
|
+
}
|
1789
|
+
if (a.returns && b.returns) {
|
1790
|
+
if (!(0, type_reference_1.typeReferenceEqual)(a.returns.type, b.returns.type)) {
|
1791
|
+
return [(0, type_reference_1.typeReferenceToString)(a.returns.type), (0, type_reference_1.typeReferenceToString)(b.returns.type)];
|
1792
|
+
}
|
1793
|
+
const x = cmpDesc(a.returns.optional, b.returns.optional, (o) => o ? 'return type optional' : 'return type required');
|
1794
|
+
if (x) {
|
1795
|
+
return x;
|
1796
|
+
}
|
1797
|
+
}
|
1798
|
+
const paramsA = a.parameters ?? [];
|
1799
|
+
const paramsB = b.parameters ?? [];
|
1800
|
+
if (paramsA.length !== paramsB.length) {
|
1801
|
+
return [`${paramsA.length} parameters`, `${paramsB.length} parameters`];
|
1802
|
+
}
|
1803
|
+
for (let i = 0; i < paramsA.length; i++) {
|
1804
|
+
const p1 = paramsA[i];
|
1805
|
+
const p2 = paramsB[i];
|
1806
|
+
if (!(0, type_reference_1.typeReferenceEqual)(p1.type, p2.type)) {
|
1807
|
+
return [(0, type_reference_1.typeReferenceToString)(p1.type), (0, type_reference_1.typeReferenceToString)(p2.type)];
|
1808
|
+
}
|
1809
|
+
const x = cmpDesc(p1.optional, p2.optional, (o) => (o ? `parameter ${i + 1} optional` : `parameter ${i + 1} required`)) ??
|
1810
|
+
cmpDesc(p1.variadic, p2.variadic, (v) => v ? `parameter ${i + 1} variadic` : `parameter ${i + 1} not variadic`);
|
1811
|
+
if (x) {
|
1812
|
+
return x;
|
1813
|
+
}
|
1814
|
+
}
|
1815
|
+
return (cmpDesc(a.abstract, b.abstract, (s) => (s ? 'abstract' : 'concrete')) ??
|
1816
|
+
cmpDesc(a.async, b.async, (s) => (s ? 'async' : 'async')) ??
|
1817
|
+
cmpDesc(a.protected, b.protected, (p) => (p ? 'protected' : 'public')) ??
|
1818
|
+
cmpDesc(a.variadic, b.variadic, (v) => (v ? 'variadic' : 'non-variadic')) ??
|
1819
|
+
cmpDesc(a.static, b.static, (s) => (s ? 'static' : 'instance member')));
|
1820
|
+
}
|
1695
1821
|
callDeferredsInOrder() {
|
1696
1822
|
// Do a topological call order of all deferreds.
|
1697
1823
|
while (this._deferred.length > 0) {
|
1698
1824
|
// All fqns in dependency lists that don't have any pending
|
1699
1825
|
// deferreds themselves can be executed now, so are removed from
|
1700
1826
|
// dependency lists.
|
1701
|
-
const pendingFqns = new Set(this._deferred.map((x) => x.fqn));
|
1827
|
+
const pendingFqns = new Set(this._deferred.map((x) => x.fqn).filter((x) => x));
|
1702
1828
|
for (const deferred of this._deferred) {
|
1703
1829
|
restrictDependenciesTo(deferred, pendingFqns);
|
1704
1830
|
}
|
@@ -1727,20 +1853,33 @@ class Assembler {
|
|
1727
1853
|
* Return the set of all (inherited) properties of an interface
|
1728
1854
|
*/
|
1729
1855
|
allProperties(root) {
|
1856
|
+
return this.allInterfacesRecursively(root, (int) => {
|
1857
|
+
return (int.properties ?? []).map((p) => p.name);
|
1858
|
+
});
|
1859
|
+
}
|
1860
|
+
/**
|
1861
|
+
* Return the set of all (inherited) methods of an interface
|
1862
|
+
*/
|
1863
|
+
allMethods(root) {
|
1864
|
+
return this.allInterfacesRecursively(root, (int) => {
|
1865
|
+
return (int.methods ?? []).map((p) => p.name);
|
1866
|
+
});
|
1867
|
+
}
|
1868
|
+
allInterfacesRecursively(root, cb) {
|
1730
1869
|
const ret = new Set();
|
1731
1870
|
recurse.call(this, root);
|
1732
1871
|
return ret;
|
1733
1872
|
function recurse(int) {
|
1734
|
-
for (const
|
1735
|
-
ret.add(
|
1873
|
+
for (const x of cb(int)) {
|
1874
|
+
ret.add(x);
|
1736
1875
|
}
|
1737
1876
|
for (const baseRef of int.interfaces ?? []) {
|
1738
|
-
const base = this._dereference(baseRef, undefined);
|
1877
|
+
const base = this._dereference(baseRef, undefined, 'used-in-syntax');
|
1739
1878
|
if (!base) {
|
1740
|
-
throw new Error('Impossible to have unresolvable base in
|
1879
|
+
throw new Error('Impossible to have unresolvable base in allInterfacesRecursively()');
|
1741
1880
|
}
|
1742
1881
|
if (!spec.isInterfaceType(base)) {
|
1743
|
-
throw new Error('Impossible to have non-interface base in
|
1882
|
+
throw new Error('Impossible to have non-interface base in allInterfacesRecursively()');
|
1744
1883
|
}
|
1745
1884
|
recurse.call(this, base);
|
1746
1885
|
}
|
@@ -1796,6 +1935,89 @@ class Assembler {
|
|
1796
1935
|
return this.findPackageInfo(parent);
|
1797
1936
|
}
|
1798
1937
|
}
|
1938
|
+
/**
|
1939
|
+
* Validate types against input/output positions in functions and APIs
|
1940
|
+
*
|
1941
|
+
* Currently used to validate that intersection types are only used in input position,
|
1942
|
+
* not output position
|
1943
|
+
*/
|
1944
|
+
validateTypesAgainstPositions() {
|
1945
|
+
const self = this;
|
1946
|
+
const validatedFqns = {
|
1947
|
+
in: new Set(),
|
1948
|
+
out: new Set(),
|
1949
|
+
};
|
1950
|
+
for (const type of this._types.values()) {
|
1951
|
+
if (spec.isClassType(type)) {
|
1952
|
+
for (const ctorParam of type.initializer?.parameters ?? []) {
|
1953
|
+
validateRefFor.call(this, 'in', ctorParam.type, `a constructor parameter of ${type.name}`);
|
1954
|
+
}
|
1955
|
+
}
|
1956
|
+
if (spec.isClassType(type) || (0, type_visitor_1.isBehavioralInterfaceType)(type)) {
|
1957
|
+
for (const property of type.properties ?? []) {
|
1958
|
+
validateRefFor.call(this, 'out', property.type, `type of property ${type.name}.${property.name}`);
|
1959
|
+
}
|
1960
|
+
for (const method of type.methods ?? []) {
|
1961
|
+
for (const param of method.parameters ?? []) {
|
1962
|
+
validateRefFor.call(this, 'in', param.type, `a parameter of method ${type.name}.${method.name}()`);
|
1963
|
+
}
|
1964
|
+
if (method.returns) {
|
1965
|
+
validateRefFor.call(this, 'out', method.returns.type, `return type of method ${type.name}.${method.name}()`);
|
1966
|
+
}
|
1967
|
+
}
|
1968
|
+
}
|
1969
|
+
}
|
1970
|
+
function validateRefFor(dir, typeRef, reason) {
|
1971
|
+
(0, type_visitor_1.visitTypeReference)(typeRef, {
|
1972
|
+
named: (ref) => {
|
1973
|
+
// Named types we'll only validate once for every direction
|
1974
|
+
if (validatedFqns[dir].has(ref.fqn)) {
|
1975
|
+
return;
|
1976
|
+
}
|
1977
|
+
validatedFqns[dir].add(ref.fqn);
|
1978
|
+
const type = self._dereference(ref, undefined, 'just-validating');
|
1979
|
+
if (!type) {
|
1980
|
+
// Maybe this is an unexported type.
|
1981
|
+
return;
|
1982
|
+
}
|
1983
|
+
validateTypeFor(dir, type, reason);
|
1984
|
+
},
|
1985
|
+
primitive: () => { },
|
1986
|
+
collection: (ref) => {
|
1987
|
+
validateRefFor(dir, ref.collection.elementtype, reason);
|
1988
|
+
},
|
1989
|
+
union: (ref) => {
|
1990
|
+
for (const t of ref.union.types) {
|
1991
|
+
validateRefFor(dir, t, reason);
|
1992
|
+
}
|
1993
|
+
},
|
1994
|
+
intersection: (ref) => {
|
1995
|
+
if (dir === 'out') {
|
1996
|
+
self._diagnostics.push(jsii_diagnostic_1.JsiiDiagnostic.JSII_1009_INTERSECTION_ONLY_INPUT.createDetached(reason));
|
1997
|
+
}
|
1998
|
+
for (const t of ref.intersection.types) {
|
1999
|
+
validateRefFor(dir, t, reason);
|
2000
|
+
}
|
2001
|
+
},
|
2002
|
+
});
|
2003
|
+
}
|
2004
|
+
function validateTypeFor(dir, type, reason) {
|
2005
|
+
(0, type_visitor_1.visitType)(type, {
|
2006
|
+
dataType: (t) => {
|
2007
|
+
// We only need to validate data types, because classes and interfaces
|
2008
|
+
// are done as part of the main loop.
|
2009
|
+
//
|
2010
|
+
// Recurse.
|
2011
|
+
for (const prop of t.properties ?? []) {
|
2012
|
+
validateRefFor(dir, prop.type, `type of property ${t.name}.${prop.name}, ${reason}`);
|
2013
|
+
}
|
2014
|
+
},
|
2015
|
+
classType: () => { },
|
2016
|
+
interfaceType: () => { },
|
2017
|
+
enumType: () => { },
|
2018
|
+
});
|
2019
|
+
}
|
2020
|
+
}
|
1799
2021
|
}
|
1800
2022
|
exports.Assembler = Assembler;
|
1801
2023
|
function _fingerprint(assembly) {
|
@@ -1929,18 +2151,6 @@ function last(xs) {
|
|
1929
2151
|
function apply(x, fn) {
|
1930
2152
|
return x !== undefined ? fn(x) : undefined;
|
1931
2153
|
}
|
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
2154
|
/**
|
1945
2155
|
* Return all members names of a JSII interface type
|
1946
2156
|
*
|
@@ -1971,12 +2181,10 @@ function isInterfaceName(name) {
|
|
1971
2181
|
function getConstructor(type) {
|
1972
2182
|
return type.symbol.members?.get(ts.InternalSymbolName.Constructor);
|
1973
2183
|
}
|
1974
|
-
function
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
}
|
1979
|
-
}
|
2184
|
+
function cmpDesc(a, b, desc) {
|
2185
|
+
const desc1 = desc(a);
|
2186
|
+
const desc2 = desc(b);
|
2187
|
+
return desc1 !== desc2 ? [desc1, desc2] : undefined;
|
1980
2188
|
}
|
1981
2189
|
function noEmptyDict(xs) {
|
1982
2190
|
if (xs == null || Object.keys(xs).length === 0) {
|
@@ -2160,6 +2368,18 @@ function _findHint(decl, hint) {
|
|
2160
2368
|
const [node] = ts.getAllJSDocTags(decl, (tag) => tag.tagName.text === hint);
|
2161
2369
|
return node;
|
2162
2370
|
}
|
2371
|
+
function containsIntersection(type) {
|
2372
|
+
if (spec.isIntersectionTypeReference(type)) {
|
2373
|
+
return true;
|
2374
|
+
}
|
2375
|
+
if (spec.isUnionTypeReference(type)) {
|
2376
|
+
return type.union.types.some(containsIntersection);
|
2377
|
+
}
|
2378
|
+
if (spec.isCollectionTypeReference(type)) {
|
2379
|
+
return containsIntersection(type.collection.elementtype);
|
2380
|
+
}
|
2381
|
+
return false;
|
2382
|
+
}
|
2163
2383
|
/**
|
2164
2384
|
* Resolve a Type to Symbol, taking into account single-valued enums which have a bug
|
2165
2385
|
*
|