jsii-pacmak 1.114.1 → 1.115.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.
Files changed (37) hide show
  1. package/lib/npm-modules.d.ts +1 -1
  2. package/lib/npm-modules.js +1 -3
  3. package/lib/packaging.d.ts +1 -5
  4. package/lib/packaging.js +12 -6
  5. package/lib/rosetta-assembly.d.ts +4 -0
  6. package/lib/rosetta-assembly.js +9 -3
  7. package/lib/targets/dotnet/dotnetdocgenerator.d.ts +4 -1
  8. package/lib/targets/dotnet/dotnetdocgenerator.js +66 -13
  9. package/lib/targets/dotnet/dotnetgenerator.d.ts +0 -4
  10. package/lib/targets/dotnet/dotnetgenerator.js +24 -14
  11. package/lib/targets/dotnet/dotnetruntimegenerator.js +11 -2
  12. package/lib/targets/dotnet/dotnettyperesolver.d.ts +13 -0
  13. package/lib/targets/dotnet/dotnettyperesolver.js +40 -2
  14. package/lib/targets/dotnet.d.ts +1 -1
  15. package/lib/targets/dotnet.js +6 -4
  16. package/lib/targets/go/runtime/runtime-type-checking.js +1 -0
  17. package/lib/targets/go/types/go-type-reference.d.ts +3 -0
  18. package/lib/targets/go/types/go-type-reference.js +20 -0
  19. package/lib/targets/go.js +1 -1
  20. package/lib/targets/java.d.ts +28 -4
  21. package/lib/targets/java.js +406 -217
  22. package/lib/targets/python/requirements-dev.txt +1 -1
  23. package/lib/targets/python/type-name.d.ts +18 -0
  24. package/lib/targets/python/type-name.js +59 -1
  25. package/lib/targets/python.d.ts +2 -1
  26. package/lib/targets/python.js +50 -18
  27. package/lib/targets/type-literals.d.ts +22 -0
  28. package/lib/targets/type-literals.js +39 -0
  29. package/lib/type-utils.d.ts +3 -0
  30. package/lib/type-utils.js +10 -0
  31. package/lib/type-visitor.d.ts +19 -0
  32. package/lib/type-visitor.js +47 -0
  33. package/lib/util.d.ts +18 -5
  34. package/lib/util.js +80 -13
  35. package/lib/version.d.ts +1 -1
  36. package/lib/version.js +3 -3
  37. package/package.json +12 -12
@@ -6,7 +6,7 @@
6
6
  setuptools~=75.3.2 # build-system
7
7
  build~=1.3.0 # build-system
8
8
 
9
- twine~=6.1.0
9
+ twine~=6.2.0
10
10
 
11
11
  # The dependency on packaging is necessary to work around an incompatibility between
12
12
  # what setuptools generates and what twine expects. <https://github.com/pypa/twine/issues/1216>
@@ -1,4 +1,8 @@
1
1
  import { Assembly, OptionalValue, TypeReference, Type } from '@jsii/spec';
2
+ import { CodeMaker } from 'codemaker';
3
+ /**
4
+ * Actually more of a TypeNameFactory than a TypeName
5
+ */
2
6
  export interface TypeName {
3
7
  pythonType(context: NamingContext): string;
4
8
  requiredImports(context: NamingContext): PythonImports;
@@ -21,6 +25,8 @@ export interface NamingContext {
21
25
  readonly typeResolver: (fqn: string) => Type;
22
26
  /** The submodule of the assembly in which the PythonType is expressed (could be the module root) */
23
27
  readonly submodule: string;
28
+ /** Holds the set of intersection types used in the current module */
29
+ readonly intersectionTypes: IntersectionTypesRegistry;
24
30
  /**
25
31
  * The declaration is made in the context of a type annotation (so it can be quoted)
26
32
  *
@@ -70,4 +76,16 @@ export declare function toPythonFqn(fqn: string, rootAssm: Assembly): {
70
76
  packageName: string;
71
77
  pythonFqn: string;
72
78
  };
79
+ /**
80
+ * Holds a set of intersection types used by the current set of modules
81
+ */
82
+ export declare class IntersectionTypesRegistry {
83
+ private readonly types;
84
+ /**
85
+ * Return a unique name for a protocol that extends the given types
86
+ */
87
+ obtain(types: string[]): string;
88
+ get typeNames(): string[];
89
+ flushHelperTypes(code: CodeMaker): void;
90
+ }
73
91
  //# sourceMappingURL=type-name.d.ts.map
@@ -10,8 +10,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _Dict_element, _List_element, _Optional_wrapped, _Primitive_pythonType, _Union_options, _UserType_fqn;
13
+ var _Dict_element, _List_element, _Optional_wrapped, _Primitive_pythonType, _Union_options, _Intersection_types, _UserType_fqn;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.IntersectionTypesRegistry = void 0;
15
16
  exports.toTypeName = toTypeName;
16
17
  exports.toPackageName = toPackageName;
17
18
  exports.mergePythonImports = mergePythonImports;
@@ -45,6 +46,13 @@ function toTypeName(ref) {
45
46
  else if ((0, spec_1.isNamedTypeReference)(type)) {
46
47
  result = new UserType(type.fqn);
47
48
  }
49
+ else if ((0, spec_1.isIntersectionTypeReference)(type)) {
50
+ const types = type.intersection.types.map(toTypeName);
51
+ if (types.some((t) => !(t instanceof UserType))) {
52
+ throw new Error('Only user types are supported in intersections');
53
+ }
54
+ result = new Intersection(types);
55
+ }
48
56
  return optional ? new Optional(result) : result;
49
57
  }
50
58
  /**
@@ -178,6 +186,23 @@ class Union {
178
186
  }
179
187
  }
180
188
  _Union_options = new WeakMap();
189
+ class Intersection {
190
+ constructor(types) {
191
+ // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility
192
+ _Intersection_types.set(this, void 0);
193
+ __classPrivateFieldSet(this, _Intersection_types, types, "f");
194
+ }
195
+ pythonType(context) {
196
+ // We will be generating a special type to represent the intersection
197
+ const name = context.intersectionTypes.obtain(__classPrivateFieldGet(this, _Intersection_types, "f").map((t) => t.pythonType(context)).map(stripQuotes));
198
+ // This will never be in scope already, so always render between quotes
199
+ return `'${name}'`;
200
+ }
201
+ requiredImports(context) {
202
+ return mergePythonImports(...__classPrivateFieldGet(this, _Intersection_types, "f").map((o) => o.requiredImports(context)));
203
+ }
204
+ }
205
+ _Intersection_types = new WeakMap();
181
206
  class UserType {
182
207
  constructor(fqn) {
183
208
  // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility
@@ -346,4 +371,37 @@ function findParentSubmodule(type, assm) {
346
371
  }
347
372
  return namespaceFqn;
348
373
  }
374
+ /**
375
+ * Holds a set of intersection types used by the current set of modules
376
+ */
377
+ class IntersectionTypesRegistry {
378
+ constructor() {
379
+ this.types = new Map();
380
+ }
381
+ /**
382
+ * Return a unique name for a protocol that extends the given types
383
+ */
384
+ obtain(types) {
385
+ const derivedName = `_${types.map(lastComponent).join('_')}`;
386
+ this.types.set(derivedName, types);
387
+ return derivedName;
388
+ }
389
+ get typeNames() {
390
+ return Array.from(this.types.keys());
391
+ }
392
+ flushHelperTypes(code) {
393
+ for (const [name, types] of this.types.entries()) {
394
+ code.line('');
395
+ code.line(`class ${name}(${types.join(', ')}, typing_extensions.Protocol):`);
396
+ code.line(' pass');
397
+ }
398
+ }
399
+ }
400
+ exports.IntersectionTypesRegistry = IntersectionTypesRegistry;
401
+ function lastComponent(x) {
402
+ return x.split('.').slice(-1)[0];
403
+ }
404
+ function stripQuotes(x) {
405
+ return x.replace(/^"|"$/g, '');
406
+ }
349
407
  //# sourceMappingURL=type-name.js.map
@@ -40,13 +40,14 @@ type FindModuleCallback = (fqn: string) => spec.AssemblyConfiguration;
40
40
  type FindTypeCallback = (fqn: string) => spec.Type;
41
41
  declare class TypeResolver {
42
42
  private readonly types;
43
+ private readonly assembly;
43
44
  private readonly boundTo?;
44
45
  private readonly boundRe;
45
46
  private readonly moduleName?;
46
47
  private readonly moduleRe;
47
48
  private readonly findModule;
48
49
  private readonly findType;
49
- constructor(types: Map<string, PythonType>, findModule: FindModuleCallback, findType: FindTypeCallback, boundTo?: string, moduleName?: string);
50
+ constructor(types: Map<string, PythonType>, assembly: spec.Assembly, findModule: FindModuleCallback, findType: FindTypeCallback, boundTo?: string, moduleName?: string);
50
51
  bind(fqn: string, moduleName?: string): TypeResolver;
51
52
  isInModule(typeRef: spec.NamedTypeReference | string): boolean;
52
53
  isInNamespace(typeRef: spec.NamedTypeReference | string): boolean;
@@ -55,7 +55,7 @@ class Python extends target_1.Target {
55
55
  // shim, but using this actually results in a WinError with Python 3.7 and 3.8 where venv will
56
56
  // fail to copy the python binary if it's not invoked as python.exe). More on this particular
57
57
  // issue can be read here: https://bugs.python.org/issue43749
58
- await (0, util_1.shell)(process.platform === 'win32' ? 'python' : 'python3', [
58
+ await (0, util_1.subprocess)(process.platform === 'win32' ? 'python' : 'python3', [
59
59
  '-m',
60
60
  'venv',
61
61
  '--system-site-packages', // Allow using globally installed packages (saves time & disk space)
@@ -68,18 +68,18 @@ class Python extends target_1.Target {
68
68
  };
69
69
  const python = path.join(venvBin, 'python');
70
70
  // Install the necessary things
71
- await (0, util_1.shell)(python, ['-m', 'pip', 'install', '--no-input', '-r', requirementsFile], {
71
+ await (0, util_1.subprocess)(python, ['-m', 'pip', 'install', '--no-input', '-r', requirementsFile], {
72
72
  cwd: sourceDir,
73
73
  env,
74
74
  retry: { maxAttempts: 5 },
75
75
  });
76
76
  // Actually package up our code, both as a sdist and a wheel for publishing.
77
- await (0, util_1.shell)(python, ['-m', 'build', '--outdir', outDir, sourceDir], {
77
+ await (0, util_1.subprocess)(python, ['-m', 'build', '--outdir', outDir, sourceDir], {
78
78
  cwd: sourceDir,
79
79
  env,
80
80
  retry: { maxAttempts: 5 },
81
81
  });
82
- await (0, util_1.shell)(python, ['-m', 'twine', 'check', path.join(outDir, '*')], {
82
+ await (0, util_1.shell)(`${python} -m twine check ${path.join(outDir, '*')}`, {
83
83
  cwd: sourceDir,
84
84
  env,
85
85
  });
@@ -405,17 +405,18 @@ class BaseMethod {
405
405
  liftedPropNames.add(toPythonParameterName(prop.name));
406
406
  }
407
407
  }
408
+ const typeFacs = this.parameters.map(type_name_1.toTypeName);
408
409
  // We need to turn a list of JSII parameters, into Python style arguments with
409
410
  // gradual typing, so we'll have to iterate over the list of parameters, and
410
411
  // build the list, converting as we go.
411
412
  const pythonParams = [];
412
- for (const param of this.parameters) {
413
+ for (const [param, typeFac] of (0, util_1.zip)(this.parameters, typeFacs)) {
413
414
  // We cannot (currently?) blindly use the names given to us by the JSII for
414
415
  // initializers, because our keyword lifting will allow two names to clash.
415
416
  // This can hopefully be removed once we get https://github.com/aws/jsii/issues/288
416
417
  // resolved.
417
418
  const paramName = toPythonParameterName(param.name, liftedPropNames);
418
- const paramType = (0, type_name_1.toTypeName)(param).pythonType({
419
+ const paramType = typeFac.pythonType({
419
420
  ...context,
420
421
  parameterType: true,
421
422
  });
@@ -1162,6 +1163,7 @@ class PythonModule {
1162
1163
  context = {
1163
1164
  ...context,
1164
1165
  submodule: this.fqn ?? context.submodule,
1166
+ intersectionTypes: new type_name_1.IntersectionTypesRegistry(),
1165
1167
  resolver,
1166
1168
  };
1167
1169
  // Before we write anything else, we need to write out our module headers, this
@@ -1289,6 +1291,15 @@ class PythonModule {
1289
1291
  code.line(`from . import ${submodule}`);
1290
1292
  }
1291
1293
  }
1294
+ context.typeCheckingHelper.flushStubs(code);
1295
+ context.intersectionTypes.flushHelperTypes(code);
1296
+ const interfaces = this.members
1297
+ .filter((m) => m instanceof Interface)
1298
+ .map((m) => m.pythonName);
1299
+ this.emitProtocolStripper(code, [
1300
+ ...interfaces,
1301
+ ...context.intersectionTypes.typeNames,
1302
+ ]);
1292
1303
  }
1293
1304
  /**
1294
1305
  * Emit the bin scripts if bin section defined.
@@ -1330,6 +1341,32 @@ class PythonModule {
1330
1341
  }
1331
1342
  return scripts;
1332
1343
  }
1344
+ /**
1345
+ * Emit a helper that will strip magic jsii elements from all protocol classes
1346
+ *
1347
+ * This is necessary because we attach the `__jsii_proxy_class__` and
1348
+ * `__jsii_type__` fields to Protocols/interfaces, which are then going to
1349
+ * show up when someone calls `typing.get_protocol_members()`, and interfere
1350
+ * with run-time type checking done by `typeguard`.
1351
+ *
1352
+ * `typing.get_protocol_members(x)` reads cached members from
1353
+ * `x.__protocol_attrs__` (put there by the `Protocol` metaclass), so what we
1354
+ * do is remove our magic members from that cached set.
1355
+ *
1356
+ * This is extremely hacky, and in a hypothetical future rewrite we should
1357
+ * store our metadata off-object (for example in a dict or `WeakKeyDictionary`),
1358
+ * so that our magic members don't interfere with built-in Python functions.
1359
+ * But for now we fiddle with the metadata to hide our magic members wherever
1360
+ * necessary.
1361
+ */
1362
+ emitProtocolStripper(code, protocolNames) {
1363
+ if (protocolNames.length === 0) {
1364
+ return;
1365
+ }
1366
+ code.line('');
1367
+ code.line(`for cls in [${protocolNames.join(', ')}]:`);
1368
+ code.line(` typing.cast(typing.Any, cls).__protocol_attrs__ = typing.cast(typing.Any, cls).__protocol_attrs__ - set(['__jsii_proxy_class__', '__jsii_type__'])`);
1369
+ }
1333
1370
  isDirectChild(pyMod) {
1334
1371
  if (this.pythonName === pyMod.pythonName ||
1335
1372
  !pyMod.pythonName.startsWith(`${this.pythonName}.`)) {
@@ -1439,7 +1476,6 @@ class Package {
1439
1476
  const filename = path.join('src', pythonModuleNameToFilename(mod.pythonName), '__init__.py');
1440
1477
  code.openFile(filename);
1441
1478
  mod.emit(code, context);
1442
- context.typeCheckingHelper.flushStubs(code);
1443
1479
  code.closeFile(filename);
1444
1480
  scripts.push(...mod.emitBinScripts(code));
1445
1481
  }
@@ -1607,8 +1643,9 @@ class Package {
1607
1643
  }
1608
1644
  }
1609
1645
  class TypeResolver {
1610
- constructor(types, findModule, findType, boundTo, moduleName) {
1646
+ constructor(types, assembly, findModule, findType, boundTo, moduleName) {
1611
1647
  this.types = types;
1648
+ this.assembly = assembly;
1612
1649
  this.findModule = findModule;
1613
1650
  this.findType = findType;
1614
1651
  this.moduleName = moduleName;
@@ -1621,7 +1658,7 @@ class TypeResolver {
1621
1658
  }
1622
1659
  }
1623
1660
  bind(fqn, moduleName) {
1624
- return new TypeResolver(this.types, this.findModule, this.findType, fqn, moduleName !== undefined
1661
+ return new TypeResolver(this.types, this.assembly, this.findModule, this.findType, fqn, moduleName !== undefined
1625
1662
  ? moduleName.startsWith('.')
1626
1663
  ? `${this.moduleName}${moduleName}`
1627
1664
  : moduleName
@@ -1679,14 +1716,8 @@ class TypeResolver {
1679
1716
  return this.findType(typeRef);
1680
1717
  }
1681
1718
  toPythonFQN(fqn) {
1682
- const [assemblyName, ...qualifiedIdentifiers] = fqn.split('.');
1683
- const fqnParts = [
1684
- this.findModule(assemblyName).targets.python.module,
1685
- ];
1686
- for (const part of qualifiedIdentifiers) {
1687
- fqnParts.push((0, util_2.toPythonIdentifier)(part));
1688
- }
1689
- return fqnParts.join('.');
1719
+ const { pythonFqn } = (0, type_name_1.toPythonFqn)(fqn, this.assembly);
1720
+ return pythonFqn;
1690
1721
  }
1691
1722
  }
1692
1723
  class PythonGenerator extends generator_1.Generator {
@@ -1833,7 +1864,7 @@ class PythonGenerator extends generator_1.Generator {
1833
1864
  this.package.addData(assemblyModule, this.getAssemblyFileName(), undefined);
1834
1865
  }
1835
1866
  onEndAssembly(assm, _fingerprint) {
1836
- const resolver = new TypeResolver(this.types, (fqn) => this.findModule(fqn), (fqn) => this.findType(fqn));
1867
+ const resolver = new TypeResolver(this.types, assm, (fqn) => this.findModule(fqn), (fqn) => this.findType(fqn));
1837
1868
  this.package.write(this.code, {
1838
1869
  assembly: assm,
1839
1870
  emittedTypes: new Set(),
@@ -1842,6 +1873,7 @@ class PythonGenerator extends generator_1.Generator {
1842
1873
  submodule: assm.name,
1843
1874
  typeCheckingHelper: new TypeCheckingHelper(),
1844
1875
  typeResolver: (fqn) => resolver.dereference(fqn),
1876
+ intersectionTypes: new type_name_1.IntersectionTypesRegistry(),
1845
1877
  });
1846
1878
  }
1847
1879
  /**
@@ -0,0 +1,22 @@
1
+ import * as spec from '@jsii/spec';
2
+ /**
3
+ * Make a type reference that references exactly a literal.
4
+ *
5
+ * This is useful if we don't want to reference a real type but a locally bound
6
+ * type parameter.
7
+ *
8
+ * This is a slightly hacky way to get the rendering functio to render a
9
+ * literal string, without looking it up. It gets us to embed the notion of
10
+ * rendering literal type parameters in the existing jsii spec without having to
11
+ * explicitly model it only for the purpose of a couple of code generators.
12
+ */
13
+ export declare function makeLiteralTypeReference(typeParameterName: string): spec.NamedTypeReference;
14
+ /**
15
+ * Return the type parameter name if the type reference is a type literal
16
+ */
17
+ export declare function literalTypeReference(x: spec.TypeReference): string | undefined;
18
+ /**
19
+ * Whether the given type is a literal type reference
20
+ */
21
+ export declare function isLiteralTypeReference(x: spec.TypeReference): boolean;
22
+ //# sourceMappingURL=type-literals.d.ts.map
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeLiteralTypeReference = makeLiteralTypeReference;
4
+ exports.literalTypeReference = literalTypeReference;
5
+ exports.isLiteralTypeReference = isLiteralTypeReference;
6
+ const spec = require("@jsii/spec");
7
+ const LITERAL_TYPE_PREFIX = '$lit:';
8
+ /**
9
+ * Make a type reference that references exactly a literal.
10
+ *
11
+ * This is useful if we don't want to reference a real type but a locally bound
12
+ * type parameter.
13
+ *
14
+ * This is a slightly hacky way to get the rendering functio to render a
15
+ * literal string, without looking it up. It gets us to embed the notion of
16
+ * rendering literal type parameters in the existing jsii spec without having to
17
+ * explicitly model it only for the purpose of a couple of code generators.
18
+ */
19
+ function makeLiteralTypeReference(typeParameterName) {
20
+ return { fqn: `${LITERAL_TYPE_PREFIX}${typeParameterName}` };
21
+ }
22
+ /**
23
+ * Return the type parameter name if the type reference is a type literal
24
+ */
25
+ function literalTypeReference(x) {
26
+ if (!spec.isNamedTypeReference(x)) {
27
+ return undefined;
28
+ }
29
+ return x.fqn.startsWith(LITERAL_TYPE_PREFIX)
30
+ ? x.fqn.slice(LITERAL_TYPE_PREFIX.length)
31
+ : undefined;
32
+ }
33
+ /**
34
+ * Whether the given type is a literal type reference
35
+ */
36
+ function isLiteralTypeReference(x) {
37
+ return literalTypeReference(x) !== undefined;
38
+ }
39
+ //# sourceMappingURL=type-literals.js.map
@@ -0,0 +1,3 @@
1
+ import * as spec from '@jsii/spec';
2
+ export declare function containsUnionType(typeRef: spec.TypeReference): typeRef is spec.UnionTypeReference | spec.CollectionTypeReference;
3
+ //# sourceMappingURL=type-utils.d.ts.map
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.containsUnionType = containsUnionType;
4
+ const spec = require("@jsii/spec");
5
+ function containsUnionType(typeRef) {
6
+ return (spec.isUnionTypeReference(typeRef) ||
7
+ (spec.isCollectionTypeReference(typeRef) &&
8
+ containsUnionType(typeRef.collection.elementtype)));
9
+ }
10
+ //# sourceMappingURL=type-utils.js.map
@@ -0,0 +1,19 @@
1
+ import * as spec from '@jsii/spec';
2
+ export interface TypeReferenceVisitor<A = void> {
3
+ named(ref: spec.NamedTypeReference): A;
4
+ primitive(ref: spec.PrimitiveTypeReference): A;
5
+ collection(ref: spec.CollectionTypeReference): A;
6
+ union(ref: spec.UnionTypeReference): A;
7
+ intersection(ref: spec.IntersectionTypeReference): A;
8
+ }
9
+ export declare function visitTypeReference<A>(typeRef: spec.TypeReference, visitor: TypeReferenceVisitor<A>): A;
10
+ export interface TypeVisitor<A = void> {
11
+ classType(t: spec.ClassType): A;
12
+ interfaceType(t: spec.InterfaceType): A;
13
+ dataType(t: spec.InterfaceType): A;
14
+ enumType(t: spec.EnumType): A;
15
+ }
16
+ export declare function visitType<A>(t: spec.Type, visitor: TypeVisitor<A>): A;
17
+ export declare function isDataType(t: spec.Type): t is spec.InterfaceType;
18
+ export declare function isBehavioralInterfaceType(t: spec.Type): t is spec.InterfaceType;
19
+ //# sourceMappingURL=type-visitor.d.ts.map
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.visitTypeReference = visitTypeReference;
4
+ exports.visitType = visitType;
5
+ exports.isDataType = isDataType;
6
+ exports.isBehavioralInterfaceType = isBehavioralInterfaceType;
7
+ const spec = require("@jsii/spec");
8
+ function visitTypeReference(typeRef, visitor) {
9
+ if (spec.isNamedTypeReference(typeRef)) {
10
+ return visitor.named(typeRef);
11
+ }
12
+ else if (spec.isPrimitiveTypeReference(typeRef)) {
13
+ return visitor.primitive(typeRef);
14
+ }
15
+ else if (spec.isCollectionTypeReference(typeRef)) {
16
+ return visitor.collection(typeRef);
17
+ }
18
+ else if (spec.isUnionTypeReference(typeRef)) {
19
+ return visitor.union(typeRef);
20
+ }
21
+ else if (spec.isIntersectionTypeReference(typeRef)) {
22
+ return visitor.intersection(typeRef);
23
+ }
24
+ throw new Error(`Unknown type reference: ${JSON.stringify(typeRef)}`);
25
+ }
26
+ function visitType(t, visitor) {
27
+ if (spec.isClassType(t)) {
28
+ return visitor.classType(t);
29
+ }
30
+ else if (spec.isInterfaceType(t) && t.datatype) {
31
+ return visitor.dataType(t);
32
+ }
33
+ else if (spec.isInterfaceType(t)) {
34
+ return visitor.interfaceType(t);
35
+ }
36
+ else if (spec.isEnumType(t)) {
37
+ return visitor.enumType(t);
38
+ }
39
+ throw new Error(`Unknown type: ${JSON.stringify(t)}`);
40
+ }
41
+ function isDataType(t) {
42
+ return spec.isInterfaceType(t) && !!t.datatype;
43
+ }
44
+ function isBehavioralInterfaceType(t) {
45
+ return spec.isInterfaceType(t) && !t.datatype;
46
+ }
47
+ //# sourceMappingURL=type-visitor.js.map
package/lib/util.d.ts CHANGED
@@ -62,7 +62,7 @@ export interface RetryOptions {
62
62
  * be awaited before making the next attempt (if
63
63
  * there are attempts left)
64
64
  */
65
- onFailedAttempt?: (error: unknown, attemptsLeft: number, backoffMilliseconds: number) => void;
65
+ onFailedAttempt?: (error: Error, attemptsLeft: number, backoffMilliseconds: number) => void;
66
66
  }
67
67
  export declare class AllAttemptsFailed<R> extends Error {
68
68
  readonly callback: () => Promise<R>;
@@ -87,16 +87,28 @@ export interface ShellOptions extends Omit<SpawnOptions, 'shell' | 'stdio'> {
87
87
  readonly retry?: RetryOptions;
88
88
  }
89
89
  /**
90
- * Spawns a child process with the provided command and arguments. The child
91
- * process is always spawned using `shell: true`, and the contents of
90
+ * Spawns a shell with the provided commandline.
91
+ *
92
+ * The child process is always spawned using `shell: true`, and the contents of
92
93
  * `process.env` is used as the initial value of the `env` spawn option (values
93
94
  * provided in `options.env` can override those).
95
+ */
96
+ export declare function shell(commandLine: string, options?: ShellOptions): Promise<string>;
97
+ /**
98
+ * Spawns a subprocess with the provided command and arguments.
99
+ *
100
+ * The child process is always spawned using `shell: false`, and the contents of
101
+ * `process.env` is used as the initial value of the `env` spawn option (values
102
+ * provided in `options.env` can override those).
103
+ *
104
+ * To make this work on Windows, if the binary happens to resolve to a batch file
105
+ * we run it through cmd.exe.
94
106
  *
95
- * @param cmd the command to shell out to.
107
+ * @param binary the command to shell out to.
96
108
  * @param args the arguments to provide to `cmd`
97
109
  * @param options any options to pass to `spawn`
98
110
  */
99
- export declare function shell(cmd: string, args: string[], { retry: retryOptions, ...options }?: ShellOptions): Promise<string>;
111
+ export declare function subprocess(binary: string, args: string[], options?: ShellOptions): Promise<string>;
100
112
  /**
101
113
  * Strip filesystem unsafe characters from a string
102
114
  */
@@ -119,4 +131,5 @@ export declare function setExtend<A>(xs: Set<A>, els: Iterable<A>): void;
119
131
  export declare function filterAsync<A>(xs: A[], pred: (x: A) => Promise<boolean>): Promise<A[]>;
120
132
  export declare function wait(ms: number): Promise<void>;
121
133
  export declare function flatten<A>(xs: readonly A[][]): A[];
134
+ export declare function zip<A, B>(xs: A[], ys: B[]): Array<[A, B]>;
122
135
  //# sourceMappingURL=util.d.ts.map
package/lib/util.js CHANGED
@@ -7,11 +7,13 @@ exports.findPackageJsonUp = findPackageJsonUp;
7
7
  exports.findUp = findUp;
8
8
  exports.retry = retry;
9
9
  exports.shell = shell;
10
+ exports.subprocess = subprocess;
10
11
  exports.slugify = slugify;
11
12
  exports.setExtend = setExtend;
12
13
  exports.filterAsync = filterAsync;
13
14
  exports.wait = wait;
14
15
  exports.flatten = flatten;
16
+ exports.zip = zip;
15
17
  const child_process_1 = require("child_process");
16
18
  const fs = require("fs-extra");
17
19
  const os = require("os");
@@ -134,25 +136,65 @@ async function retry(cb, opts = {}, waiter = wait) {
134
136
  return Promise.reject(new AllAttemptsFailed(cb, errors));
135
137
  }
136
138
  /**
137
- * Spawns a child process with the provided command and arguments. The child
138
- * process is always spawned using `shell: true`, and the contents of
139
+ * Spawns a shell with the provided commandline.
140
+ *
141
+ * The child process is always spawned using `shell: true`, and the contents of
139
142
  * `process.env` is used as the initial value of the `env` spawn option (values
140
143
  * provided in `options.env` can override those).
144
+ */
145
+ async function shell(commandLine, options) {
146
+ return handleSubprocess(options, () => {
147
+ logging.debug(commandLine, JSON.stringify(options));
148
+ return {
149
+ command: commandLine,
150
+ child: (0, child_process_1.spawn)(commandLine, {
151
+ ...options,
152
+ shell: true,
153
+ env: { ...process.env, ...(options?.env ?? {}) },
154
+ stdio: ['ignore', 'pipe', 'pipe'],
155
+ }),
156
+ };
157
+ });
158
+ }
159
+ /**
160
+ * Spawns a subprocess with the provided command and arguments.
141
161
  *
142
- * @param cmd the command to shell out to.
162
+ * The child process is always spawned using `shell: false`, and the contents of
163
+ * `process.env` is used as the initial value of the `env` spawn option (values
164
+ * provided in `options.env` can override those).
165
+ *
166
+ * To make this work on Windows, if the binary happens to resolve to a batch file
167
+ * we run it through cmd.exe.
168
+ *
169
+ * @param binary the command to shell out to.
143
170
  * @param args the arguments to provide to `cmd`
144
171
  * @param options any options to pass to `spawn`
145
172
  */
146
- async function shell(cmd, args, { retry: retryOptions, ...options } = {}) {
147
- async function spawn1() {
148
- logging.debug(cmd, args.join(' '), JSON.stringify(options));
149
- return new Promise((ok, ko) => {
150
- const child = (0, child_process_1.spawn)(cmd, args, {
173
+ async function subprocess(binary, args, options) {
174
+ if (os.platform() === 'win32') {
175
+ const resolved = resolveBinaryWindows(binary);
176
+ // Anything that's not an executable, run it through cmd.exe
177
+ if (!resolved.toLocaleLowerCase().endsWith('.exe')) {
178
+ binary = process.env.COMSPEC ?? 'cmd.exe';
179
+ args = ['/d', '/c', resolved, ...args];
180
+ }
181
+ }
182
+ return handleSubprocess(options, () => {
183
+ logging.debug(binary, args.join(' '), JSON.stringify(options ?? {}));
184
+ return {
185
+ command: `${binary} ${args.join(' ')}`.trim(),
186
+ child: (0, child_process_1.spawn)(binary, args, {
151
187
  ...options,
152
- shell: true,
153
- env: { ...process.env, ...(options.env ?? {}) },
188
+ env: { ...process.env, ...(options?.env ?? {}) },
154
189
  stdio: ['ignore', 'pipe', 'pipe'],
155
- });
190
+ }),
191
+ };
192
+ });
193
+ }
194
+ async function handleSubprocess({ retry: retryOptions } = {}, doSpawn) {
195
+ async function spawn1() {
196
+ return new Promise((ok, ko) => {
197
+ const { command, child } = doSpawn();
156
198
  const stdout = new Array();
157
199
  const stderr = new Array();
158
200
  child.stdout.on('data', (chunk) => {
@@ -177,7 +219,6 @@ async function shell(cmd, args, { retry: retryOptions, ...options } = {}) {
177
219
  }
178
220
  const err = Buffer.concat(stderr).toString('utf-8');
179
221
  const reason = signal != null ? `signal ${signal}` : `status ${code}`;
180
- const command = `${cmd} ${args.join(' ')}`;
181
222
  return ko(new Error([
182
223
  `Command (${command}) failed with ${reason}:`,
183
224
  // STDERR first, the erro message could be truncated in logs.
@@ -202,12 +243,31 @@ async function shell(cmd, args, { retry: retryOptions, ...options } = {}) {
202
243
  const retryInfo = attemptsLeft > 0
203
244
  ? `Waiting ${backoffMs} ms before retrying (${attemptsLeft} attempts left)`
204
245
  : 'No attempts left';
205
- logging.info(`Command "${cmd} ${args.join(' ')}" failed with ${message}. ${retryInfo}.`);
246
+ logging.info(`${message}. ${retryInfo}.`);
206
247
  }),
207
248
  });
208
249
  }
209
250
  return spawn1();
210
251
  }
252
+ /**
253
+ * Resolve a command to an executable on Windows
254
+ */
255
+ function resolveBinaryWindows(command) {
256
+ const extensions = (process.env.PATHEXT ?? '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH').split(';');
257
+ const dirs = [
258
+ process.cwd(),
259
+ ...(process.env.PATH?.split(path.delimiter) ?? []),
260
+ ];
261
+ for (const dir of dirs) {
262
+ for (const ext of ['', ...extensions]) {
263
+ const candidate = path.resolve(dir, `${command}${ext}`);
264
+ if (fs.pathExistsSync(candidate)) {
265
+ return candidate;
266
+ }
267
+ }
268
+ }
269
+ throw new Error(`Unable to resolve command: ${command} in ${process.env.PATH}`);
270
+ }
211
271
  /**
212
272
  * Strip filesystem unsafe characters from a string
213
273
  */
@@ -274,4 +334,11 @@ async function wait(ms) {
274
334
  function flatten(xs) {
275
335
  return Array.prototype.concat.call([], ...xs);
276
336
  }
337
+ function zip(xs, ys) {
338
+ const ret = new Array();
339
+ for (let i = 0; i < xs.length; i++) {
340
+ ret.push([xs[i], ys[i]]);
341
+ }
342
+ return ret;
343
+ }
277
344
  //# sourceMappingURL=util.js.map
package/lib/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** The short version number for this jsii-pacmak release (e.g: `X.Y.Z`) */
2
2
  export declare const VERSION: string;
3
3
  /** The qualified version number for this jsii-pacmak release (e.g: `X.Y.Z (build #######)`) */
4
- export declare const VERSION_DESC = "1.114.1 (build 8a29f60)";
4
+ export declare const VERSION_DESC = "1.115.0 (build 9c5134e)";
5
5
  //# sourceMappingURL=version.d.ts.map