jsii-pacmak 1.63.0 → 1.64.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.
@@ -55,6 +55,13 @@ export declare class DotNetGenerator extends Generator {
55
55
  protected onEnumMember(enm: spec.EnumType, member: spec.EnumMember): void;
56
56
  private namespaceFor;
57
57
  private emitMethod;
58
+ /**
59
+ * Emits type checks for values passed for type union parameters.
60
+ *
61
+ * @param parameters the list of parameters received by the function.
62
+ * @param noMangle use parameter names as-is (useful for setters, for example) instead of mangling them.
63
+ */
64
+ private emitUnionParameterValdation;
58
65
  /**
59
66
  * Founds out if a member (property or method) is already defined in one of the base classes
60
67
  *
@@ -4,8 +4,11 @@ exports.DotNetGenerator = void 0;
4
4
  const spec = require("@jsii/spec");
5
5
  const clone = require("clone");
6
6
  const fs = require("fs-extra");
7
+ const http = require("http");
8
+ const https = require("https");
7
9
  const path = require("path");
8
10
  const generator_1 = require("../../generator");
11
+ const logging_1 = require("../../logging");
9
12
  const dotnetdocgenerator_1 = require("./dotnetdocgenerator");
10
13
  const dotnetruntimegenerator_1 = require("./dotnetruntimegenerator");
11
14
  const dotnettyperesolver_1 = require("./dotnettyperesolver");
@@ -48,7 +51,6 @@ class DotNetGenerator extends generator_1.Generator {
48
51
  const tarballFileName = path.basename(tarball);
49
52
  const filegen = new filegenerator_1.FileGenerator(this.assembly, tarballFileName, this.code);
50
53
  filegen.generateAssemblyInfoFile();
51
- filegen.generateProjectFile(this.typeresolver.namespaceDependencies);
52
54
  // Calling super.save() dumps the tarball in the format name@version.jsii.tgz.
53
55
  // This is not in sync with the Old .NET generator where the name is scope-name-version.tgz.
54
56
  // Hence we are saving the files ourselves here:
@@ -59,6 +61,17 @@ class DotNetGenerator extends generator_1.Generator {
59
61
  }
60
62
  await fs.mkdirp(path.join(outdir, packageId));
61
63
  await fs.copyFile(tarball, path.join(outdir, packageId, tarballFileName));
64
+ // Attempt to download the package icon from the configured URL so we can use the non-deprecated PackageIcon
65
+ // attribute. If this fails or is opted out (via $JSII_PACMAK_DOTNET_NO_DOWNLOAD_ICON being set), then only the
66
+ // deprecated PackageIconUrl will be emitted.
67
+ const iconFile = this.assembly.targets?.dotnet?.iconUrl != null &&
68
+ !process.env.JSII_PACMAK_DOTNET_NO_DOWNLOAD_ICON
69
+ ? await tryDownloadResource(this.assembly.targets.dotnet.iconUrl, path.join(outdir, packageId)).catch((err) => {
70
+ (0, logging_1.debug)(`[dotnet] Unable to download package icon, will only use deprecated PackageIconUrl attribute: ${err.cause}`);
71
+ return Promise.resolve(undefined);
72
+ })
73
+ : undefined;
74
+ filegen.generateProjectFile(this.typeresolver.namespaceDependencies, iconFile);
62
75
  // Create an anchor file for the current model
63
76
  this.generateDependencyAnchorFile();
64
77
  if (license) {
@@ -251,10 +264,18 @@ class DotNetGenerator extends generator_1.Generator {
251
264
  // Create the constructors:
252
265
  // Abstract classes have protected constructors.
253
266
  const visibility = cls.abstract ? 'protected' : 'public';
267
+ this.code.openBlock(`${visibility} ${className}(${parametersDefinition}): base(_MakeDeputyProps(${parametersBase}))`);
268
+ this.code.closeBlock();
269
+ this.code.line();
270
+ // This private method is injected so we can validate arguments before deferring to the base constructor, where
271
+ // the instance will be created in the kernel (where it'd fail on a sub-optimal error instead)...
272
+ this.code.line('[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]');
273
+ this.code.openBlock(`private static DeputyProps _MakeDeputyProps(${parametersDefinition})`);
274
+ this.emitUnionParameterValdation(initializer.parameters);
254
275
  const args = parametersBase.length > 0
255
276
  ? `new object?[]{${parametersBase}}`
256
277
  : `System.Array.Empty<object?>()`;
257
- this.code.openBlock(`${visibility} ${className}(${parametersDefinition}): base(new DeputyProps(${args}))`);
278
+ this.code.line(`return new DeputyProps(${args});`);
258
279
  this.code.closeBlock();
259
280
  this.code.line();
260
281
  }
@@ -410,10 +431,108 @@ class DotNetGenerator extends generator_1.Generator {
410
431
  }
411
432
  else {
412
433
  this.code.openBlock(`${access} ${staticKeyWord}${overrideKeyWord}${virtualKeyWord}${signature}`);
434
+ this.emitUnionParameterValdation(method.parameters);
413
435
  this.code.line(this.dotnetRuntimeGenerator.createInvokeMethodIdentifier(method, cls));
414
436
  this.code.closeBlock();
415
437
  }
416
438
  }
439
+ /**
440
+ * Emits type checks for values passed for type union parameters.
441
+ *
442
+ * @param parameters the list of parameters received by the function.
443
+ * @param noMangle use parameter names as-is (useful for setters, for example) instead of mangling them.
444
+ */
445
+ emitUnionParameterValdation(parameters, { noMangle = false } = {}) {
446
+ const unionParameters = parameters?.filter(({ type }) => containsUnionType(type));
447
+ if (unionParameters == null || unionParameters.length === 0) {
448
+ return;
449
+ }
450
+ this.code.openBlock('if (Amazon.JSII.Runtime.Configuration.RuntimeTypeChecking)');
451
+ for (const param of unionParameters) {
452
+ const name = noMangle
453
+ ? param.name
454
+ : this.nameutils.convertParameterName(param.name);
455
+ if (param.optional) {
456
+ this.code.openBlock(`if (${name} != null)`);
457
+ }
458
+ validate.call(this, name, noMangle ? name : `argument {nameof(${name})}`, param.type, noMangle ? name : `{nameof(${name})}`);
459
+ if (param.optional) {
460
+ this.code.closeBlock();
461
+ }
462
+ }
463
+ this.code.closeBlock();
464
+ function validate(value, descr, type, parameterName) {
465
+ if (spec.isUnionTypeReference(type)) {
466
+ validateTypeUnion.call(this, value, descr, type, parameterName);
467
+ }
468
+ else {
469
+ const collectionType = type;
470
+ if (collectionType.collection.kind === spec.CollectionKind.Array) {
471
+ validateArray.call(this, value, descr, collectionType.collection.elementtype, parameterName);
472
+ }
473
+ else if (collectionType.collection.kind === spec.CollectionKind.Map) {
474
+ validateMap.call(this, value, descr, collectionType.collection.elementtype, parameterName);
475
+ }
476
+ else {
477
+ throw new Error(`Unhandled collection kind: ${spec.describeTypeReference(type)}`);
478
+ }
479
+ }
480
+ }
481
+ function validateArray(value, descr, elementType, parameterName) {
482
+ const varName = `__idx_${descr.replace(/[^a-z0-9_]/gi, '_')}`;
483
+ this.code.openBlock(`for (int ${varName} = 0 ; ${varName} < ${value}.Length ; ${varName}++)`);
484
+ validate.call(this, `${value}[${varName}]`, `${descr}[{${varName}}]`, elementType, parameterName);
485
+ this.code.closeBlock();
486
+ }
487
+ function validateMap(value, descr, elementType, parameterName) {
488
+ const varName = `__item_${descr.replace(/[^a-z0-9_]/gi, '_')}`;
489
+ this.code.openBlock(`foreach (var ${varName} in ${value})`);
490
+ validate.call(this, `${varName}.Value`, `${descr}[\\"{${varName}.Key}\\"]`, elementType, parameterName);
491
+ this.code.closeBlock();
492
+ }
493
+ function validateTypeUnion(value, descr, type, parameterName) {
494
+ this.code.indent('if (');
495
+ let emitAnd = false;
496
+ const typeRefs = type.union.types;
497
+ for (const typeRef of typeRefs) {
498
+ const prefix = emitAnd ? '&& ' : '';
499
+ const dotNetType = this.typeresolver.toDotNetType(typeRef);
500
+ // In the case of double, we test for all standard numeric types of .NET (these implicitly convert).
501
+ const test = dotNetType === 'double'
502
+ ? [
503
+ 'byte',
504
+ 'decimal',
505
+ 'double',
506
+ 'float',
507
+ 'int',
508
+ 'long',
509
+ 'sbyte',
510
+ 'short',
511
+ 'uint',
512
+ 'ulong',
513
+ 'ushort',
514
+ ]
515
+ .map((numeric) => `${value} is ${numeric}`)
516
+ .join(' || ')
517
+ : `${value} is ${dotNetType}`;
518
+ this.code.line(`${prefix}!(${test})`);
519
+ emitAnd = true;
520
+ }
521
+ this.code.unindent(')');
522
+ this.code.openBlock('');
523
+ const placeholders = typeRefs
524
+ .map((typeRef) => {
525
+ const typeName = this.typeresolver.toDotNetTypeName(typeRef);
526
+ if (typeName.startsWith('"') && typeName.endsWith('"')) {
527
+ return typeName.slice(1, -1);
528
+ }
529
+ return `{${typeName}}`;
530
+ })
531
+ .join(', ');
532
+ this.code.line(`throw new System.ArgumentException($"Expected ${descr} to be one of: ${placeholders}; received {${value}.GetType().FullName}", $"${parameterName}");`);
533
+ this.code.closeBlock();
534
+ }
535
+ }
417
536
  /**
418
537
  * Founds out if a member (property or method) is already defined in one of the base classes
419
538
  *
@@ -546,7 +665,8 @@ class DotNetGenerator extends generator_1.Generator {
546
665
  : // An abstract class could extend a concrete class... We must walk up the inheritance tree in this case...
547
666
  this.proxyMustUseNewModifier(base)));
548
667
  }
549
- return (type.interfaces?.find((fqn) => this.findType(fqn).assembly === type.assembly) != null);
668
+ return (type.interfaces != null &&
669
+ type.interfaces.some((fqn) => this.findType(fqn).assembly === type.assembly));
550
670
  }
551
671
  /**
552
672
  * Emits an Interface Datatype class
@@ -670,6 +790,17 @@ class DotNetGenerator extends generator_1.Generator {
670
790
  const access = this.renderAccessLevel(prop);
671
791
  const staticKeyWord = prop.static ? 'static ' : '';
672
792
  const propName = this.nameutils.convertPropertyName(prop.name);
793
+ const propTypeFQN = this.typeresolver.toDotNetType(prop.type);
794
+ const isOptional = prop.optional ? '?' : '';
795
+ // We need to use a backing field so we can perform type checking if the property type is a union, and this is a struct.
796
+ const backingFieldName = spec.isInterfaceType(cls) && datatype && containsUnionType(prop.type)
797
+ ? // We down-case the first letter, private fields are conventionally named with a _ prefix, and a camelCase name.
798
+ `_${propName.replace(/[A-Z]/, (c) => c.toLowerCase())}`
799
+ : undefined;
800
+ if (backingFieldName != null) {
801
+ this.code.line(`private ${propTypeFQN}${isOptional} ${backingFieldName};`);
802
+ this.code.line();
803
+ }
673
804
  this.dotnetDocGenerator.emitDocs(prop, {
674
805
  api: 'member',
675
806
  fqn: definingType.fqn,
@@ -701,12 +832,13 @@ class DotNetGenerator extends generator_1.Generator {
701
832
  isVirtualKeyWord = 'virtual ';
702
833
  }
703
834
  }
704
- const propTypeFQN = this.typeresolver.toDotNetType(prop.type);
705
- const isOptional = prop.optional ? '?' : '';
706
835
  const statement = `${access} ${isAbstractKeyword}${isVirtualKeyWord}${staticKeyWord}${isOverrideKeyWord}${propTypeFQN}${isOptional} ${propName}`;
707
836
  this.code.openBlock(statement);
708
837
  // Emit getters
709
- if (datatype || prop.const || prop.abstract) {
838
+ if (backingFieldName != null) {
839
+ this.code.line(`get => ${backingFieldName};`);
840
+ }
841
+ else if (datatype || prop.const || prop.abstract) {
710
842
  this.code.line('get;');
711
843
  }
712
844
  else {
@@ -720,16 +852,34 @@ class DotNetGenerator extends generator_1.Generator {
720
852
  }
721
853
  }
722
854
  // Emit setters
723
- if (datatype || (!prop.immutable && prop.abstract)) {
855
+ if (backingFieldName) {
856
+ this.code.openBlock('set');
857
+ this.emitUnionParameterValdation([
858
+ {
859
+ name: 'value',
860
+ type: prop.type,
861
+ optional: prop.optional,
862
+ },
863
+ ], { noMangle: true });
864
+ this.code.line(`${backingFieldName} = value;`);
865
+ this.code.closeBlock();
866
+ }
867
+ else if (datatype || (!prop.immutable && prop.abstract)) {
724
868
  this.code.line('set;');
725
869
  }
726
870
  else {
727
871
  if (!prop.immutable) {
728
- if (prop.static) {
729
- this.code.line(`set => SetStaticProperty(typeof(${className}), value);`);
872
+ const setCode = prop.static
873
+ ? `SetStaticProperty(typeof(${className}), value);`
874
+ : 'SetInstanceProperty(value);';
875
+ if (containsUnionType(prop.type)) {
876
+ this.code.openBlock('set');
877
+ this.emitUnionParameterValdation([{ name: 'value', optional: prop.optional, type: prop.type }], { noMangle: true });
878
+ this.code.line(setCode);
879
+ this.code.closeBlock();
730
880
  }
731
881
  else {
732
- this.code.line('set => SetInstanceProperty(value);');
882
+ this.code.line(`set => ${setCode}`);
733
883
  }
734
884
  }
735
885
  }
@@ -872,4 +1022,100 @@ class DotNetGenerator extends generator_1.Generator {
872
1022
  }
873
1023
  }
874
1024
  exports.DotNetGenerator = DotNetGenerator;
1025
+ async function tryDownloadResource(urlText, into) {
1026
+ const url = new URL(urlText);
1027
+ let request;
1028
+ switch (url.protocol) {
1029
+ case 'http:':
1030
+ request = http.get;
1031
+ break;
1032
+ case 'https:':
1033
+ request = https.get;
1034
+ break;
1035
+ default:
1036
+ // Unhandled protocol... ignoring
1037
+ (0, logging_1.debug)(`Unsupported URL protocol for resource download: ${url.protocol} (full URL: ${urlText})`);
1038
+ return undefined;
1039
+ }
1040
+ return new Promise((ok, ko) => request(url, (res) => {
1041
+ switch (res.statusCode) {
1042
+ case 200:
1043
+ let fileName = path.basename(url.pathname);
1044
+ // Ensure there is a content-appropriate extension on the result...
1045
+ switch (res.headers['content-type']) {
1046
+ case 'image/gif':
1047
+ if (!fileName.endsWith('.gif')) {
1048
+ fileName = `${fileName}.gif`;
1049
+ }
1050
+ break;
1051
+ case 'image/jpeg':
1052
+ if (!fileName.endsWith('.jpg')) {
1053
+ fileName = `${fileName}.jpg`;
1054
+ }
1055
+ break;
1056
+ case 'image/png':
1057
+ if (!fileName.endsWith('.png')) {
1058
+ fileName = `${fileName}.png`;
1059
+ }
1060
+ break;
1061
+ default:
1062
+ // Nothing to do...
1063
+ }
1064
+ const filePath = path.join('resources', fileName);
1065
+ try {
1066
+ fs.mkdirpSync(path.join(into, 'resources'));
1067
+ }
1068
+ catch (err) {
1069
+ return ko(err);
1070
+ }
1071
+ try {
1072
+ const fd = fs.openSync(path.join(into, filePath), fs.constants.O_CREAT |
1073
+ fs.constants.O_TRUNC |
1074
+ fs.constants.O_WRONLY);
1075
+ res
1076
+ .once('error', (cause) => {
1077
+ try {
1078
+ fs.closeSync(fd);
1079
+ }
1080
+ catch {
1081
+ // IGNORE
1082
+ }
1083
+ ko(cause);
1084
+ })
1085
+ .on('data', (chunk) => {
1086
+ const buff = Buffer.from(chunk);
1087
+ let offset = 0;
1088
+ while (offset < buff.length) {
1089
+ try {
1090
+ offset += fs.writeSync(fd, buff, offset);
1091
+ }
1092
+ catch (err) {
1093
+ return ko(err);
1094
+ }
1095
+ }
1096
+ })
1097
+ .once('close', () => {
1098
+ try {
1099
+ fs.closeSync(fd);
1100
+ ok(filePath);
1101
+ }
1102
+ catch (err) {
1103
+ ko(err);
1104
+ }
1105
+ });
1106
+ }
1107
+ catch (err) {
1108
+ return ko(err);
1109
+ }
1110
+ break;
1111
+ default:
1112
+ ko(new Error(`GET ${urlText} -- HTTP ${res.statusCode ?? 0} (${res.statusMessage ?? 'Unknown Error'})`));
1113
+ }
1114
+ }).once('error', ko));
1115
+ }
1116
+ function containsUnionType(typeRef) {
1117
+ return (spec.isUnionTypeReference(typeRef) ||
1118
+ (spec.isCollectionTypeReference(typeRef) &&
1119
+ containsUnionType(typeRef.collection.elementtype)));
1120
+ }
875
1121
  //# sourceMappingURL=dotnetgenerator.js.map
@@ -27,15 +27,27 @@ export declare class DotNetTypeResolver {
27
27
  * Translates any jsii type to its corresponding .NET type
28
28
  */
29
29
  toDotNetType(typeref: spec.TypeReference): string;
30
+ /**
31
+ * Translates any jsii type to the name of its corresponding .NET type (as a .NET string).
32
+ */
33
+ toDotNetTypeName(typeref: spec.TypeReference): string;
30
34
  resolveNamespace(assm: spec.AssemblyConfiguration, assmName: string, ns: string): string;
31
35
  /**
32
36
  * Translates a primitive in jsii to a native .NET primitive
33
37
  */
34
38
  private toDotNetPrimitive;
39
+ /**
40
+ * Translates a primitive in jsii to the name of a native .NET primitive
41
+ */
42
+ private toDotNetPrimitiveName;
35
43
  /**
36
44
  * Translates a collection in jsii to a native .NET collection
37
45
  */
38
46
  private toDotNetCollection;
47
+ /**
48
+ * Translates a collection in jsii to the name of a native .NET collection
49
+ */
50
+ private toDotNetCollectionName;
39
51
  }
40
52
  export {};
41
53
  //# sourceMappingURL=dotnettyperesolver.d.ts.map
@@ -107,6 +107,24 @@ class DotNetTypeResolver {
107
107
  }
108
108
  throw new Error(`Invalid type reference: ${JSON.stringify(typeref)}`);
109
109
  }
110
+ /**
111
+ * Translates any jsii type to the name of its corresponding .NET type (as a .NET string).
112
+ */
113
+ toDotNetTypeName(typeref) {
114
+ if (spec.isPrimitiveTypeReference(typeref)) {
115
+ return this.toDotNetPrimitiveName(typeref.primitive);
116
+ }
117
+ else if (spec.isCollectionTypeReference(typeref)) {
118
+ return this.toDotNetCollectionName(typeref);
119
+ }
120
+ else if (spec.isNamedTypeReference(typeref)) {
121
+ return `typeof(${this.toNativeFqn(typeref.fqn)}).FullName`;
122
+ }
123
+ else if (typeref.union) {
124
+ return '"object"';
125
+ }
126
+ throw new Error(`Invalid type reference: ${JSON.stringify(typeref)}`);
127
+ }
110
128
  resolveNamespace(assm, assmName, ns) {
111
129
  let resolved = assm.targets?.dotnet?.namespace;
112
130
  if (!resolved) {
@@ -146,6 +164,27 @@ class DotNetTypeResolver {
146
164
  throw new Error(`Unknown primitive type: ${primitive}`);
147
165
  }
148
166
  }
167
+ /**
168
+ * Translates a primitive in jsii to the name of a native .NET primitive
169
+ */
170
+ toDotNetPrimitiveName(primitive) {
171
+ switch (primitive) {
172
+ case spec.PrimitiveType.Boolean:
173
+ return '"bool"';
174
+ case spec.PrimitiveType.Date:
175
+ return 'typeof(System.DateTime).FullName';
176
+ case spec.PrimitiveType.Json:
177
+ return 'typeof(Newtonsoft.Json.Linq.JObject).FullName';
178
+ case spec.PrimitiveType.Number:
179
+ return '"double"';
180
+ case spec.PrimitiveType.String:
181
+ return '"string"';
182
+ case spec.PrimitiveType.Any:
183
+ return '"object"';
184
+ default:
185
+ throw new Error(`Unknown primitive type: ${primitive}`);
186
+ }
187
+ }
149
188
  /**
150
189
  * Translates a collection in jsii to a native .NET collection
151
190
  */
@@ -160,6 +199,21 @@ class DotNetTypeResolver {
160
199
  throw new Error(`Unsupported collection kind: ${ref.collection.kind}`);
161
200
  }
162
201
  }
202
+ /**
203
+ * Translates a collection in jsii to the name of a native .NET collection
204
+ */
205
+ toDotNetCollectionName(ref) {
206
+ switch (ref.collection.kind) {
207
+ case spec.CollectionKind.Array:
208
+ const elementDotNetTypeName = this.toDotNetTypeName(ref.collection.elementtype);
209
+ return `$"{${elementDotNetTypeName}}[]"`;
210
+ case spec.CollectionKind.Map:
211
+ const elementDotNetType = this.toDotNetType(ref.collection.elementtype);
212
+ return `typeof(System.Collections.Generic.IDictionary<string, ${elementDotNetType}>).FullName`;
213
+ default:
214
+ throw new Error(`Unsupported collection kind: ${ref.collection.kind}`);
215
+ }
216
+ }
163
217
  }
164
218
  exports.DotNetTypeResolver = DotNetTypeResolver;
165
219
  //# sourceMappingURL=dotnettyperesolver.js.map
@@ -15,7 +15,7 @@ export declare class FileGenerator {
15
15
  private readonly assemblyInfoNamespaces;
16
16
  private readonly nameutils;
17
17
  constructor(assm: Assembly, tarballFileName: string, code: CodeMaker);
18
- generateProjectFile(dependencies: Map<string, DotNetDependency>): void;
18
+ generateProjectFile(dependencies: Map<string, DotNetDependency>, iconFile?: string): void;
19
19
  generateAssemblyInfoFile(): void;
20
20
  private getDescription;
21
21
  private getDecoratedVersion;
@@ -34,7 +34,7 @@ class FileGenerator {
34
34
  this.code = code;
35
35
  }
36
36
  // Generates the .csproj file
37
- generateProjectFile(dependencies) {
37
+ generateProjectFile(dependencies, iconFile) {
38
38
  const assembly = this.assm;
39
39
  const packageId = assembly.targets.dotnet.packageId;
40
40
  const projectFilePath = path.join(packageId, `${packageId}.csproj`);
@@ -49,6 +49,19 @@ class FileGenerator {
49
49
  const dotnetInfo = assembly.targets.dotnet;
50
50
  propertyGroup.comment('Package Identification');
51
51
  propertyGroup.ele('Description', this.getDescription());
52
+ if (iconFile != null) {
53
+ propertyGroup.ele('PackageIcon', iconFile.split(/[/\\]+/).join('\\'));
54
+ // We also need to actually include the icon in the package
55
+ const noneNode = rootNode.ele('ItemGroup').ele('None');
56
+ noneNode.att('Include', iconFile.split(/[/\\]+/).join('\\'));
57
+ noneNode.att('Pack', 'true');
58
+ noneNode.att('PackagePath', `\\${path
59
+ .dirname(iconFile)
60
+ .split(/[/\\]+/)
61
+ .join('\\')}`);
62
+ }
63
+ // We continue to include the PackageIconUrl even if we put PackageIcon for backwards compatibility, as suggested
64
+ // by https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets#packageicon
52
65
  if (dotnetInfo.iconUrl != null) {
53
66
  propertyGroup.ele('PackageIconUrl', dotnetInfo.iconUrl);
54
67
  }
@@ -1,6 +1,5 @@
1
1
  import { CodeMaker } from 'codemaker';
2
2
  import { Assembly, ModuleLike as JsiiModuleLike, Submodule as JsiiSubmodule } from 'jsii-reflect';
3
- import { SpecialDependencies } from './dependencies';
4
3
  import { EmitContext } from './emit-context';
5
4
  import { GoClass, GoType, GoInterface, GoTypeRef } from './types';
6
5
  export declare const GOMOD_FILENAME = "go.mod";
@@ -21,7 +20,6 @@ export declare abstract class Package {
21
20
  constructor(jsiiModule: JsiiModuleLike, packageName: string, filePath: string, moduleName: string, version: string, root?: Package);
22
21
  get dependencies(): Package[];
23
22
  get goModuleName(): string;
24
- get dependencyImports(): Set<string>;
25
23
  findType(fqn: string): GoType | undefined;
26
24
  emit(context: EmitContext): void;
27
25
  emitSubmodules(context: EmitContext): void;
@@ -41,7 +39,6 @@ export declare abstract class Package {
41
39
  */
42
40
  resolveEmbeddedType(type: GoClass | GoInterface): EmbeddedType;
43
41
  protected emitHeader(code: CodeMaker): void;
44
- protected get specialDependencies(): SpecialDependencies;
45
42
  /**
46
43
  * Emits a `func init() { ... }` in a dedicated file (so we don't have to
47
44
  * worry about what needs to be imported and whatnot). This function is
@@ -28,7 +28,7 @@ class Package {
28
28
  this.version = version;
29
29
  this.embeddedTypes = new Map();
30
30
  this.directory = filePath;
31
- this.file = `${this.directory}/${packageName}.go`;
31
+ this.file = (0, path_1.join)(this.directory, `${packageName}.go`);
32
32
  this.root = root ?? this;
33
33
  this.submodules = this.jsiiModule.submodules.map((sm) => new InternalPackage(this.root, this, sm));
34
34
  this.types = this.jsiiModule.types.map((type) => {
@@ -68,12 +68,6 @@ class Package {
68
68
  const suffix = this.filePath !== '' ? `/${this.filePath}` : ``;
69
69
  return `${prefix}${rootPackageName}${versionSuffix}${suffix}`;
70
70
  }
71
- /*
72
- * The module names of this module's dependencies. Used for import statements.
73
- */
74
- get dependencyImports() {
75
- return new Set(this.dependencies.map((pkg) => pkg.goModuleName));
76
- }
77
71
  /*
78
72
  * Search for a type with a `fqn` within this. Searches all Children modules as well.
79
73
  */
@@ -81,12 +75,7 @@ class Package {
81
75
  return (0, util_1.findTypeInTree)(this, fqn);
82
76
  }
83
77
  emit(context) {
84
- const { code } = context;
85
- code.openFile(this.file);
86
- this.emitHeader(code);
87
- this.emitImports(code);
88
78
  this.emitTypes(context);
89
- code.closeFile(this.file);
90
79
  this.readmeFile?.emit(context);
91
80
  this.emitGoInitFunction(context);
92
81
  this.emitSubmodules(context);
@@ -141,16 +130,6 @@ class Package {
141
130
  code.line(`package ${this.packageName}`);
142
131
  code.line();
143
132
  }
144
- get specialDependencies() {
145
- return this.types
146
- .map((t) => t.specialDependencies)
147
- .reduce((acc, elt) => ({
148
- runtime: acc.runtime || elt.runtime,
149
- init: acc.init || elt.init,
150
- internal: acc.internal || elt.internal,
151
- time: acc.time || elt.time,
152
- }), { runtime: false, init: false, internal: false, time: false });
153
- }
154
133
  /**
155
134
  * Emits a `func init() { ... }` in a dedicated file (so we don't have to
156
135
  * worry about what needs to be imported and whatnot). This function is
@@ -163,7 +142,7 @@ class Package {
163
142
  // form. It also saves us from "imported but unused" errors that would arise
164
143
  // as a consequence.
165
144
  if (this.types.length > 0) {
166
- const initFile = (0, path_1.join)((0, path_1.dirname)(this.file), `${(0, path_1.basename)(this.file, '.go')}.init.go`);
145
+ const initFile = (0, path_1.join)(this.directory, `${this.packageName}.go`);
167
146
  code.openFile(initFile);
168
147
  code.line(`package ${this.packageName}`);
169
148
  code.line();
@@ -177,9 +156,9 @@ class Package {
177
156
  code.closeFile(initFile);
178
157
  }
179
158
  }
180
- emitImports(code) {
159
+ emitImports(code, type) {
181
160
  const toImport = new Array();
182
- const specialDeps = this.specialDependencies;
161
+ const specialDeps = type.specialDependencies;
183
162
  if (specialDeps.time) {
184
163
  toImport.push({ module: 'time' });
185
164
  }
@@ -197,10 +176,10 @@ class Package {
197
176
  module: `${this.goModuleName}/${INTERNAL_PACKAGE_NAME}`,
198
177
  });
199
178
  }
200
- for (const packageName of this.dependencyImports) {
179
+ for (const goModuleName of new Set(type.dependencies.map(({ goModuleName }) => goModuleName))) {
201
180
  // If the module is the same as the current one being written, don't emit an import statement
202
- if (packageName !== this.packageName) {
203
- toImport.push({ module: packageName });
181
+ if (goModuleName !== this.goModuleName) {
182
+ toImport.push({ module: goModuleName });
204
183
  }
205
184
  }
206
185
  importGoModules(code, toImport);
@@ -208,7 +187,12 @@ class Package {
208
187
  }
209
188
  emitTypes(context) {
210
189
  for (const type of this.types) {
190
+ const filePath = (0, path_1.join)(this.directory, `${this.packageName}_${type.name}.go`);
191
+ context.code.openFile(filePath);
192
+ this.emitHeader(context.code);
193
+ this.emitImports(context.code, type);
211
194
  type.emit(context);
195
+ context.code.closeFile(filePath);
212
196
  }
213
197
  }
214
198
  emitInternal(context) {
@@ -56,9 +56,12 @@ class GoTypeRef {
56
56
  if (ref.mapOfType) {
57
57
  return containsDate(ref.mapOfType);
58
58
  }
59
- if (ref.unionOfTypes) {
60
- return ref.unionOfTypes.some(containsDate);
61
- }
59
+ // NOTE: UNION gets represented as interface{} so we don't need to import
60
+ // individual types here...
61
+ //
62
+ // if (ref.unionOfTypes) {
63
+ // return ref.unionOfTypes.some(containsDate);
64
+ // }
62
65
  return false;
63
66
  }
64
67
  }
@@ -8,9 +8,9 @@ import { GoType } from './go-type';
8
8
  import { GoMethod, GoProperty } from './type-member';
9
9
  export declare class GoInterface extends GoType<InterfaceType> {
10
10
  readonly methods: InterfaceMethod[];
11
- readonly reimplementedMethods?: readonly InterfaceMethod[];
11
+ readonly reimplementedMethods: readonly InterfaceMethod[];
12
12
  readonly properties: InterfaceProperty[];
13
- readonly reimplementedProperties?: readonly InterfaceProperty[];
13
+ readonly reimplementedProperties: readonly InterfaceProperty[];
14
14
  constructor(pkg: Package, type: InterfaceType);
15
15
  emit(context: EmitContext): void;
16
16
  emitRegistration(code: CodeMaker): void;
@@ -34,6 +34,10 @@ class GoInterface extends go_type_1.GoType {
34
34
  .map((property) => new InterfaceProperty(this, property))
35
35
  .sort(comparators.byName);
36
36
  }
37
+ else {
38
+ this.reimplementedMethods = [];
39
+ this.reimplementedProperties = [];
40
+ }
37
41
  }
38
42
  emit(context) {
39
43
  this.emitDocs(context);
@@ -67,7 +71,7 @@ class GoInterface extends go_type_1.GoType {
67
71
  for (const method of this.methods) {
68
72
  method.emit(context);
69
73
  }
70
- for (const method of this.reimplementedMethods ?? []) {
74
+ for (const method of this.reimplementedMethods) {
71
75
  method.emit(context);
72
76
  }
73
77
  for (const prop of this.properties) {
@@ -76,7 +80,7 @@ class GoInterface extends go_type_1.GoType {
76
80
  prop.emitSetterProxy(context);
77
81
  }
78
82
  }
79
- for (const prop of this.reimplementedProperties ?? []) {
83
+ for (const prop of this.reimplementedProperties) {
80
84
  prop.emitGetterProxy(context);
81
85
  if (!prop.immutable) {
82
86
  prop.emitSetterProxy(context);
@@ -111,7 +115,9 @@ class GoInterface extends go_type_1.GoType {
111
115
  get specialDependencies() {
112
116
  return [
113
117
  ...this.properties.map((p) => p.specialDependencies),
118
+ ...this.reimplementedProperties.map((p) => p.specialDependencies),
114
119
  ...this.methods.map((m) => m.specialDependencies),
120
+ ...this.reimplementedMethods.map((m) => m.specialDependencies),
115
121
  ].reduce((acc, elt) => ({
116
122
  runtime: acc.runtime || elt.runtime,
117
123
  init: acc.init || elt.init,
@@ -143,8 +149,11 @@ class GoInterface extends go_type_1.GoType {
143
149
  return [
144
150
  ...this.extendsDependencies,
145
151
  ...(0, util_1.getMemberDependencies)(this.methods),
146
- ...(0, util_1.getParamDependencies)(this.methods),
152
+ ...(0, util_1.getMemberDependencies)(this.reimplementedMethods),
147
153
  ...(0, util_1.getMemberDependencies)(this.properties),
154
+ ...(0, util_1.getMemberDependencies)(this.reimplementedProperties),
155
+ ...(0, util_1.getParamDependencies)(this.methods),
156
+ ...(0, util_1.getParamDependencies)(this.reimplementedMethods),
148
157
  ];
149
158
  }
150
159
  }
@@ -5,7 +5,7 @@ export declare function findTypeInTree(module: Package, fqn: string): GoType | u
5
5
  export declare function goPackageNameForAssembly(assembly: Assembly | Submodule): string;
6
6
  export declare function flatMap<T, R>(collection: readonly T[], mapper: (value: T) => readonly R[]): readonly R[];
7
7
  export declare function getMemberDependencies(members: readonly GoTypeMember[]): Package[];
8
- export declare function getParamDependencies(methods: GoMethod[]): Package[];
8
+ export declare function getParamDependencies(methods: readonly GoMethod[]): Package[];
9
9
  export declare function substituteReservedWords(name: string): string;
10
10
  /**
11
11
  * Computes a safe tarball name for the provided assembly.
@@ -35,21 +35,11 @@ exports.flatMap = flatMap;
35
35
  * Return module dependencies of a class or interface members
36
36
  */
37
37
  function getMemberDependencies(members) {
38
- const deps = new Array();
39
- for (const member of members) {
40
- deps.push(...(member.reference?.dependencies ?? []));
41
- }
42
- return deps;
38
+ return members.flatMap((member) => member.reference?.dependencies ?? []);
43
39
  }
44
40
  exports.getMemberDependencies = getMemberDependencies;
45
41
  function getParamDependencies(methods) {
46
- const dependencies = [];
47
- for (const method of methods) {
48
- for (const param of method.parameters) {
49
- dependencies.push(...(param.reference?.dependencies ?? []));
50
- }
51
- }
52
- return dependencies;
42
+ return methods.flatMap(({ parameters }) => parameters.flatMap((param) => param.reference?.dependencies ?? []));
53
43
  }
54
44
  exports.getParamDependencies = getParamDependencies;
55
45
  const RESERVED_WORDS = {
@@ -1,4 +1,4 @@
1
- import { Assembly, OptionalValue, TypeReference } from '@jsii/spec';
1
+ import { Assembly, OptionalValue, TypeReference, Type } from '@jsii/spec';
2
2
  export interface TypeName {
3
3
  pythonType(context: NamingContext): string;
4
4
  requiredImports(context: NamingContext): PythonImports;
@@ -17,6 +17,8 @@ export interface PythonImports {
17
17
  export interface NamingContext {
18
18
  /** The assembly in which the PythonType is expressed. */
19
19
  readonly assembly: Assembly;
20
+ /** A resolver to obtain complete information about a type. */
21
+ readonly typeResolver: (fqn: string) => Type;
20
22
  /** The submodule of the assembly in which the PythonType is expressed (could be the module root) */
21
23
  readonly submodule: string;
22
24
  /**
@@ -68,4 +70,14 @@ export declare function toPythonFqn(fqn: string, rootAssm: Assembly): {
68
70
  packageName: string;
69
71
  pythonFqn: string;
70
72
  };
73
+ /**
74
+ * Computes the nesting-qualified name of a type.
75
+ *
76
+ * @param fqn the fully qualified jsii name of the type.
77
+ * @param rootAssm the root assembly for the project.
78
+ *
79
+ * @returns the nesting-qualified python type name (the name of the class,
80
+ * qualified with all nesting parent classes).
81
+ */
82
+ export declare function toPythonFullName(fqn: string, rootAssm: Assembly): string;
71
83
  //# sourceMappingURL=type-name.d.ts.map
@@ -12,7 +12,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  };
13
13
  var _Dict_element, _List_element, _Optional_wrapped, _Primitive_pythonType, _Union_options, _UserType_fqn;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.toPythonFqn = exports.mergePythonImports = exports.toPackageName = exports.toTypeName = void 0;
15
+ exports.toPythonFullName = exports.toPythonFqn = exports.mergePythonImports = exports.toPackageName = exports.toTypeName = void 0;
16
16
  const spec_1 = require("@jsii/spec");
17
17
  const codemaker_1 = require("codemaker");
18
18
  const crypto_1 = require("crypto");
@@ -193,11 +193,18 @@ class UserType {
193
193
  }
194
194
  return { [requiredImport.sourcePackage]: new Set([requiredImport.item]) };
195
195
  }
196
- resolve({ assembly, emittedTypes, submodule, surroundingTypeFqns, typeAnnotation = true, }) {
196
+ resolve({ assembly, emittedTypes, submodule, surroundingTypeFqns, typeAnnotation = true, parameterType, typeResolver, }) {
197
197
  const { assemblyName, packageName, pythonFqn } = toPythonFqn(__classPrivateFieldGet(this, _UserType_fqn, "f"), assembly);
198
+ // If this is a type annotation for a parameter, allow dicts to be passed where structs are expected.
199
+ const type = typeResolver(__classPrivateFieldGet(this, _UserType_fqn, "f"));
200
+ const isStruct = (0, spec_1.isInterfaceType)(type) && !!type.datatype;
201
+ const wrapType = typeAnnotation && parameterType && isStruct
202
+ ? (pyType) => `typing.Union[${pyType}, typing.Dict[str, typing.Any]]`
203
+ : (pyType) => pyType;
198
204
  if (assemblyName !== assembly.name) {
199
205
  return {
200
- pythonType: pythonFqn,
206
+ // If it's a struct, then we allow passing as a dict, too...
207
+ pythonType: wrapType(pythonFqn),
201
208
  requiredImport: {
202
209
  sourcePackage: packageName,
203
210
  item: '',
@@ -219,7 +226,7 @@ class UserType {
219
226
  (!emittedTypes.has(__classPrivateFieldGet(this, _UserType_fqn, "f")) || nestingParent != null)) {
220
227
  // Possibly a forward reference, outputting the stringifierd python FQN
221
228
  return {
222
- pythonType: JSON.stringify(pythonFqn.substring(submodulePythonName.length + 1)),
229
+ pythonType: wrapType(JSON.stringify(pythonFqn.substring(submodulePythonName.length + 1))),
223
230
  };
224
231
  }
225
232
  if (!typeAnnotation && nestingParent) {
@@ -230,7 +237,7 @@ class UserType {
230
237
  }
231
238
  // We'll just make a module-qualified reference at this point.
232
239
  return {
233
- pythonType: pythonFqn.substring(submodulePythonName.length + 1),
240
+ pythonType: wrapType(pythonFqn.substring(submodulePythonName.length + 1)),
234
241
  };
235
242
  }
236
243
  const [toImport, ...nested] = pythonFqn
@@ -262,6 +269,20 @@ function toPythonFqn(fqn, rootAssm) {
262
269
  return { assemblyName, packageName, pythonFqn: fqnParts.join('.') };
263
270
  }
264
271
  exports.toPythonFqn = toPythonFqn;
272
+ /**
273
+ * Computes the nesting-qualified name of a type.
274
+ *
275
+ * @param fqn the fully qualified jsii name of the type.
276
+ * @param rootAssm the root assembly for the project.
277
+ *
278
+ * @returns the nesting-qualified python type name (the name of the class,
279
+ * qualified with all nesting parent classes).
280
+ */
281
+ function toPythonFullName(fqn, rootAssm) {
282
+ const { packageName, pythonFqn } = toPythonFqn(fqn, rootAssm);
283
+ return pythonFqn.slice(packageName.length + 1);
284
+ }
285
+ exports.toPythonFullName = toPythonFullName;
265
286
  /**
266
287
  * Computes the python relative import path from `fromModule` to `toModule`.
267
288
  *
@@ -295,7 +295,7 @@ class BasePythonClassType {
295
295
  }
296
296
  }
297
297
  class BaseMethod {
298
- constructor(generator, pythonName, jsName, parameters, returns, docs, isStatic, pythonParent, opts) {
298
+ constructor(generator, pythonName, jsName, parameters, returns, docs, isStatic, opts) {
299
299
  this.generator = generator;
300
300
  this.pythonName = pythonName;
301
301
  this.jsName = jsName;
@@ -303,7 +303,6 @@ class BaseMethod {
303
303
  this.returns = returns;
304
304
  this.docs = docs;
305
305
  this.isStatic = isStatic;
306
- this.pythonParent = pythonParent;
307
306
  this.classAsFirstParameter = false;
308
307
  this.returnFromJSIIMethod = true;
309
308
  this.shouldEmitBody = true;
@@ -420,7 +419,6 @@ class BaseMethod {
420
419
  }
421
420
  const decorators = new Array();
422
421
  if (this.jsName !== undefined) {
423
- // "# type: ignore[misc]" needed because mypy does not know how to check decorated declarations
424
422
  decorators.push(`@jsii.member(jsii_name="${this.jsName}")`);
425
423
  }
426
424
  if (this.decorator !== undefined) {
@@ -430,22 +428,19 @@ class BaseMethod {
430
428
  decorators.push('@abc.abstractmethod');
431
429
  }
432
430
  if (decorators.length > 0) {
433
- // "# type: ignore[misc]" needed because mypy does not know how to check decorated declarations
434
- for (const decorator of decorators
435
- .join(' # type: ignore[misc]\n')
436
- .split('\n')) {
431
+ for (const decorator of decorators) {
437
432
  code.line(decorator);
438
433
  }
439
434
  }
440
435
  pythonParams.unshift(slugifyAsNeeded(this.implicitParameter, pythonParams.map((param) => param.split(':')[0].trim())));
441
- openSignature(code, 'def', this.pythonName, pythonParams, false, returnType);
436
+ openSignature(code, 'def', this.pythonName, pythonParams, returnType);
442
437
  this.generator.emitDocString(code, this.apiLocation, this.docs, {
443
438
  arguments: documentableArgs,
444
439
  documentableItem: `method-${this.pythonName}`,
445
440
  });
446
441
  if ((this.shouldEmitBody || forceEmitBody) &&
447
442
  (!renderAbstract || !this.abstract)) {
448
- emitParameterTypeChecks(code, pythonParams.slice(1), `${this.pythonParent.pythonName}.${this.pythonName}`);
443
+ emitParameterTypeChecks(code, pythonParams.slice(1), `${(0, type_name_1.toPythonFullName)(this.parent.fqn, context.assembly)}.${this.pythonName}`);
449
444
  }
450
445
  this.emitBody(code, context, renderAbstract, forceEmitBody, liftedPropNames, pythonParams[0], returnType);
451
446
  code.closeBlock();
@@ -546,13 +541,12 @@ class BaseMethod {
546
541
  }
547
542
  }
548
543
  class BaseProperty {
549
- constructor(generator, pythonName, jsName, type, docs, pythonParent, opts) {
544
+ constructor(generator, pythonName, jsName, type, docs, opts) {
550
545
  this.generator = generator;
551
546
  this.pythonName = pythonName;
552
547
  this.jsName = jsName;
553
548
  this.type = type;
554
549
  this.docs = docs;
555
- this.pythonParent = pythonParent;
556
550
  this.shouldEmitBody = true;
557
551
  const { abstract = false, immutable = false, isStatic = false } = opts;
558
552
  this.abstract = abstract;
@@ -569,13 +563,17 @@ class BaseProperty {
569
563
  emit(code, context, opts) {
570
564
  const { renderAbstract = true, forceEmitBody = false } = opts ?? {};
571
565
  const pythonType = (0, type_name_1.toTypeName)(this.type).pythonType(context);
572
- // "# type: ignore[misc]" is needed because mypy cannot check decorated things
573
- code.line(`@${this.decorator} # type: ignore[misc]`);
566
+ code.line(`@${this.decorator}`);
574
567
  code.line(`@jsii.member(jsii_name="${this.jsName}")`);
575
568
  if (renderAbstract && this.abstract) {
576
569
  code.line('@abc.abstractmethod');
577
570
  }
578
- openSignature(code, 'def', this.pythonName, [this.implicitParameter], true, pythonType);
571
+ openSignature(code, 'def', this.pythonName, [this.implicitParameter], pythonType,
572
+ // PyRight and MyPY both special-case @property, but not custom implementations such as our @classproperty...
573
+ // MyPY reports on the re-declaration, but PyRight reports on the initial declaration (duh!)
574
+ this.isStatic && !this.immutable
575
+ ? 'pyright: ignore [reportGeneralTypeIssues]'
576
+ : undefined);
579
577
  this.generator.emitDocString(code, this.apiLocation, this.docs, {
580
578
  documentableItem: `prop-${this.pythonName}`,
581
579
  });
@@ -590,18 +588,20 @@ class BaseProperty {
590
588
  code.closeBlock();
591
589
  if (!this.immutable) {
592
590
  code.line();
591
+ // PyRight and MyPY both special-case @property, but not custom implementations such as our @classproperty...
592
+ // MyPY reports on the re-declaration, but PyRight reports on the initial declaration (duh!)
593
593
  code.line(`@${this.pythonName}.setter${this.isStatic ? ' # type: ignore[no-redef]' : ''}`);
594
594
  if (renderAbstract && this.abstract) {
595
595
  code.line('@abc.abstractmethod');
596
596
  }
597
- openSignature(code, 'def', this.pythonName, [this.implicitParameter, `value: ${pythonType}`], false, 'None');
597
+ openSignature(code, 'def', this.pythonName, [this.implicitParameter, `value: ${pythonType}`], 'None');
598
598
  if ((this.shouldEmitBody || forceEmitBody) &&
599
599
  (!renderAbstract || !this.abstract)) {
600
600
  emitParameterTypeChecks(code, [`value: ${pythonType}`],
601
601
  // In order to get a property accessor, we must resort to getting the
602
602
  // attribute on the type, instead of the value (where the getter would
603
603
  // be implicitly invoked for us...)
604
- `getattr(${this.pythonParent.pythonName}, ${JSON.stringify(this.pythonName)}).fset`);
604
+ `getattr(${(0, type_name_1.toPythonFullName)(this.parent.fqn, context.assembly)}, ${JSON.stringify(this.pythonName)}).fset`);
605
605
  code.line(`jsii.${this.jsiiSetMethod}(${this.implicitParameter}, "${this.jsName}", value)`);
606
606
  }
607
607
  else {
@@ -734,20 +734,17 @@ class Struct extends BasePythonClassType {
734
734
  const constructorArguments = kwargs.length > 0
735
735
  ? [implicitParameter, '*', ...kwargs]
736
736
  : [implicitParameter];
737
- openSignature(code, 'def', '__init__', constructorArguments, false, 'None');
737
+ openSignature(code, 'def', '__init__', constructorArguments, 'None');
738
738
  this.emitConstructorDocstring(code);
739
739
  // Re-type struct arguments that were passed as "dict". Do this before validating argument types...
740
740
  for (const member of members.filter((m) => m.isStruct(this.generator))) {
741
741
  // Note that "None" is NOT an instance of dict (that's convenient!)
742
- const typeName = (0, type_name_1.toTypeName)(member.type.type).pythonType({
743
- ...context,
744
- typeAnnotation: false,
745
- });
742
+ const typeName = (0, type_name_1.toPythonFullName)(member.type.type.fqn, context.assembly);
746
743
  code.openBlock(`if isinstance(${member.pythonName}, dict)`);
747
744
  code.line(`${member.pythonName} = ${typeName}(**${member.pythonName})`);
748
745
  code.closeBlock();
749
746
  }
750
- emitParameterTypeChecks(code, kwargs, `${this.pythonName}.__init__`);
747
+ emitParameterTypeChecks(code, kwargs, `${(0, type_name_1.toPythonFullName)(this.spec.fqn, context.assembly)}.__init__`);
751
748
  // Required properties, those will always be put into the dict
752
749
  assignDictionary(code, `${implicitParameter}._values: typing.Dict[str, typing.Any]`, members
753
750
  .filter((m) => !m.optional)
@@ -774,7 +771,7 @@ class Struct extends BasePythonClassType {
774
771
  emitGetter(member, code, context) {
775
772
  const pythonType = member.typeAnnotation(context);
776
773
  code.line('@builtins.property');
777
- openSignature(code, 'def', member.pythonName, ['self'], true, pythonType);
774
+ openSignature(code, 'def', member.pythonName, ['self'], pythonType);
778
775
  member.emitDocString(code);
779
776
  // NOTE: No parameter to validate here, this is a getter.
780
777
  code.line(`result = self._values.get(${JSON.stringify(member.pythonName)})`);
@@ -1485,6 +1482,12 @@ class Package {
1485
1482
  .reduce((buildTools, entry) => (entry ? [...buildTools, entry] : buildTools), new Array());
1486
1483
  code.line(`requires = [${buildTools.map((x) => `"${x}"`).join(', ')}]`);
1487
1484
  code.line('build-backend = "setuptools.build_meta"');
1485
+ code.line();
1486
+ code.line('[tool.pyright]');
1487
+ code.line('defineConstant = { DEBUG = true }');
1488
+ code.line('pythonVersion = "3.7"');
1489
+ code.line('pythonPlatform = "All"');
1490
+ code.line('reportSelfClsParameterName = false');
1488
1491
  code.closeFile('pyproject.toml');
1489
1492
  // We also need to write out a MANIFEST.in to ensure that all of our required
1490
1493
  // files are included.
@@ -1726,6 +1729,7 @@ class PythonGenerator extends generator_1.Generator {
1726
1729
  emittedTypes: new Set(),
1727
1730
  resolver,
1728
1731
  submodule: assm.name,
1732
+ typeResolver: (fqn) => resolver.dereference(fqn),
1729
1733
  });
1730
1734
  }
1731
1735
  /**
@@ -1773,7 +1777,7 @@ class PythonGenerator extends generator_1.Generator {
1773
1777
  if (cls.initializer !== undefined) {
1774
1778
  const { parameters = [] } = cls.initializer;
1775
1779
  klass.addMember(new Initializer(this, '__init__', undefined, parameters, undefined, cls.initializer.docs, false, // Never static
1776
- klass, { liftedProp: this.getliftedProp(cls.initializer), parent: cls }));
1780
+ { liftedProp: this.getliftedProp(cls.initializer), parent: cls }));
1777
1781
  }
1778
1782
  this.addPythonType(klass);
1779
1783
  }
@@ -1781,7 +1785,7 @@ class PythonGenerator extends generator_1.Generator {
1781
1785
  const { parameters = [] } = method;
1782
1786
  const klass = this.getPythonType(cls.fqn);
1783
1787
  klass.addMember(new StaticMethod(this, toPythonMethodName(method.name), method.name, parameters, method.returns, method.docs, true, // Always static
1784
- klass, {
1788
+ {
1785
1789
  abstract: method.abstract,
1786
1790
  liftedProp: this.getliftedProp(method),
1787
1791
  parent: cls,
@@ -1789,7 +1793,7 @@ class PythonGenerator extends generator_1.Generator {
1789
1793
  }
1790
1794
  onStaticProperty(cls, prop) {
1791
1795
  const klass = this.getPythonType(cls.fqn);
1792
- klass.addMember(new StaticProperty(this, toPythonPropertyName(prop.name, prop.const), prop.name, prop, prop.docs, klass, {
1796
+ klass.addMember(new StaticProperty(this, toPythonPropertyName(prop.name, prop.const), prop.name, prop, prop.docs, {
1793
1797
  abstract: prop.abstract,
1794
1798
  immutable: prop.immutable,
1795
1799
  isStatic: prop.static,
@@ -1800,14 +1804,14 @@ class PythonGenerator extends generator_1.Generator {
1800
1804
  const { parameters = [] } = method;
1801
1805
  const klass = this.getPythonType(cls.fqn);
1802
1806
  if (method.async) {
1803
- klass.addMember(new AsyncMethod(this, toPythonMethodName(method.name, method.protected), method.name, parameters, method.returns, method.docs, !!method.static, klass, {
1807
+ klass.addMember(new AsyncMethod(this, toPythonMethodName(method.name, method.protected), method.name, parameters, method.returns, method.docs, !!method.static, {
1804
1808
  abstract: method.abstract,
1805
1809
  liftedProp: this.getliftedProp(method),
1806
1810
  parent: cls,
1807
1811
  }));
1808
1812
  }
1809
1813
  else {
1810
- klass.addMember(new Method(this, toPythonMethodName(method.name, method.protected), method.name, parameters, method.returns, method.docs, !!method.static, klass, {
1814
+ klass.addMember(new Method(this, toPythonMethodName(method.name, method.protected), method.name, parameters, method.returns, method.docs, !!method.static, {
1811
1815
  abstract: method.abstract,
1812
1816
  liftedProp: this.getliftedProp(method),
1813
1817
  parent: cls,
@@ -1816,7 +1820,7 @@ class PythonGenerator extends generator_1.Generator {
1816
1820
  }
1817
1821
  onProperty(cls, prop) {
1818
1822
  const klass = this.getPythonType(cls.fqn);
1819
- klass.addMember(new Property(this, toPythonPropertyName(prop.name, prop.const, prop.protected), prop.name, prop, prop.docs, klass, {
1823
+ klass.addMember(new Property(this, toPythonPropertyName(prop.name, prop.const, prop.protected), prop.name, prop, prop.docs, {
1820
1824
  abstract: prop.abstract,
1821
1825
  immutable: prop.immutable,
1822
1826
  isStatic: prop.static,
@@ -1842,7 +1846,7 @@ class PythonGenerator extends generator_1.Generator {
1842
1846
  onInterfaceMethod(ifc, method) {
1843
1847
  const { parameters = [] } = method;
1844
1848
  const klass = this.getPythonType(ifc.fqn);
1845
- klass.addMember(new InterfaceMethod(this, toPythonMethodName(method.name, method.protected), method.name, parameters, method.returns, method.docs, !!method.static, klass, { liftedProp: this.getliftedProp(method), parent: ifc }));
1849
+ klass.addMember(new InterfaceMethod(this, toPythonMethodName(method.name, method.protected), method.name, parameters, method.returns, method.docs, !!method.static, { liftedProp: this.getliftedProp(method), parent: ifc }));
1846
1850
  }
1847
1851
  onInterfaceProperty(ifc, prop) {
1848
1852
  let ifaceProperty;
@@ -1851,7 +1855,7 @@ class PythonGenerator extends generator_1.Generator {
1851
1855
  ifaceProperty = new StructField(this, prop, ifc);
1852
1856
  }
1853
1857
  else {
1854
- ifaceProperty = new InterfaceProperty(this, toPythonPropertyName(prop.name, prop.const, prop.protected), prop.name, prop, prop.docs, klass, { immutable: prop.immutable, isStatic: prop.static, parent: ifc });
1858
+ ifaceProperty = new InterfaceProperty(this, toPythonPropertyName(prop.name, prop.const, prop.protected), prop.name, prop, prop.docs, { immutable: prop.immutable, isStatic: prop.static, parent: ifc });
1855
1859
  }
1856
1860
  klass.addMember(ifaceProperty);
1857
1861
  }
@@ -1973,7 +1977,7 @@ function slugifyAsNeeded(name, inUse) {
1973
1977
  //
1974
1978
  // @see https://black.readthedocs.io/en/stable/the_black_code_style.html
1975
1979
  const TARGET_LINE_LENGTH = 88;
1976
- function openSignature(code, keyword, name, params, trailingComma = false, returnType) {
1980
+ function openSignature(code, keyword, name, params, returnType, lineComment) {
1977
1981
  const prefix = `${keyword} ${name}`;
1978
1982
  const suffix = returnType ? ` -> ${returnType}` : '';
1979
1983
  if (params.length === 0) {
@@ -1982,8 +1986,8 @@ function openSignature(code, keyword, name, params, trailingComma = false, retur
1982
1986
  }
1983
1987
  const join = ', ';
1984
1988
  const { elementsSize, joinSize } = totalSizeOf(params, join);
1985
- const hasComments = !params.some((param) => /# .+$/.exec(param));
1986
- if (hasComments &&
1989
+ const hasComments = params.some((param) => /#\s*.+$/.exec(param) != null);
1990
+ if (!hasComments &&
1987
1991
  TARGET_LINE_LENGTH >
1988
1992
  code.currentIndentLength +
1989
1993
  prefix.length +
@@ -1991,25 +1995,15 @@ function openSignature(code, keyword, name, params, trailingComma = false, retur
1991
1995
  joinSize +
1992
1996
  suffix.length +
1993
1997
  2) {
1994
- code.openBlock(`${prefix}(${params.join(join)})${suffix}`);
1998
+ code.indent(`${prefix}(${params.join(join)})${suffix}:${lineComment ? ` # ${lineComment}` : ''}`);
1995
1999
  return;
1996
2000
  }
1997
2001
  code.indent(`${prefix}(`);
1998
- if (!hasComments &&
1999
- TARGET_LINE_LENGTH >
2000
- code.currentIndentLength +
2001
- elementsSize +
2002
- joinSize +
2003
- (trailingComma ? 1 : 0)) {
2004
- code.line(`${params.join(join)}${trailingComma ? ',' : ''}`);
2005
- }
2006
- else {
2007
- for (const param of params) {
2008
- code.line(param.replace(/(\s*# .+)?$/, ',$1'));
2009
- }
2002
+ for (const param of params) {
2003
+ code.line(param.replace(/(\s*# .+)?$/, ',$1'));
2010
2004
  }
2011
2005
  code.unindent(false);
2012
- code.openBlock(`)${suffix}`);
2006
+ code.indent(`)${suffix}:${lineComment ? ` # ${lineComment}` : ''}`);
2013
2007
  }
2014
2008
  /**
2015
2009
  * Emits runtime type checking code for parameters.
@@ -2020,7 +2014,7 @@ function openSignature(code, keyword, name, params, trailingComma = false, retur
2020
2014
  */
2021
2015
  function emitParameterTypeChecks(code, params, typedEntity) {
2022
2016
  const paramInfo = params.map((param) => {
2023
- const [name] = param.split(/\s*[:=]\s*/, 1);
2017
+ const [name] = param.split(/\s*[:=#]\s*/, 1);
2024
2018
  if (name === '*') {
2025
2019
  return { kwargsMark: true };
2026
2020
  }
@@ -2045,11 +2039,14 @@ function emitParameterTypeChecks(code, params, typedEntity) {
2045
2039
  openedBlock = true;
2046
2040
  }
2047
2041
  let expectedType = `${typesVar}[${JSON.stringify(name)}]`;
2042
+ let comment = '';
2048
2043
  if (is_rest) {
2049
2044
  // This is a vararg, so the value will appear as a tuple.
2050
2045
  expectedType = `typing.Tuple[${expectedType}, ...]`;
2046
+ // Need to ignore reportGeneralTypeIssues because pyright incorrectly parses that as a type annotation 😒
2047
+ comment = ' # pyright: ignore [reportGeneralTypeIssues]';
2051
2048
  }
2052
- code.line(`check_type(argname=${JSON.stringify(`argument ${name}`)}, value=${name}, expected_type=${expectedType})`);
2049
+ code.line(`check_type(argname=${JSON.stringify(`argument ${name}`)}, value=${name}, expected_type=${expectedType})${comment}`);
2053
2050
  }
2054
2051
  if (openedBlock) {
2055
2052
  code.closeBlock();
package/lib/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** The short version number for this JSII compiler (e.g: `X.Y.Z`) */
2
- export declare const VERSION = "1.63.0";
2
+ export declare const VERSION = "1.64.0";
3
3
  /** The qualified version number for this JSII compiler (e.g: `X.Y.Z (build #######)`) */
4
- export declare const VERSION_DESC = "1.63.0 (build 7c24e36)";
4
+ export declare const VERSION_DESC = "1.64.0 (build 4c1eae8)";
5
5
  //# sourceMappingURL=version.d.ts.map
package/lib/version.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
- // Generated at 2022-07-26T16:29:28Z by generate.sh
2
+ // Generated at 2022-08-12T17:08:11Z 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 compiler (e.g: `X.Y.Z`) */
6
- exports.VERSION = '1.63.0';
6
+ exports.VERSION = '1.64.0';
7
7
  /** The qualified version number for this JSII compiler (e.g: `X.Y.Z (build #######)`) */
8
- exports.VERSION_DESC = '1.63.0 (build 7c24e36)';
8
+ exports.VERSION_DESC = '1.64.0 (build 4c1eae8)';
9
9
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsii-pacmak",
3
- "version": "1.63.0",
3
+ "version": "1.64.0",
4
4
  "description": "A code generation framework for jsii backend languages",
5
5
  "license": "Apache-2.0",
6
6
  "author": {
@@ -37,32 +37,33 @@
37
37
  "package": "package-js"
38
38
  },
39
39
  "dependencies": {
40
- "@jsii/check-node": "1.63.0",
41
- "@jsii/spec": "^1.63.0",
40
+ "@jsii/check-node": "1.64.0",
41
+ "@jsii/spec": "^1.64.0",
42
42
  "clone": "^2.1.2",
43
- "codemaker": "^1.63.0",
43
+ "codemaker": "^1.64.0",
44
44
  "commonmark": "^0.30.0",
45
45
  "escape-string-regexp": "^4.0.0",
46
46
  "fs-extra": "^10.1.0",
47
- "jsii-reflect": "^1.63.0",
48
- "jsii-rosetta": "^1.63.0",
47
+ "jsii-reflect": "^1.64.0",
48
+ "jsii-rosetta": "^1.64.0",
49
49
  "semver": "^7.3.7",
50
50
  "spdx-license-list": "^6.6.0",
51
51
  "xmlbuilder": "^15.1.1",
52
52
  "yargs": "^16.2.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@jsii/dotnet-runtime": "^1.63.0",
56
- "@jsii/java-runtime": "^1.63.0",
57
- "@jsii/go-runtime": "^1.63.0",
58
- "@scope/jsii-calc-lib": "^1.63.0",
55
+ "@jsii/dotnet-runtime": "^1.64.0",
56
+ "@jsii/java-runtime": "^1.64.0",
57
+ "@jsii/go-runtime": "^1.64.0",
58
+ "@scope/jsii-calc-lib": "^1.64.0",
59
59
  "@types/clone": "^2.1.1",
60
60
  "@types/commonmark": "^0.27.5",
61
61
  "@types/fs-extra": "^9.0.13",
62
62
  "@types/semver": "^7.3.10",
63
- "jsii": "^1.63.0",
64
- "jsii-build-tools": "^1.63.0",
65
- "jsii-calc": "^3.20.120"
63
+ "jsii": "^1.64.0",
64
+ "jsii-build-tools": "^1.64.0",
65
+ "jsii-calc": "^3.20.120",
66
+ "pyright": "^1.1.266"
66
67
  },
67
68
  "keywords": [
68
69
  "jsii",