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