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.
@@ -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 t ype
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 t ype
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.map((bt) => (typeof bt === 'string' ? bt : bt.fqn));
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.map((x) => this._dereference(x, referencingNode)).filter((x) => x !== undefined);
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
- jsiiType.initializer.parameters.push(
1007
- // eslint-disable-next-line no-await-in-loop
1008
- this._toParameter(param, ctx.replaceStability(jsiiType.docs?.stability)));
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 _unionType.call(this);
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 _unionType() {
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
- return types.length === 1 ? { optional, type: types[0] } : { optional, type: { union: { types } } };
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 property of int.properties ?? []) {
1735
- ret.add(property.name);
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 allProperties()');
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 allProperties()');
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* intersect(xs, ys) {
1975
- for (const x of xs) {
1976
- if (ys.has(x)) {
1977
- yield x;
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
  *