jsii-pacmak 1.120.0 → 1.122.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.
@@ -107,16 +107,16 @@ declare class JavaGenerator extends Generator {
107
107
  protected onInterfaceMethodOverload(ifc: spec.InterfaceType, overload: spec.Method, _originalMethod: spec.Method): void;
108
108
  protected onInterfaceProperty(ifc: spec.InterfaceType, prop: spec.Property): void;
109
109
  /**
110
- * Emits a local default implementation for optional properties inherited from
111
- * multiple distinct parent types. This remvoes the default method dispatch
112
- * ambiguity that would otherwise exist.
110
+ * Emits a local default implementation for properties inherited from multiple
111
+ * distinct parent types. This removes the default method dispatch ambiguity
112
+ * that would otherwise exist.
113
113
  *
114
114
  * @param ifc the interface to be processed.
115
115
 
116
116
  *
117
117
  * @see https://github.com/aws/jsii/issues/2256
118
118
  */
119
- private emitMultiplyInheritedOptionalProperties;
119
+ private emitMultiplyInheritedProperties;
120
120
  private emitAssemblyPackageInfo;
121
121
  private emitSubmodulePackageInfo;
122
122
  private emitMavenPom;
@@ -215,6 +215,34 @@ declare class JavaGenerator extends Generator {
215
215
  private renderAccessLevel;
216
216
  private makeModuleClass;
217
217
  private emitModuleFile;
218
+ /**
219
+ * Given a method, return the methods that we should generate implementations for on the $Default interface
220
+ *
221
+ * This can be 0..N:
222
+ *
223
+ * - 0: if the method can be inherited from a parent $Default implementation
224
+ * - 1: if the method cannot be inherited from a parent $Default implementation
225
+ * - N: ah-ha, wait! There can be overloads! And because of a historical bug,
226
+ * we didn't use to generate overloads onto $Default interfaces. So it's possible
227
+ * that we don't generate the "main" implementation, but we do generate its overloads.
228
+ *
229
+ * Technically speaking we only have to account for the bug if the type is from a different
230
+ * assembly (because we know all types from the current assembly will be generated ✨ bugless ✨,
231
+ * but just to keep it simple we'll always do the same thing).
232
+ *
233
+ * We can only get rid of this bug once the oldest dependency package a Java
234
+ * package can be used with definitely has overloaded $Default impls. So that will be a while.
235
+ */
236
+ private makeDefaultImpls;
237
+ /**
238
+ * Given a method, return the methods that we should generate implementations for on the $Proxy class
239
+ *
240
+ * See `makeDefaultImpls` for the main rationale behind this. The $Proxy class inherits from $Default
241
+ * so technically this could have usually been empty, but we need to account for the possibility that
242
+ * we implement a $Default interface from another assembly that has been generated with a buggy version
243
+ * of pacmak.
244
+ */
245
+ private makeProxyImpls;
218
246
  private emitJsiiInitializers;
219
247
  /**
220
248
  * Computes the java FQN for a JSII FQN:
@@ -7,6 +7,7 @@ const clone = require("clone");
7
7
  const case_utils_1 = require("codemaker/lib/case-utils");
8
8
  const crypto_1 = require("crypto");
9
9
  const fs = require("fs-extra");
10
+ const reflect = require("jsii-reflect");
10
11
  const jsii_rosetta_1 = require("jsii-rosetta");
11
12
  const path = require("path");
12
13
  const xmlbuilder = require("xmlbuilder");
@@ -29,6 +30,14 @@ const BUILDER_CLASS_NAME = 'Builder';
29
30
  const ANN_NOT_NULL = '@org.jetbrains.annotations.NotNull';
30
31
  const ANN_NULLABLE = '@org.jetbrains.annotations.Nullable';
31
32
  const ANN_INTERNAL = '@software.amazon.jsii.Internal';
33
+ /**
34
+ * Because of a historical bug, $Default interfaces we inherit from might not
35
+ * have all method overloads generated correctly.
36
+ *
37
+ * So when inheriting these, we might need to generate the overloads in
38
+ * subinterfaces/subclasses.
39
+ */
40
+ const GENERATE_POTENTIALLY_MISING_DEFAULT_OVERLOADS = true;
32
41
  /**
33
42
  * Build Java packages all together, by generating an aggregate POM
34
43
  *
@@ -58,6 +67,7 @@ class JavaBuilder {
58
67
  try {
59
68
  const tempSourceDir = await this.generateAggregateSourceDir(this.modules, this.options);
60
69
  scratchDirs.push(tempSourceDir);
70
+ await resolveMavenVersions(tempSourceDir.directory);
61
71
  // Need any old module object to make a target to be able to invoke build, though none of its settings
62
72
  // will be used.
63
73
  const target = this.makeTarget(this.modules[0], this.options);
@@ -542,7 +552,7 @@ class JavaGenerator extends generator_1.Generator {
542
552
  this.code.openBlock(`public${inner} interface ${ifc.name} extends ${bases}`);
543
553
  }
544
554
  onEndInterface(ifc) {
545
- this.emitMultiplyInheritedOptionalProperties(ifc);
555
+ this.emitMultiplyInheritedProperties(ifc);
546
556
  if (ifc.datatype) {
547
557
  this.emitDataType(ifc);
548
558
  }
@@ -636,53 +646,37 @@ class JavaGenerator extends generator_1.Generator {
636
646
  }
637
647
  }
638
648
  /**
639
- * Emits a local default implementation for optional properties inherited from
640
- * multiple distinct parent types. This remvoes the default method dispatch
641
- * ambiguity that would otherwise exist.
649
+ * Emits a local default implementation for properties inherited from multiple
650
+ * distinct parent types. This removes the default method dispatch ambiguity
651
+ * that would otherwise exist.
642
652
  *
643
653
  * @param ifc the interface to be processed.
644
654
 
645
655
  *
646
656
  * @see https://github.com/aws/jsii/issues/2256
647
657
  */
648
- emitMultiplyInheritedOptionalProperties(ifc) {
658
+ emitMultiplyInheritedProperties(ifc) {
649
659
  if (ifc.interfaces == null || ifc.interfaces.length <= 1) {
650
660
  // Nothing to do if we don't have parent interfaces, or if we have exactly one
651
661
  return;
652
662
  }
653
- const inheritedOptionalProps = ifc.interfaces
654
- .map(allOptionalProps.bind(this))
655
- // Calculate how many direct parents brought a given optional property
656
- .reduce((histogram, entry) => {
657
- for (const [name, spec] of Object.entries(entry)) {
658
- histogram[name] = histogram[name] ?? { spec, count: 0 };
659
- histogram[name].count += 1;
660
- }
661
- return histogram;
662
- }, {});
663
- const localProps = new Set(ifc.properties?.map((prop) => prop.name) ?? []);
664
- for (const { spec, count } of Object.values(inheritedOptionalProps)) {
665
- if (count < 2 || localProps.has(spec.name)) {
666
- continue;
667
- }
668
- this.onInterfaceProperty(ifc, spec);
669
- }
670
- function allOptionalProps(fqn) {
671
- const type = this.findType(fqn);
672
- const result = {};
673
- for (const prop of type.properties ?? []) {
674
- // Adding artifical "overrides" here for code-gen quality's sake.
675
- result[prop.name] = { ...prop, overrides: type.fqn };
676
- }
677
- // Include optional properties of all super interfaces in the result
678
- for (const base of type.interfaces ?? []) {
679
- for (const [name, prop] of Object.entries(allOptionalProps.call(this, base))) {
680
- if (!(name in result)) {
681
- result[name] = prop;
682
- }
663
+ const memberSources = {};
664
+ for (const parent of ifc.interfaces) {
665
+ const type = this.reflectAssembly.system.findInterface(parent);
666
+ for (const prop of type.allProperties) {
667
+ if (!(prop.name in memberSources)) {
668
+ memberSources[prop.name] = {};
683
669
  }
670
+ memberSources[prop.name][prop.definingType.fqn] = prop.spec;
671
+ }
672
+ }
673
+ for (const defininingTypes of Object.values(memberSources)) {
674
+ // Ignore our own type
675
+ delete defininingTypes[ifc.fqn];
676
+ const keys = Object.keys(defininingTypes);
677
+ if (keys.length > 1) {
678
+ this.onInterfaceProperty(ifc, defininingTypes[keys[0]]);
684
679
  }
685
- return result;
686
680
  }
687
681
  }
688
682
  emitAssemblyPackageInfo(mod) {
@@ -1320,9 +1314,11 @@ class JavaGenerator extends generator_1.Generator {
1320
1314
  this.code.line('/**');
1321
1315
  this.code.line(' * A proxy class which represents a concrete javascript instance of this type.');
1322
1316
  this.code.line(' */');
1317
+ // Get the list of $Default interfaces
1323
1318
  const baseInterfaces = this.defaultInterfacesFor(type, {
1324
1319
  includeThisType: true,
1325
1320
  });
1321
+ // Add ourselves if we don't have a $Default interface
1326
1322
  if (type.isInterfaceType() && !hasDefaultInterfaces(type.assembly)) {
1327
1323
  // Extend this interface directly since this module does not have the Jsii$Default
1328
1324
  baseInterfaces.push(this.toNativeFqn(type.fqn));
@@ -1339,10 +1335,7 @@ class JavaGenerator extends generator_1.Generator {
1339
1335
  this.code.line('super(objRef);');
1340
1336
  this.code.closeBlock();
1341
1337
  // emit all properties
1342
- for (const reflectProp of type.allProperties.filter((prop) => prop.abstract &&
1343
- (prop.parentType.fqn === type.fqn ||
1344
- prop.parentType.isClassType() ||
1345
- !hasDefaultInterfaces(prop.assembly)))) {
1338
+ for (const reflectProp of type.allProperties.filter(needsProxyImpl)) {
1346
1339
  const prop = clone(reflectProp.spec);
1347
1340
  prop.abstract = false;
1348
1341
  // Emitting "final" since this is a proxy and nothing will/should override this
@@ -1352,21 +1345,11 @@ class JavaGenerator extends generator_1.Generator {
1352
1345
  });
1353
1346
  }
1354
1347
  // emit all the methods
1355
- for (const reflectMethod of type.allMethods.filter((method) => method.abstract &&
1356
- (method.parentType.fqn === type.fqn ||
1357
- method.parentType.isClassType() ||
1358
- !hasDefaultInterfaces(method.assembly)))) {
1359
- const method = clone(reflectMethod.spec);
1360
- method.abstract = false;
1348
+ for (const reflectMethod of type.allMethods.flatMap(this.makeProxyImpls.bind(this))) {
1349
+ const method = clone(reflectMethod);
1361
1350
  // Emitting "final" since this is a proxy and nothing will/should override this
1351
+ method.abstract = false;
1362
1352
  this.emitMethod(type.spec, method, { final: true, overrides: true });
1363
- for (const overloadedMethod of this.createOverloadsForOptionals(method)) {
1364
- overloadedMethod.abstract = false;
1365
- this.emitMethod(type.spec, overloadedMethod, {
1366
- final: true,
1367
- overrides: true,
1368
- });
1369
- }
1370
1353
  }
1371
1354
  this.code.closeBlock();
1372
1355
  }
@@ -1380,23 +1363,16 @@ class JavaGenerator extends generator_1.Generator {
1380
1363
  this.code.openBlock(`interface ${INTERFACE_DEFAULT_CLASS_NAME} extends ${baseInterfaces
1381
1364
  .sort()
1382
1365
  .join(', ')}`);
1383
- for (const property of type.allProperties.filter((prop) => prop.abstract &&
1384
- // Only checking the getter - java.lang.Object has no setters.
1385
- !isJavaLangObjectMethodName(`get${(0, naming_util_1.jsiiToPascalCase)(prop.name)}`) &&
1386
- (prop.parentType.fqn === type.fqn ||
1387
- !hasDefaultInterfaces(prop.assembly)))) {
1366
+ for (const property of type.allProperties.filter(needsDefaultImpl)) {
1388
1367
  this.emitProperty(type.spec, property.spec, property.definingType.spec, {
1389
1368
  defaultImpl: true,
1390
1369
  overrides: type.isInterfaceType(),
1391
1370
  });
1392
1371
  }
1393
- for (const method of type.allMethods.filter((method) => method.abstract &&
1394
- !isJavaLangObjectMethodName(method.name) &&
1395
- (method.parentType.fqn === type.fqn ||
1396
- !hasDefaultInterfaces(method.assembly)))) {
1397
- this.emitMethod(type.spec, method.spec, {
1372
+ for (const method of type.allMethods.flatMap(this.makeDefaultImpls.bind(this))) {
1373
+ this.emitMethod(type.spec, method, {
1398
1374
  defaultImpl: true,
1399
- overrides: type.isInterfaceType(),
1375
+ overrides: true,
1400
1376
  });
1401
1377
  }
1402
1378
  this.code.closeBlock();
@@ -1795,7 +1771,7 @@ class JavaGenerator extends generator_1.Generator {
1795
1771
  }
1796
1772
  this.code.line();
1797
1773
  this.code.line('@Override');
1798
- this.code.openBlock('public final boolean equals(final Object o)');
1774
+ this.code.openBlock('public final boolean equals(final java.lang.Object o)');
1799
1775
  this.code.line('if (this == o) return true;');
1800
1776
  // This was already checked by `super.equals(o)`, so we skip it here...
1801
1777
  this.code.line('if (o == null || getClass() != o.getClass()) return false;');
@@ -2313,6 +2289,54 @@ class JavaGenerator extends generator_1.Generator {
2313
2289
  this.code.closeFile(moduleFile);
2314
2290
  return moduleClass;
2315
2291
  }
2292
+ /**
2293
+ * Given a method, return the methods that we should generate implementations for on the $Default interface
2294
+ *
2295
+ * This can be 0..N:
2296
+ *
2297
+ * - 0: if the method can be inherited from a parent $Default implementation
2298
+ * - 1: if the method cannot be inherited from a parent $Default implementation
2299
+ * - N: ah-ha, wait! There can be overloads! And because of a historical bug,
2300
+ * we didn't use to generate overloads onto $Default interfaces. So it's possible
2301
+ * that we don't generate the "main" implementation, but we do generate its overloads.
2302
+ *
2303
+ * Technically speaking we only have to account for the bug if the type is from a different
2304
+ * assembly (because we know all types from the current assembly will be generated ✨ bugless ✨,
2305
+ * but just to keep it simple we'll always do the same thing).
2306
+ *
2307
+ * We can only get rid of this bug once the oldest dependency package a Java
2308
+ * package can be used with definitely has overloaded $Default impls. So that will be a while.
2309
+ */
2310
+ makeDefaultImpls(m) {
2311
+ const ret = [];
2312
+ if (needsDefaultImpl(m)) {
2313
+ ret.push(m.spec);
2314
+ }
2315
+ // Account for a past bug
2316
+ if (needsDefaultImpl(m) || GENERATE_POTENTIALLY_MISING_DEFAULT_OVERLOADS) {
2317
+ ret.push(...this.createOverloadsForOptionals(m.spec));
2318
+ }
2319
+ return ret;
2320
+ }
2321
+ /**
2322
+ * Given a method, return the methods that we should generate implementations for on the $Proxy class
2323
+ *
2324
+ * See `makeDefaultImpls` for the main rationale behind this. The $Proxy class inherits from $Default
2325
+ * so technically this could have usually been empty, but we need to account for the possibility that
2326
+ * we implement a $Default interface from another assembly that has been generated with a buggy version
2327
+ * of pacmak.
2328
+ */
2329
+ makeProxyImpls(m) {
2330
+ const ret = [];
2331
+ if (needsProxyImpl(m)) {
2332
+ ret.push(m.spec);
2333
+ }
2334
+ // Account for a past bug
2335
+ if (needsProxyImpl(m) || GENERATE_POTENTIALLY_MISING_DEFAULT_OVERLOADS) {
2336
+ ret.push(...this.createOverloadsForOptionals(m.spec));
2337
+ }
2338
+ return ret;
2339
+ }
2316
2340
  emitJsiiInitializers(cls) {
2317
2341
  this.code.line();
2318
2342
  this.code.openBlock(`protected ${cls.name}(final software.amazon.jsii.JsiiObjectRef objRef)`);
@@ -2816,4 +2840,58 @@ function removeIntersections(x) {
2816
2840
  }
2817
2841
  return x;
2818
2842
  }
2843
+ /**
2844
+ * Run the maven 'versions:resolve-ranges' plugin
2845
+ *
2846
+ * Initially, we generate version ranges into the pom file based on the NPM
2847
+ * version ranges.
2848
+ *
2849
+ * At build time, given a dependency version range, Maven will download metadata
2850
+ * for all possible versions before every (uncached) build. This takes a long
2851
+ * time, before finally resolving to the latest version anyway.
2852
+ *
2853
+ * Instead, we use the Maven 'versions' plugin to resolve our wide ranges to
2854
+ * point versions. We want the "latest matching" version anyway, and if we don't
2855
+ * the resolution now (which downloads the .poms of all possible versions) it
2856
+ * will happen during every single build.
2857
+ */
2858
+ async function resolveMavenVersions(directory) {
2859
+ const versionsPluginVersion = '2.20.1';
2860
+ await (0, util_1.subprocess)('mvn', [
2861
+ `org.codehaus.mojo:versions-maven-plugin:${versionsPluginVersion}:resolve-ranges`,
2862
+ ], {
2863
+ cwd: directory,
2864
+ retry: { maxAttempts: 1 },
2865
+ });
2866
+ }
2867
+ /**
2868
+ * Whether the given property or method needs to be implemented on a $Proxy class
2869
+ *
2870
+ * Proxies extend the class they're for (if for a class), and the $Default interfaces
2871
+ * of all the base interfaces, so implementations need to be present for everything
2872
+ * that is not abstract and can be inherited from a $Default interface.
2873
+ */
2874
+ function needsProxyImpl(x) {
2875
+ // Interface members are always marked 'abstract', but we only need to
2876
+ // implement them if they come from a class (because interface members
2877
+ // will have a $Default impl that calls out to jsii already).
2878
+ const isAbstractClassMember = x.definingType.isClassType() && x.abstract;
2879
+ return (isAbstractClassMember || !hasDefaultInterfaces(x.definingType.assembly));
2880
+ }
2881
+ /**
2882
+ * Whether the given property or method needs to be implemented on a $Default interface
2883
+ *
2884
+ * $Default interfaces extend the interface they're for, and the $Default interfaces
2885
+ * of all the base interfaces, so implementations need to be present for everything
2886
+ * that is defined on the current interface or cannot be inherited from a $Default interface.
2887
+ */
2888
+ function needsDefaultImpl(x) {
2889
+ const isBuiltinMethod = x instanceof reflect.Property
2890
+ ? // Only checking the getter - java.lang.Object has no setters.
2891
+ isJavaLangObjectMethodName(`get${(0, naming_util_1.jsiiToPascalCase)(x.name)}`)
2892
+ : isJavaLangObjectMethodName(x.name);
2893
+ return ((!hasDefaultInterfaces(x.definingType.assembly) ||
2894
+ x.definingType.fqn === x.parentType.fqn) &&
2895
+ !isBuiltinMethod);
2896
+ }
2819
2897
  //# sourceMappingURL=java.js.map
@@ -1,10 +1,21 @@
1
1
  import { Assembly, OptionalValue, TypeReference, Type } from '@jsii/spec';
2
2
  import { CodeMaker } from 'codemaker';
3
+ /**
4
+ * The position of a type
5
+ *
6
+ * Types are rendered differently depending on what position they're in:
7
+ *
8
+ * - `type`: a type annotation; these are not evaluated during execution.
9
+ * - `value`: a value in a function body; these are evaluated when the function is called.
10
+ * - `decl`: a value in a class declaration; these are evaluated when a class is being
11
+ * instantiated, before it's done.
12
+ */
13
+ export type TypePosition = 'type' | 'value' | 'decl';
3
14
  /**
4
15
  * Actually more of a TypeNameFactory than a TypeName
5
16
  */
6
17
  export interface TypeName {
7
- pythonType(context: NamingContext): string;
18
+ pythonType(pos: TypePosition, context: NamingContext): string;
8
19
  requiredImports(context: NamingContext): PythonImports;
9
20
  }
10
21
  export interface PythonImports {
@@ -27,12 +38,6 @@ export interface NamingContext {
27
38
  readonly submodule: string;
28
39
  /** Holds the set of intersection types used in the current module */
29
40
  readonly intersectionTypes: IntersectionTypesRegistry;
30
- /**
31
- * The declaration is made in the context of a type annotation (so it can be quoted)
32
- *
33
- * @default true
34
- */
35
- readonly typeAnnotation?: boolean;
36
41
  /**
37
42
  * A an array representing the stack of declarations currently being
38
43
  * initialized. All of these names can only be referred to using a forward
@@ -40,6 +45,8 @@ export interface NamingContext {
40
45
  * they can be used safely from implementations so long as those are not *run*
41
46
  * as part of the declaration).
42
47
  *
48
+ * Closest to the current type is at the end.
49
+ *
43
50
  * @default []
44
51
  */
45
52
  readonly surroundingTypeFqns?: readonly string[];
@@ -49,12 +56,6 @@ export interface NamingContext {
49
56
  * @internal
50
57
  */
51
58
  readonly ignoreOptional?: boolean;
52
- /**
53
- * The set of jsii type FQNs that have already been emitted so far. This is
54
- * used to determine whether a given type reference is a forward declaration
55
- * or not when emitting type signatures.
56
- */
57
- readonly emittedTypes: Set<string>;
58
59
  /**
59
60
  * Whether the type is emitted for a parameter or not. This may change the
60
61
  * exact type signature being emitted (e.g: Arrays are typing.Sequence[T] for
@@ -87,8 +87,8 @@ class Dict {
87
87
  _Dict_element.set(this, void 0);
88
88
  __classPrivateFieldSet(this, _Dict_element, element, "f");
89
89
  }
90
- pythonType(context) {
91
- return `typing.Mapping[builtins.str, ${__classPrivateFieldGet(this, _Dict_element, "f").pythonType(context)}]`;
90
+ pythonType(pos, context) {
91
+ return `typing.Mapping[builtins.str, ${__classPrivateFieldGet(this, _Dict_element, "f").pythonType(pos, context)}]`;
92
92
  }
93
93
  requiredImports(context) {
94
94
  return __classPrivateFieldGet(this, _Dict_element, "f").requiredImports(context);
@@ -101,9 +101,9 @@ class List {
101
101
  _List_element.set(this, void 0);
102
102
  __classPrivateFieldSet(this, _List_element, element, "f");
103
103
  }
104
- pythonType(context) {
104
+ pythonType(pos, context) {
105
105
  const type = context.parameterType ? 'Sequence' : 'List';
106
- return `typing.${type}[${__classPrivateFieldGet(this, _List_element, "f").pythonType(context)}]`;
106
+ return `typing.${type}[${__classPrivateFieldGet(this, _List_element, "f").pythonType(pos, context)}]`;
107
107
  }
108
108
  requiredImports(context) {
109
109
  return __classPrivateFieldGet(this, _List_element, "f").requiredImports(context);
@@ -116,8 +116,8 @@ class Optional {
116
116
  _Optional_wrapped.set(this, void 0);
117
117
  __classPrivateFieldSet(this, _Optional_wrapped, wrapped, "f");
118
118
  }
119
- pythonType(context) {
120
- const optionalType = __classPrivateFieldGet(this, _Optional_wrapped, "f").pythonType({
119
+ pythonType(pos, context) {
120
+ const optionalType = __classPrivateFieldGet(this, _Optional_wrapped, "f").pythonType(pos, {
121
121
  ...context,
122
122
  ignoreOptional: true,
123
123
  });
@@ -176,9 +176,9 @@ class Union {
176
176
  _Union_options.set(this, void 0);
177
177
  __classPrivateFieldSet(this, _Union_options, options, "f");
178
178
  }
179
- pythonType(context) {
179
+ pythonType(pos, context) {
180
180
  return `typing.Union[${__classPrivateFieldGet(this, _Union_options, "f")
181
- .map((o) => o.pythonType(context))
181
+ .map((o) => o.pythonType(pos, context))
182
182
  .join(', ')}]`;
183
183
  }
184
184
  requiredImports(context) {
@@ -192,9 +192,9 @@ class Intersection {
192
192
  _Intersection_types.set(this, void 0);
193
193
  __classPrivateFieldSet(this, _Intersection_types, types, "f");
194
194
  }
195
- pythonType(context) {
195
+ pythonType(pos, context) {
196
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));
197
+ const name = context.intersectionTypes.obtain(__classPrivateFieldGet(this, _Intersection_types, "f").map((t) => t.pythonType(pos, context)).map(stripQuotes));
198
198
  // This will never be in scope already, so always render between quotes
199
199
  return `'${name}'`;
200
200
  }
@@ -209,24 +209,32 @@ class UserType {
209
209
  _UserType_fqn.set(this, void 0);
210
210
  __classPrivateFieldSet(this, _UserType_fqn, fqn, "f");
211
211
  }
212
- pythonType(context) {
213
- return this.resolve(context).pythonType;
212
+ pythonType(pos, context) {
213
+ return this.resolve(pos, context).pythonType;
214
214
  }
215
215
  requiredImports(context) {
216
- const requiredImport = this.resolve(context).requiredImport;
216
+ const requiredImport = this.resolve('value', context).requiredImport;
217
217
  if (requiredImport == null) {
218
218
  return {};
219
219
  }
220
220
  return { [requiredImport.sourcePackage]: new Set([requiredImport.item]) };
221
221
  }
222
- resolve({ assembly, emittedTypes, submodule, surroundingTypeFqns, typeAnnotation = true, parameterType, typeResolver, }) {
222
+ resolve(pos, { assembly, submodule, surroundingTypeFqns, parameterType, typeResolver, }) {
223
223
  const { assemblyName, packageName, pythonFqn } = toPythonFqn(__classPrivateFieldGet(this, _UserType_fqn, "f"), assembly);
224
- // If this is a type annotation for a parameter, allow dicts to be passed where structs are expected.
224
+ // If this is a type annotation for a parameter, allow dicts to be passed
225
+ // where structs are expected for backwards compatibility with the very
226
+ // first versions of jsii (dicts need to be in jsii-casing).
225
227
  const type = typeResolver(__classPrivateFieldGet(this, _UserType_fqn, "f"));
226
228
  const isStruct = (0, spec_1.isInterfaceType)(type) && !!type.datatype;
227
- const wrapType = typeAnnotation && parameterType && isStruct
228
- ? (pyType) => `typing.Union[${pyType}, typing.Dict[builtins.str, typing.Any]]`
229
- : (pyType) => pyType;
229
+ // Make a function that quotes the string based on whether we're using it as a type annotation or not.
230
+ // It's never wrong to quote type annotations, and it never fails and evaluates faster because it avoids
231
+ // object lookups at eval time.
232
+ const maybeQuote = (x) => (pos === 'type' ? `"${x}"` : x);
233
+ const wrapType = pos === 'type' && parameterType && isStruct
234
+ ? (pyType) => `typing.Union[${maybeQuote(pyType)}, typing.Dict[builtins.str, typing.Any]]`
235
+ : maybeQuote;
236
+ /////////////////////////////////
237
+ // Type from other assembly
230
238
  // Emit aliased imports for dependencies (this avoids name collisions)
231
239
  if (assemblyName !== assembly.name) {
232
240
  const aliasSuffix = (0, crypto_1.createHash)('sha256')
@@ -247,50 +255,69 @@ class UserType {
247
255
  }
248
256
  const submodulePythonName = toPythonFqn(submodule, assembly).pythonFqn;
249
257
  const typeSubmodulePythonName = toPythonFqn(findParentSubmodule(type, assembly), assembly).pythonFqn;
250
- if (typeSubmodulePythonName === submodulePythonName) {
251
- // Identify declarations that are not yet initialized and hence cannot be
252
- // used as part of a type qualification. Since this is not a forward
253
- // reference, the type was already emitted and its un-qualified name must
254
- // be used instead of its locally qualified name.
258
+ //////////////////////////////////////////////
259
+ // Type from same assembly, other submodule
260
+ if (typeSubmodulePythonName !== submodulePythonName) {
261
+ const [toImport, ...nested] = pythonFqn
262
+ .substring(typeSubmodulePythonName.length + 1)
263
+ .split('.');
264
+ const aliasSuffix = (0, crypto_1.createHash)('sha256')
265
+ .update(typeSubmodulePythonName)
266
+ .update('.')
267
+ .update(toImport)
268
+ .digest('hex')
269
+ .substring(0, 8);
270
+ const alias = `_${toImport}_${aliasSuffix}`;
271
+ return {
272
+ pythonType: wrapType([alias, ...nested].join('.')),
273
+ requiredImport: {
274
+ sourcePackage: relativeImportPath(submodulePythonName, typeSubmodulePythonName),
275
+ item: `${toImport} as ${alias}`,
276
+ },
277
+ };
278
+ // Have the 'else' here to minimize the diff.
279
+ // eslint-disable-next-line no-else-return
280
+ }
281
+ else {
282
+ //////////////////////////////////////////////
283
+ // Type from same submodule
284
+ //
285
+ // Considerations:
286
+ // - We could be in the same nested class or in a different nested class here.
287
+ // - We could also be trying to reference types that will be below
288
+ // ourselves in the source code order, which we will need to render as
289
+ // type reference strings.
255
290
  const nestingParent = surroundingTypeFqns
256
291
  ?.map((fqn) => toPythonFqn(fqn, assembly).pythonFqn)
257
292
  ?.reverse()
258
293
  ?.find((parent) => pythonFqn.startsWith(`${parent}.`));
259
- if (typeAnnotation &&
260
- (!emittedTypes.has(__classPrivateFieldGet(this, _UserType_fqn, "f")) || nestingParent != null)) {
261
- // Possibly a forward reference, outputting the stringifierd python FQN
294
+ if (nestingParent && pos === 'decl') {
295
+ // In normal function bodies etc. we must use the fully-qualified name,
296
+ // but while executing the class declarations we must use the shorter name
297
+ // of the local variable we're defining.
298
+ //
299
+ // An example is most clear:
300
+ //
301
+ // ```py
302
+ // class A:
303
+ // class B: pass
304
+ // class C(B): # <-- note
305
+ // def some_method(self, b: "A.B"): # <-- note
306
+ // return A.B() # <-- note
307
+ // ```
308
+ //
309
+ // The FQN is separated by `.` and we would
310
+ // also use `.` to access subtypes in Python and have the same names, so we
311
+ // can just use a substring.
262
312
  return {
263
- pythonType: wrapType(JSON.stringify(pythonFqn.substring(submodulePythonName.length + 1))),
313
+ pythonType: wrapType(pythonFqn.slice(nestingParent.length + 1)),
264
314
  };
265
315
  }
266
- if (!typeAnnotation && nestingParent) {
267
- // This is not for a type annotation, so we should be at a point in time
268
- // where the surrounding symbol has been defined entirely, so we can
269
- // refer to it "normally" now.
270
- return { pythonType: pythonFqn.slice(packageName.length + 1) };
271
- }
272
316
  // We'll just make a module-qualified reference at this point.
273
317
  return {
274
318
  pythonType: wrapType(pythonFqn.substring(submodulePythonName.length + 1)),
275
319
  };
276
320
  }
277
- const [toImport, ...nested] = pythonFqn
278
- .substring(typeSubmodulePythonName.length + 1)
279
- .split('.');
280
- const aliasSuffix = (0, crypto_1.createHash)('sha256')
281
- .update(typeSubmodulePythonName)
282
- .update('.')
283
- .update(toImport)
284
- .digest('hex')
285
- .substring(0, 8);
286
- const alias = `_${toImport}_${aliasSuffix}`;
287
- return {
288
- pythonType: wrapType([alias, ...nested].join('.')),
289
- requiredImport: {
290
- sourcePackage: relativeImportPath(submodulePythonName, typeSubmodulePythonName),
291
- item: `${toImport} as ${alias}`,
292
- },
293
- };
294
321
  }
295
322
  }
296
323
  _UserType_fqn = new WeakMap();
@@ -341,9 +341,6 @@ class BasePythonClassType {
341
341
  code.line('pass');
342
342
  }
343
343
  code.closeBlock();
344
- if (this.fqn != null) {
345
- context.emittedTypes.add(this.fqn);
346
- }
347
344
  }
348
345
  /**
349
346
  * Sort the this.bases array for proper Python MRO.
@@ -469,7 +466,9 @@ class BaseMethod {
469
466
  }
470
467
  emit(code, context, opts) {
471
468
  const { renderAbstract = true, forceEmitBody = false } = opts ?? {};
472
- const returnType = (0, type_name_1.toTypeName)(this.returns).pythonType(context);
469
+ const returnType = (0, type_name_1.toTypeName)(this.returns).pythonType('type', {
470
+ ...context,
471
+ });
473
472
  // We cannot (currently?) blindly use the names given to us by the JSII for
474
473
  // initializers, because our keyword lifting will allow two names to clash.
475
474
  // This can hopefully be removed once we get https://github.com/aws/jsii/issues/288
@@ -492,7 +491,7 @@ class BaseMethod {
492
491
  // This can hopefully be removed once we get https://github.com/aws/jsii/issues/288
493
492
  // resolved.
494
493
  const paramName = toPythonParameterName(param.name, liftedPropNames);
495
- const paramType = typeFac.pythonType({
494
+ const paramType = typeFac.pythonType('type', {
496
495
  ...context,
497
496
  parameterType: true,
498
497
  });
@@ -525,10 +524,9 @@ class BaseMethod {
525
524
  // Iterate over all of our props, and reflect them into our params.
526
525
  for (const prop of liftedProperties) {
527
526
  const paramName = toPythonParameterName(prop.prop.name);
528
- const paramType = (0, type_name_1.toTypeName)(prop.prop).pythonType({
527
+ const paramType = (0, type_name_1.toTypeName)(prop.prop).pythonType('type', {
529
528
  ...context,
530
529
  parameterType: true,
531
- typeAnnotation: true,
532
530
  });
533
531
  const paramDefault = prop.prop.optional ? ' = None' : '';
534
532
  pythonParams.push(`${paramName}: ${paramType}${paramDefault}`);
@@ -549,7 +547,7 @@ class BaseMethod {
549
547
  pythonParams.pop();
550
548
  const lastParameter = this.parameters.slice(-1)[0];
551
549
  const paramName = toPythonParameterName(lastParameter.name);
552
- const paramType = (0, type_name_1.toTypeName)(lastParameter.type).pythonType(context);
550
+ const paramType = (0, type_name_1.toTypeName)(lastParameter.type).pythonType('type', context);
553
551
  pythonParams.push(`*${paramName}: ${paramType}`);
554
552
  }
555
553
  const decorators = new Array();
@@ -595,10 +593,7 @@ class BaseMethod {
595
593
  emitAutoProps(code, context, liftedPropNames) {
596
594
  const lastParameter = this.parameters.slice(-1)[0];
597
595
  const argName = toPythonParameterName(lastParameter.name, liftedPropNames);
598
- const typeName = (0, type_name_1.toTypeName)(lastParameter.type).pythonType({
599
- ...context,
600
- typeAnnotation: false,
601
- });
596
+ const typeName = (0, type_name_1.toTypeName)(lastParameter.type).pythonType('value', context);
602
597
  // We need to build up a list of properties, which are mandatory, these are the
603
598
  // ones we will specify to start with in our dictionary literal.
604
599
  const liftedProps = this.getLiftedProperties(context.resolver).map((p) => new StructField(this.generator, p.prop, p.definingType));
@@ -616,10 +611,7 @@ class BaseMethod {
616
611
  throw new Error('Parent not known.');
617
612
  }
618
613
  if (this.isStatic) {
619
- jsiiMethodParams.push((0, type_name_1.toTypeName)(this.parent).pythonType({
620
- ...context,
621
- typeAnnotation: false,
622
- }));
614
+ jsiiMethodParams.push((0, type_name_1.toTypeName)(this.parent).pythonType('value', context));
623
615
  }
624
616
  else {
625
617
  // Using the dynamic class of `self`.
@@ -698,7 +690,7 @@ class BaseProperty {
698
690
  }
699
691
  emit(code, context, opts) {
700
692
  const { renderAbstract = true, forceEmitBody = false } = opts ?? {};
701
- const pythonType = (0, type_name_1.toTypeName)(this.type).pythonType(context);
693
+ const pythonType = (0, type_name_1.toTypeName)(this.type).pythonType('type', context);
702
694
  code.line(`@${this.decorator}`);
703
695
  code.line(`@jsii.member(jsii_name="${this.jsName}")`);
704
696
  if (renderAbstract && this.abstract) {
@@ -758,10 +750,7 @@ class Interface extends BasePythonClassType {
758
750
  // Then, we have to emit a Proxy class which implements our proxy interface.
759
751
  const proxyBases = this.bases.map((b) =>
760
752
  // "# type: ignore[misc]" because MyPy cannot check dynamic base classes (naturally)
761
- `jsii.proxy_for(${(0, type_name_1.toTypeName)(b).pythonType({
762
- ...context,
763
- typeAnnotation: false,
764
- })}) # type: ignore[misc]`);
753
+ `jsii.proxy_for(${(0, type_name_1.toTypeName)(b).pythonType('value', context)}) # type: ignore[misc]`);
765
754
  openSignature(code, 'class', this.proxyClassName, proxyBases);
766
755
  this.generator.emitDocString(code, this.apiLocation, this.docs, {
767
756
  documentableItem: `class-${this.pythonName}`,
@@ -783,12 +772,9 @@ class Interface extends BasePythonClassType {
783
772
  code.line();
784
773
  code.line('# Adding a "__jsii_proxy_class__(): typing.Type" function to the interface');
785
774
  code.line(`typing.cast(typing.Any, ${this.pythonName}).__jsii_proxy_class__ = lambda : ${this.proxyClassName}`);
786
- if (this.fqn != null) {
787
- context.emittedTypes.add(this.fqn);
788
- }
789
775
  }
790
776
  getClassParams(context) {
791
- const params = this.bases.map((b) => (0, type_name_1.toTypeName)(b).pythonType({ ...context, typeAnnotation: false }));
777
+ const params = this.bases.map((b) => (0, type_name_1.toTypeName)(b).pythonType('decl', context));
792
778
  params.push('typing_extensions.Protocol');
793
779
  return params;
794
780
  }
@@ -842,15 +828,12 @@ class Struct extends BasePythonClassType {
842
828
  }
843
829
  this.emitMagicMethods(code);
844
830
  code.closeBlock();
845
- if (this.fqn != null) {
846
- context.emittedTypes.add(this.fqn);
847
- }
848
831
  }
849
832
  requiredImports(context) {
850
833
  return (0, type_name_1.mergePythonImports)(super.requiredImports(context), ...this.allMembers.map((mem) => mem.requiredImports(context)));
851
834
  }
852
835
  getClassParams(context) {
853
- return this.bases.map((b) => (0, type_name_1.toTypeName)(b).pythonType({ ...context, typeAnnotation: false }));
836
+ return this.bases.map((b) => (0, type_name_1.toTypeName)(b).pythonType('decl', context));
854
837
  }
855
838
  /**
856
839
  * Find all fields (inherited as well)
@@ -876,10 +859,7 @@ class Struct extends BasePythonClassType {
876
859
  // Re-type struct arguments that were passed as "dict". Do this before validating argument types...
877
860
  for (const member of members.filter((m) => m.isStruct(this.generator))) {
878
861
  // Note that "None" is NOT an instance of dict (that's convenient!)
879
- const typeName = (0, type_name_1.toTypeName)(member.type.type).pythonType({
880
- ...context,
881
- typeAnnotation: false,
882
- });
862
+ const typeName = (0, type_name_1.toTypeName)(member.type.type).pythonType('value', context);
883
863
  code.openBlock(`if isinstance(${member.pythonName}, dict)`);
884
864
  code.line(`${member.pythonName} = ${typeName}(**${member.pythonName})`);
885
865
  code.closeBlock();
@@ -987,7 +967,7 @@ class StructField {
987
967
  * Return the Python type annotation for this type
988
968
  */
989
969
  typeAnnotation(context) {
990
- return (0, type_name_1.toTypeName)(this.type).pythonType(context);
970
+ return (0, type_name_1.toTypeName)(this.type).pythonType('type', context);
991
971
  }
992
972
  emitDocString(code) {
993
973
  this.generator.emitDocString(code, this.apiLocation, this.docs, {
@@ -1042,7 +1022,7 @@ class Class extends BasePythonClassType {
1042
1022
  emit(code, context) {
1043
1023
  // First we emit our implments decorator
1044
1024
  if (this.interfaces.length > 0) {
1045
- const interfaces = this.interfaces.map((b) => (0, type_name_1.toTypeName)(b).pythonType({ ...context, typeAnnotation: false }));
1025
+ const interfaces = this.interfaces.map((b) => (0, type_name_1.toTypeName)(b).pythonType('decl', context));
1046
1026
  code.line(`@jsii.implements(${interfaces.join(', ')})`);
1047
1027
  }
1048
1028
  // Then we do our normal class logic for emitting our members.
@@ -1055,10 +1035,7 @@ class Class extends BasePythonClassType {
1055
1035
  const proxyBases = [this.pythonName];
1056
1036
  for (const base of this.abstractBases) {
1057
1037
  // "# type: ignore[misc]" because MyPy cannot check dynamic base classes (naturally)
1058
- proxyBases.push(`jsii.proxy_for(${(0, type_name_1.toTypeName)(base).pythonType({
1059
- ...context,
1060
- typeAnnotation: false,
1061
- })}) # type: ignore[misc]`);
1038
+ proxyBases.push(`jsii.proxy_for(${(0, type_name_1.toTypeName)(base).pythonType('value', context)}) # type: ignore[misc]`);
1062
1039
  }
1063
1040
  code.line();
1064
1041
  code.line();
@@ -1090,7 +1067,7 @@ class Class extends BasePythonClassType {
1090
1067
  }
1091
1068
  }
1092
1069
  getClassParams(context) {
1093
- const params = this.bases.map((b) => (0, type_name_1.toTypeName)(b).pythonType({ ...context, typeAnnotation: false }));
1070
+ const params = this.bases.map((b) => (0, type_name_1.toTypeName)(b).pythonType('decl', context));
1094
1071
  const metaclass = this.abstract ? 'JSIIAbstractClass' : 'JSIIMeta';
1095
1072
  params.push(`metaclass=jsii.${metaclass}`);
1096
1073
  params.push(`jsii_type="${this.fqn}"`);
@@ -1948,7 +1925,6 @@ class PythonGenerator extends generator_1.Generator {
1948
1925
  const resolver = new TypeResolver(this.types, assm, (fqn) => this.findModule(fqn), (fqn) => this.findType(fqn));
1949
1926
  this.package.write(this.code, {
1950
1927
  assembly: assm,
1951
- emittedTypes: new Set(),
1952
1928
  resolver,
1953
1929
  runtimeTypeChecking: this.runtimeTypeChecking,
1954
1930
  submodule: assm.name,
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.120.0 (build 192dc88)";
4
+ export declare const VERSION_DESC = "1.122.0 (build d5d44e9)";
5
5
  //# sourceMappingURL=version.d.ts.map
package/lib/version.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
- // Generated at 2025-11-24T11:51:54Z by generate.sh
2
+ // Generated at 2025-12-22T15:21:44Z by generate.sh
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.VERSION_DESC = exports.VERSION = void 0;
5
5
  /** The short version number for this jsii-pacmak release (e.g: `X.Y.Z`) */
6
6
  // eslint-disable-next-line @typescript-eslint/no-inferrable-types
7
- exports.VERSION = '1.120.0';
7
+ exports.VERSION = '1.122.0';
8
8
  /** The qualified version number for this jsii-pacmak release (e.g: `X.Y.Z (build #######)`) */
9
- exports.VERSION_DESC = '1.120.0 (build 192dc88)';
9
+ exports.VERSION_DESC = '1.122.0 (build d5d44e9)';
10
10
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsii-pacmak",
3
- "version": "1.120.0",
3
+ "version": "1.122.0",
4
4
  "description": "A code generation framework for jsii backend languages",
5
5
  "license": "Apache-2.0",
6
6
  "author": {
@@ -37,24 +37,24 @@
37
37
  "package": "package-js"
38
38
  },
39
39
  "dependencies": {
40
- "@jsii/check-node": "1.120.0",
41
- "@jsii/spec": "1.120.0",
40
+ "@jsii/check-node": "1.122.0",
41
+ "@jsii/spec": "1.122.0",
42
42
  "clone": "^2.1.2",
43
- "codemaker": "^1.120.0",
43
+ "codemaker": "^1.122.0",
44
44
  "commonmark": "^0.31.2",
45
45
  "escape-string-regexp": "^4.0.0",
46
46
  "fs-extra": "^10.1.0",
47
- "jsii-reflect": "^1.120.0",
47
+ "jsii-reflect": "^1.122.0",
48
48
  "semver": "^7.7.2",
49
49
  "spdx-license-list": "^6.10.0",
50
50
  "xmlbuilder": "^15.1.1",
51
51
  "yargs": "^17.7.2"
52
52
  },
53
53
  "devDependencies": {
54
- "@jsii/dotnet-runtime": "^1.120.0",
55
- "@jsii/go-runtime": "^1.120.0",
56
- "@jsii/java-runtime": "^1.120.0",
57
- "@scope/jsii-calc-lib": "^1.120.0",
54
+ "@jsii/dotnet-runtime": "^1.122.0",
55
+ "@jsii/go-runtime": "^1.122.0",
56
+ "@jsii/java-runtime": "^1.122.0",
57
+ "@scope/jsii-calc-lib": "^1.122.0",
58
58
  "@types/clone": "^2.1.4",
59
59
  "@types/commonmark": "^0.27.10",
60
60
  "@types/diff": "^5.2.3",
@@ -63,7 +63,7 @@
63
63
  "@types/yargs": "^17.0.33",
64
64
  "diff": "^5.2.0",
65
65
  "jsii": "^5.9.10",
66
- "jsii-build-tools": "^1.120.0",
66
+ "jsii-build-tools": "^1.122.0",
67
67
  "jsii-calc": "^3.20.120",
68
68
  "jsii-rosetta": "~5.9.10",
69
69
  "pyright": "^1.1.403"