jsii-pacmak 1.113.0 → 1.115.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/bin/jsii-pacmak.js +1 -1
  2. package/lib/index.js +2 -0
  3. package/lib/npm-modules.d.ts +1 -1
  4. package/lib/npm-modules.js +1 -3
  5. package/lib/packaging.d.ts +1 -5
  6. package/lib/packaging.js +12 -6
  7. package/lib/rosetta-assembly.d.ts +20 -0
  8. package/lib/rosetta-assembly.js +29 -0
  9. package/lib/targets/dotnet/dotnetdocgenerator.d.ts +4 -1
  10. package/lib/targets/dotnet/dotnetdocgenerator.js +69 -13
  11. package/lib/targets/dotnet/dotnetgenerator.d.ts +0 -4
  12. package/lib/targets/dotnet/dotnetgenerator.js +24 -14
  13. package/lib/targets/dotnet/dotnetruntimegenerator.js +11 -2
  14. package/lib/targets/dotnet/dotnettyperesolver.d.ts +13 -0
  15. package/lib/targets/dotnet/dotnettyperesolver.js +42 -4
  16. package/lib/targets/dotnet.d.ts +1 -1
  17. package/lib/targets/dotnet.js +6 -4
  18. package/lib/targets/go/runtime/runtime-type-checking.js +1 -0
  19. package/lib/targets/go/types/go-type-reference.d.ts +3 -0
  20. package/lib/targets/go/types/go-type-reference.js +20 -0
  21. package/lib/targets/go.js +1 -1
  22. package/lib/targets/java.d.ts +28 -4
  23. package/lib/targets/java.js +411 -219
  24. package/lib/targets/python/requirements-dev.txt +2 -2
  25. package/lib/targets/python/type-name.d.ts +18 -0
  26. package/lib/targets/python/type-name.js +59 -1
  27. package/lib/targets/python.d.ts +2 -1
  28. package/lib/targets/python.js +53 -18
  29. package/lib/targets/type-literals.d.ts +22 -0
  30. package/lib/targets/type-literals.js +39 -0
  31. package/lib/type-utils.d.ts +3 -0
  32. package/lib/type-utils.js +10 -0
  33. package/lib/type-visitor.d.ts +19 -0
  34. package/lib/type-visitor.js +47 -0
  35. package/lib/util.d.ts +18 -5
  36. package/lib/util.js +80 -13
  37. package/lib/version.d.ts +1 -1
  38. package/lib/version.js +3 -3
  39. package/package.json +15 -14
@@ -172,7 +172,7 @@ const version_1 = require("../lib/version");
172
172
  force: argv.force,
173
173
  forceSubdirectory: argv['force-subdirectory'],
174
174
  forceTarget: argv['force-target'],
175
- inputDirectories: argv.PROJECTS,
175
+ inputDirectories: argv.PROJECTS, // type cast due to bug https://github.com/yargs/yargs/issues/2292
176
176
  outputDirectory: argv.outdir,
177
177
  parallel: argv.parallel,
178
178
  recurse: argv.recurse,
package/lib/index.js CHANGED
@@ -8,6 +8,7 @@ const path_1 = require("path");
8
8
  const process_1 = require("process");
9
9
  const logging = require("./logging");
10
10
  const npm_modules_1 = require("./npm-modules");
11
+ const rosetta_assembly_1 = require("./rosetta-assembly");
11
12
  const targets_1 = require("./targets");
12
13
  Object.defineProperty(exports, "TargetName", { enumerable: true, get: function () { return targets_1.TargetName; } });
13
14
  const timer_1 = require("./timer");
@@ -55,6 +56,7 @@ async function pacmak({ argv = {}, clean = true, codeOnly = false, fingerprint =
55
56
  const system = new jsii_reflect_1.TypeSystem();
56
57
  return Promise.all(modulesToPackageFlat.map(async (m) => {
57
58
  await m.load(system, validateAssemblies);
59
+ (0, rosetta_assembly_1.assertSpecIsRosettaCompatible)(m.assembly.spec);
58
60
  return rosetta.addAssembly(m.assembly.spec, m.moduleDirectory);
59
61
  }));
60
62
  });
@@ -1,7 +1,7 @@
1
1
  import { JsiiModule } from './packaging';
2
2
  import { Toposorted } from './toposort';
3
3
  /**
4
- * Find all modules that need to be packagerd
4
+ * Find all modules that need to be packaged
5
5
  *
6
6
  * If the input list is empty, include the current directory.
7
7
  *
@@ -10,7 +10,7 @@ const toposort_1 = require("./toposort");
10
10
  const util_1 = require("./util");
11
11
  const logging = require("../lib/logging");
12
12
  /**
13
- * Find all modules that need to be packagerd
13
+ * Find all modules that need to be packaged
14
14
  *
15
15
  * If the input list is empty, include the current directory.
16
16
  *
@@ -66,12 +66,10 @@ async function findJsiiModules(directories, recurse) {
66
66
  }
67
67
  // outdir is either by package.json/jsii.outdir (relative to package root) or via command line (relative to cwd)
68
68
  const outputDirectory = pkg.jsii.outdir && path.resolve(realPath, pkg.jsii.outdir);
69
- const targets = [...Object.keys(pkg.jsii.targets), 'js']; // "js" is an implicit target.
70
69
  ret.push(new packaging_1.JsiiModule({
71
70
  name: pkg.name,
72
71
  moduleDirectory: realPath,
73
72
  defaultOutputDirectory: outputDirectory,
74
- availableTargets: targets,
75
73
  dependencyNames,
76
74
  }));
77
75
  }
@@ -9,10 +9,6 @@ export interface JsiiModuleOptions {
9
9
  * The module directory
10
10
  */
11
11
  moduleDirectory: string;
12
- /**
13
- * Identifier of the targets to build
14
- */
15
- availableTargets: string[];
16
12
  /**
17
13
  * Output directory where to package everything
18
14
  */
@@ -26,7 +22,6 @@ export declare class JsiiModule {
26
22
  readonly name: string;
27
23
  readonly dependencyNames: string[];
28
24
  readonly moduleDirectory: string;
29
- readonly availableTargets: string[];
30
25
  outputDirectory: string;
31
26
  private _tarball?;
32
27
  _assembly?: Assembly;
@@ -38,6 +33,7 @@ export declare class JsiiModule {
38
33
  get tarball(): string;
39
34
  load(system: TypeSystem, validate?: boolean): Promise<Assembly>;
40
35
  get assembly(): Assembly;
36
+ get availableTargets(): string[];
41
37
  cleanup(): Promise<void>;
42
38
  }
43
39
  //# sourceMappingURL=packaging.d.ts.map
package/lib/packaging.js CHANGED
@@ -6,11 +6,11 @@ const path = require("path");
6
6
  const util_1 = require("./util");
7
7
  const logging = require("../lib/logging");
8
8
  exports.DEFAULT_PACK_COMMAND = 'npm pack';
9
+ const ASSEMBLY_SUPPORTED_FEATURES = ['intersection-types'];
9
10
  class JsiiModule {
10
11
  constructor(options) {
11
12
  this.name = options.name;
12
13
  this.moduleDirectory = options.moduleDirectory;
13
- this.availableTargets = options.availableTargets;
14
14
  this.outputDirectory = options.defaultOutputDirectory;
15
15
  this.dependencyNames = options.dependencyNames ?? [];
16
16
  }
@@ -19,20 +19,19 @@ class JsiiModule {
19
19
  */
20
20
  async npmPack(packCommand = exports.DEFAULT_PACK_COMMAND) {
21
21
  this._tarball = await util_1.Scratch.make(async (tmpdir) => {
22
- const args = [];
23
22
  if (packCommand === exports.DEFAULT_PACK_COMMAND) {
24
23
  // Quoting (JSON-stringifying) the module directory in order to avoid
25
24
  // problems if there are spaces or other special characters in the path.
26
- args.push(JSON.stringify(this.moduleDirectory));
25
+ packCommand += ` ${JSON.stringify(this.moduleDirectory)}`;
27
26
  if (logging.level.valueOf() >= logging.LEVEL_VERBOSE) {
28
- args.push('--loglevel=verbose');
27
+ packCommand += ' --loglevel=verbose';
29
28
  }
30
29
  }
31
30
  else {
32
31
  // Ensure module is copied to tmpdir to ensure parallel execution does not contend on generated tarballs
33
32
  await fs.copy(this.moduleDirectory, tmpdir, { dereference: true });
34
33
  }
35
- const out = await (0, util_1.shell)(packCommand, args, {
34
+ const out = await (0, util_1.shell)(packCommand, {
36
35
  cwd: tmpdir,
37
36
  });
38
37
  // Take only the last line of npm pack which should contain the
@@ -57,7 +56,10 @@ class JsiiModule {
57
56
  }
58
57
  async load(system, validate = true) {
59
58
  return system
60
- .loadModule(this.moduleDirectory, { validate })
59
+ .loadModule(this.moduleDirectory, {
60
+ validate,
61
+ supportedFeatures: ASSEMBLY_SUPPORTED_FEATURES,
62
+ })
61
63
  .then((assembly) => (this._assembly = assembly));
62
64
  }
63
65
  get assembly() {
@@ -66,6 +68,10 @@ class JsiiModule {
66
68
  }
67
69
  return this._assembly;
68
70
  }
71
+ get availableTargets() {
72
+ // "js" is an implicit target
73
+ return [...Object.keys(this.assembly.targets ?? {}), 'js'];
74
+ }
69
75
  async cleanup() {
70
76
  if (this._tarball) {
71
77
  await this._tarball.cleanup();
@@ -0,0 +1,20 @@
1
+ import * as spec from '@jsii/spec';
2
+ import { RosettaTabletReader } from 'jsii-rosetta';
3
+ /**
4
+ * Assert that the given spec is safe to give to Rosetta
5
+ *
6
+ * We have to do it like this, because Rosetta has its own internal copy of the
7
+ * spec and new schema additions may make it technically illegal to assign our
8
+ * Assembly instance to Rosetta's Assembly type.
9
+ *
10
+ * We do runtime validation here to make sure that assignment is safe,
11
+ * and then assert it in the type system.
12
+ *
13
+ * The check should be cheap, this gets called quite a lot.
14
+ *
15
+ * (In actual fact, Rosetta doesn't do much with the Assembly, just crawl
16
+ * all API documentations, so basically most new features would be supported...
17
+ * but we technically should do *something* here anyway).
18
+ */
19
+ export declare function assertSpecIsRosettaCompatible(x: spec.Assembly): asserts x is Parameters<RosettaTabletReader['addAssembly']>[0];
20
+ //# sourceMappingURL=rosetta-assembly.d.ts.map
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertSpecIsRosettaCompatible = assertSpecIsRosettaCompatible;
4
+ const ROSETTA_SUPPORTED_ASSEMBLY_FEATURES = [
5
+ 'intersection-types',
6
+ ];
7
+ /**
8
+ * Assert that the given spec is safe to give to Rosetta
9
+ *
10
+ * We have to do it like this, because Rosetta has its own internal copy of the
11
+ * spec and new schema additions may make it technically illegal to assign our
12
+ * Assembly instance to Rosetta's Assembly type.
13
+ *
14
+ * We do runtime validation here to make sure that assignment is safe,
15
+ * and then assert it in the type system.
16
+ *
17
+ * The check should be cheap, this gets called quite a lot.
18
+ *
19
+ * (In actual fact, Rosetta doesn't do much with the Assembly, just crawl
20
+ * all API documentations, so basically most new features would be supported...
21
+ * but we technically should do *something* here anyway).
22
+ */
23
+ function assertSpecIsRosettaCompatible(x) {
24
+ const unsupported = (x.usedFeatures ?? []).filter((f) => !ROSETTA_SUPPORTED_ASSEMBLY_FEATURES.includes(f));
25
+ if (unsupported.length > 0) {
26
+ throw new Error(`This assembly uses features that jsii-pacmak doesn't think jsii-rosetta can handle yet: ${unsupported.join(', ')}`);
27
+ }
28
+ }
29
+ //# sourceMappingURL=rosetta-assembly.js.map
@@ -1,6 +1,7 @@
1
1
  import * as spec from '@jsii/spec';
2
2
  import { CodeMaker } from 'codemaker';
3
3
  import { RosettaTabletReader, ApiLocation } from 'jsii-rosetta';
4
+ import { DotNetTypeResolver } from './dotnettyperesolver';
4
5
  /**
5
6
  * Generates the Jsii attributes and calls for the .NET runtime
6
7
  *
@@ -9,9 +10,10 @@ import { RosettaTabletReader, ApiLocation } from 'jsii-rosetta';
9
10
  export declare class DotNetDocGenerator {
10
11
  private readonly rosetta;
11
12
  private readonly assembly;
13
+ private readonly resolver;
12
14
  private readonly code;
13
15
  private readonly nameutils;
14
- constructor(code: CodeMaker, rosetta: RosettaTabletReader, assembly: spec.Assembly);
16
+ constructor(code: CodeMaker, rosetta: RosettaTabletReader, assembly: spec.Assembly, resolver: DotNetTypeResolver);
15
17
  /**
16
18
  * Emits all documentation depending on what is available in the jsii model
17
19
  *
@@ -31,5 +33,6 @@ export declare class DotNetDocGenerator {
31
33
  private convertExample;
32
34
  private convertSamplesInMarkdown;
33
35
  private emitXmlDoc;
36
+ private renderTypeForDocs;
34
37
  }
35
38
  //# sourceMappingURL=dotnetdocgenerator.d.ts.map
@@ -6,15 +6,28 @@ const jsii_rosetta_1 = require("jsii-rosetta");
6
6
  const xmlbuilder = require("xmlbuilder");
7
7
  const _utils_1 = require("../_utils");
8
8
  const nameutils_1 = require("./nameutils");
9
+ const rosetta_assembly_1 = require("../../rosetta-assembly");
10
+ const type_utils_1 = require("../../type-utils");
11
+ const type_visitor_1 = require("../../type-visitor");
12
+ // Define some tokens that will be turned into literal < and > in XML comments.
13
+ // This will be used by a function later on that needs to output literal tokens,
14
+ // in a string where they would usually be escaped into &lt; and &gt;
15
+ //
16
+ // We use a random string in here so the actual token values cannot be predicted
17
+ // in advance, so that an attacker can not use this knowledge to inject the tokens
18
+ // literally into doc comments, and perform an XSS attack that way.
19
+ const L_ANGLE = `@l${Math.random()}@`;
20
+ const R_ANGLE = `@r${Math.random()}@`;
9
21
  /**
10
22
  * Generates the Jsii attributes and calls for the .NET runtime
11
23
  *
12
24
  * Uses the same instance of CodeMaker as the rest of the code
13
25
  */
14
26
  class DotNetDocGenerator {
15
- constructor(code, rosetta, assembly) {
27
+ constructor(code, rosetta, assembly, resolver) {
16
28
  this.rosetta = rosetta;
17
29
  this.assembly = assembly;
30
+ this.resolver = resolver;
18
31
  this.nameutils = new nameutils_1.DotNetNameUtils();
19
32
  this.code = code;
20
33
  }
@@ -34,34 +47,44 @@ class DotNetDocGenerator {
34
47
  this.emitXmlDoc('summary', (0, _utils_1.renderSummary)(obj.docs));
35
48
  // Handling parameters only if the obj is a method
36
49
  const objMethod = obj;
37
- if (objMethod.parameters) {
50
+ if (objMethod && objMethod.parameters) {
38
51
  objMethod.parameters.forEach((param) => {
39
52
  // Remove any slug `@` from the parameter name - it's not supposed to show up here.
40
53
  const paramName = this.nameutils
41
54
  .convertParameterName(param.name)
42
55
  .replace(/^@/, '');
43
- this.emitXmlDoc('param', param.docs?.summary ?? '', {
56
+ const unionHint = (0, type_utils_1.containsUnionType)(param.type)
57
+ ? `Type union: ${this.renderTypeForDocs(param.type)}`
58
+ : '';
59
+ this.emitXmlDoc('param', combineSentences(param.docs?.summary, unionHint), {
44
60
  attributes: { name: paramName },
45
61
  });
46
62
  });
47
63
  }
48
- // At this pdocfx namespacedocd a valid instance of docs
49
- if (!docs) {
50
- return;
51
- }
52
- if (docs.returns) {
53
- this.emitXmlDoc('returns', docs.returns);
64
+ const returnUnionHint = objMethod.returns && (0, type_utils_1.containsUnionType)(objMethod.returns.type)
65
+ ? `Type union: ${this.renderTypeForDocs(objMethod.returns.type)}`
66
+ : '';
67
+ if (docs?.returns || returnUnionHint) {
68
+ this.emitXmlDoc('returns', combineSentences(docs?.returns, returnUnionHint));
54
69
  }
70
+ const propUnionHint = spec.isProperty(obj) && (0, type_utils_1.containsUnionType)(obj.type)
71
+ ? `Type union: ${this.renderTypeForDocs(obj.type)}`
72
+ : '';
55
73
  // Remarks does not use emitXmlDoc() because the remarks can contain code blocks
56
74
  // which are fenced with <code> tags, which would be escaped to
57
75
  // &lt;code&gt; if we used the xml builder.
58
- const remarks = this.renderRemarks(docs, apiLocation);
59
- if (remarks.length > 0) {
76
+ const remarks = this.renderRemarks(docs ?? {}, apiLocation);
77
+ if (remarks.length > 0 || propUnionHint) {
60
78
  this.code.line('/// <remarks>');
61
79
  remarks.forEach((r) => this.code.line(`/// ${r}`.trimRight()));
80
+ if (propUnionHint) {
81
+ // Very likely to contain < and > from `Dictionary<...>`, but we also want the literal angle brackets
82
+ // from `<see cref="...">`.
83
+ this.code.line(`/// <para>${unescapeAngleMarkers(escapeAngleBrackets(propUnionHint))}</para>`);
84
+ }
62
85
  this.code.line('/// </remarks>');
63
86
  }
64
- if (docs.example) {
87
+ if (docs?.example) {
65
88
  this.code.line('/// <example>');
66
89
  this.emitXmlDoc('code', this.convertExample(docs.example, apiLocation));
67
90
  this.code.line('/// </example>');
@@ -122,10 +145,12 @@ class DotNetDocGenerator {
122
145
  }
123
146
  }
124
147
  convertExample(example, apiLocation) {
148
+ (0, rosetta_assembly_1.assertSpecIsRosettaCompatible)(this.assembly);
125
149
  const translated = this.rosetta.translateExample(apiLocation, example, jsii_rosetta_1.TargetLanguage.CSHARP, (0, jsii_rosetta_1.enforcesStrictMode)(this.assembly));
126
150
  return translated.source;
127
151
  }
128
152
  convertSamplesInMarkdown(markdown, api) {
153
+ (0, rosetta_assembly_1.assertSpecIsRosettaCompatible)(this.assembly);
129
154
  return this.rosetta.translateSnippetsInMarkdown(api, markdown, jsii_rosetta_1.TargetLanguage.CSHARP, (0, jsii_rosetta_1.enforcesStrictMode)(this.assembly));
130
155
  }
131
156
  emitXmlDoc(tag, content, { attributes = {} } = {}) {
@@ -136,7 +161,8 @@ class DotNetDocGenerator {
136
161
  for (const [name, value] of Object.entries(attributes)) {
137
162
  xml.att(name, value);
138
163
  }
139
- const xmlstring = xml.end({ allowEmpty: true, pretty: false });
164
+ // Unescape angle brackets that may have been injected by `renderTypeForDocs`
165
+ const xmlstring = unescapeAngleMarkers(xml.end({ allowEmpty: true, pretty: false }));
140
166
  const trimLeft = tag !== 'code';
141
167
  for (const line of xmlstring
142
168
  .split('\n')
@@ -144,6 +170,22 @@ class DotNetDocGenerator {
144
170
  this.code.line(`/// ${line}`);
145
171
  }
146
172
  }
173
+ renderTypeForDocs(x) {
174
+ return (0, type_visitor_1.visitTypeReference)(x, {
175
+ named: (ref) => `${L_ANGLE}see cref="${this.resolver.toNativeFqn(ref.fqn)}" /${R_ANGLE}`,
176
+ primitive: (ref) => this.resolver.toDotNetType(ref),
177
+ collection: (ref) => {
178
+ switch (ref.collection.kind) {
179
+ case spec.CollectionKind.Array:
180
+ return `(${this.renderTypeForDocs(ref.collection.elementtype)})[]`;
181
+ case spec.CollectionKind.Map:
182
+ return `Dictionary<string, ${this.renderTypeForDocs(ref.collection.elementtype)}>`;
183
+ }
184
+ },
185
+ union: (ref) => `either ${ref.union.types.map((x) => this.renderTypeForDocs(x)).join(' or ')}`,
186
+ intersection: (ref) => `${ref.intersection.types.map((x) => this.renderTypeForDocs(x)).join(' + ')}`,
187
+ });
188
+ }
147
189
  }
148
190
  exports.DotNetDocGenerator = DotNetDocGenerator;
149
191
  /**
@@ -156,4 +198,18 @@ function shouldMentionStability(s) {
156
198
  // Don't render "stable" or "external", those are both stable by implication
157
199
  return s === spec.Stability.Deprecated || s === spec.Stability.Experimental;
158
200
  }
201
+ function combineSentences(...xs) {
202
+ return xs.filter((x) => x).join('. ');
203
+ }
204
+ function escapeAngleBrackets(x) {
205
+ return x.replace(/</g, '&lt;').replace(/>/g, '&gt;');
206
+ }
207
+ /**
208
+ * Replace the special angle markers produced by renderTypeForDocs with literal angle brackets
209
+ */
210
+ function unescapeAngleMarkers(x) {
211
+ return x
212
+ .replace(new RegExp(L_ANGLE, 'g'), '<')
213
+ .replace(new RegExp(R_ANGLE, 'g'), '>');
214
+ }
159
215
  //# sourceMappingURL=dotnetdocgenerator.js.map
@@ -72,10 +72,6 @@ export declare class DotNetGenerator extends Generator {
72
72
  * Used to figure out if the override or virtual keywords are necessary.
73
73
  */
74
74
  private isMemberDefinedOnAncestor;
75
- /**
76
- * Renders method parameters string
77
- */
78
- private renderMethodParameters;
79
75
  /**
80
76
  * Renders parameters string for methods or constructors
81
77
  */
@@ -42,7 +42,7 @@ class DotNetGenerator extends generator_1.Generator {
42
42
  generate(fingerprint) {
43
43
  this.typeresolver = new dotnettyperesolver_1.DotNetTypeResolver(this.assembly, (fqn) => this.findModule(fqn), (fqn) => this.findType(fqn), this.assembliesCurrentlyBeingCompiled);
44
44
  this.dotnetRuntimeGenerator = new dotnetruntimegenerator_1.DotNetRuntimeGenerator(this.code, this.typeresolver);
45
- this.dotnetDocGenerator = new dotnetdocgenerator_1.DotNetDocGenerator(this.code, this.rosetta, this.assembly);
45
+ this.dotnetDocGenerator = new dotnetdocgenerator_1.DotNetDocGenerator(this.code, this.rosetta, this.assembly, this.typeresolver);
46
46
  this.emitAssemblyDocs();
47
47
  // We need to resolve the dependency tree
48
48
  this.typeresolver.resolveNamespacesDependencies();
@@ -165,7 +165,8 @@ class DotNetGenerator extends generator_1.Generator {
165
165
  ? this.typeresolver.toDotNetType(method.returns.type)
166
166
  : 'void';
167
167
  const nullable = method.returns?.optional ? '?' : '';
168
- this.code.line(`${returnType}${nullable} ${this.nameutils.convertMethodName(method.name)}(${this.renderMethodParameters(method)});`);
168
+ const { parameters, whereClause, typeParameters } = this.typeresolver.renderGenericParameters(method.parameters);
169
+ this.code.line(`${returnType}${nullable} ${this.nameutils.convertMethodName(method.name)}${typeParameters}(${this.renderParametersString(parameters)})${whereClause};`);
169
170
  }
170
171
  onInterfaceMethodOverload(ifc, overload, _originalMethod) {
171
172
  this.onInterfaceMethod(ifc, overload);
@@ -187,7 +188,12 @@ class DotNetGenerator extends generator_1.Generator {
187
188
  memberName: prop.name,
188
189
  });
189
190
  this.dotnetRuntimeGenerator.emitAttributesForProperty(prop);
190
- const propType = this.typeresolver.toDotNetType(prop.type);
191
+ // Unfortunately we can only render this as one type. We'll take the first one.
192
+ let apparentType = prop.type;
193
+ if (spec.isIntersectionTypeReference(apparentType)) {
194
+ apparentType = apparentType.intersection.types[0];
195
+ }
196
+ const propType = this.typeresolver.toDotNetType(apparentType);
191
197
  const propName = this.nameutils.convertPropertyName(prop.name);
192
198
  if (prop.optional) {
193
199
  this.code.line('[Amazon.JSII.Runtime.Deputy.JsiiOptional]');
@@ -253,7 +259,11 @@ class DotNetGenerator extends generator_1.Generator {
253
259
  });
254
260
  this.dotnetRuntimeGenerator.emitDeprecatedAttributeIfNecessary(initializer);
255
261
  if (initializer.parameters) {
256
- parametersDefinition = this.renderParametersString(initializer.parameters);
262
+ const { parameters, whereClause } = this.typeresolver.renderGenericParameters(initializer.parameters);
263
+ if (whereClause) {
264
+ throw new Error('C# does not allow generic parameters to a constructor');
265
+ }
266
+ parametersDefinition = this.renderParametersString(parameters);
257
267
  for (const p of initializer.parameters) {
258
268
  parametersBase += `${this.nameutils.convertParameterName(p.name)}`;
259
269
  // If this is not the last parameter, append ,
@@ -391,7 +401,8 @@ class DotNetGenerator extends generator_1.Generator {
391
401
  const access = this.renderAccessLevel(method);
392
402
  const methodName = this.nameutils.convertMethodName(method.name);
393
403
  const isOptional = method.returns && method.returns.optional ? '?' : '';
394
- const signature = `${returnType}${isOptional} ${methodName}(${this.renderMethodParameters(method)})`;
404
+ const { parameters, whereClause, typeParameters } = this.typeresolver.renderGenericParameters(method.parameters);
405
+ const signature = `${returnType}${isOptional} ${methodName}${typeParameters}(${this.renderParametersString(parameters)})${whereClause}`;
395
406
  this.dotnetDocGenerator.emitDocs(method, {
396
407
  api: 'member',
397
408
  fqn: definingType.fqn,
@@ -514,12 +525,6 @@ class DotNetGenerator extends generator_1.Generator {
514
525
  }
515
526
  return false;
516
527
  }
517
- /**
518
- * Renders method parameters string
519
- */
520
- renderMethodParameters(method) {
521
- return this.renderParametersString(method.parameters);
522
- }
523
528
  /**
524
529
  * Renders parameters string for methods or constructors
525
530
  */
@@ -728,10 +733,15 @@ class DotNetGenerator extends generator_1.Generator {
728
733
  const access = this.renderAccessLevel(prop);
729
734
  const staticKeyWord = prop.static ? 'static ' : '';
730
735
  const propName = this.nameutils.convertPropertyName(prop.name);
731
- const propTypeFQN = this.typeresolver.toDotNetType(prop.type);
736
+ // Unfortunately we can only render this as one type. We'll take the first one.
737
+ let apparentType = prop.type;
738
+ if (spec.isIntersectionTypeReference(apparentType)) {
739
+ apparentType = apparentType.intersection.types[0];
740
+ }
741
+ const propTypeFQN = this.typeresolver.toDotNetType(apparentType);
732
742
  const isOptional = prop.optional ? '?' : '';
733
743
  // 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.
734
- const backingFieldName = spec.isInterfaceType(cls) && datatype && containsUnionType(prop.type)
744
+ const backingFieldName = spec.isInterfaceType(cls) && datatype && containsUnionType(apparentType)
735
745
  ? // We down-case the first letter, private fields are conventionally named with a _ prefix, and a camelCase name.
736
746
  `_${propName.replace(/[A-Z]/, (c) => c.toLowerCase())}`
737
747
  : undefined;
@@ -773,7 +783,7 @@ class DotNetGenerator extends generator_1.Generator {
773
783
  const reflectCls = this.reflectAssembly.findType(cls.fqn);
774
784
  const syntheticParam = new reflect.Parameter(reflectCls.system, reflectCls, new reflect.Method(reflectCls.system, reflectCls.assembly, reflectCls, reflectCls, { name: '<synthetic>' }), {
775
785
  name: 'value',
776
- type: prop.type,
786
+ type: apparentType,
777
787
  optional: prop.optional,
778
788
  });
779
789
  if (backingFieldName) {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DotNetRuntimeGenerator = void 0;
4
4
  const spec = require("@jsii/spec");
5
5
  const nameutils_1 = require("./nameutils");
6
+ const type_literals_1 = require("../type-literals");
6
7
  /**
7
8
  * Generates the Jsii attributes and calls for the jsii .NET runtime
8
9
  *
@@ -143,8 +144,16 @@ class DotNetRuntimeGenerator {
143
144
  const paramTypes = new Array();
144
145
  const params = new Array();
145
146
  if (method.parameters) {
146
- for (const param of method.parameters) {
147
- paramTypes.push(`typeof(${this.typeresolver.toDotNetType(param.type)}${param.variadic ? '[]' : ''})`);
147
+ const { parameters } = this.typeresolver.renderGenericParameters(method.parameters);
148
+ for (const param of parameters) {
149
+ if ((0, type_literals_1.isLiteralTypeReference)(param.type)) {
150
+ // Generic type argument -- since we don't actually need this type anyway because we don't use it
151
+ // for method resolution, we can just use Object.
152
+ paramTypes.push('typeof(System.Object)');
153
+ }
154
+ else {
155
+ paramTypes.push(`typeof(${this.typeresolver.toDotNetType(param.type)}${param.variadic ? '[]' : ''})`);
156
+ }
148
157
  params.push(this.nameutils.convertParameterName(param.name));
149
158
  }
150
159
  }
@@ -48,6 +48,19 @@ export declare class DotNetTypeResolver {
48
48
  * Translates a collection in jsii to the name of a native .NET collection
49
49
  */
50
50
  private toDotNetCollectionName;
51
+ /**
52
+ * Render generics for function parameters; updates parameters replacing generic types with type parameters
53
+ *
54
+ * FIXME: This is the wrong way around. It is better to have the renderer
55
+ * assign a unique name and return the fact that a type needs generics. That
56
+ * way it's trivially possible to represent "union-of-intersections", which
57
+ * otherwise will be hard. See the way it's done for Java.
58
+ */
59
+ renderGenericParameters(inParameters: spec.Parameter[] | undefined): {
60
+ parameters: spec.Parameter[];
61
+ typeParameters: string;
62
+ whereClause: string;
63
+ };
51
64
  }
52
65
  export {};
53
66
  //# sourceMappingURL=dotnettyperesolver.d.ts.map
@@ -5,6 +5,7 @@ const spec = require("@jsii/spec");
5
5
  const codemaker_1 = require("codemaker");
6
6
  const filegenerator_1 = require("./filegenerator");
7
7
  const nameutils_1 = require("./nameutils");
8
+ const type_literals_1 = require("../type-literals");
8
9
  class DotNetTypeResolver {
9
10
  constructor(assembly, findModule, findType, assembliesCurrentlyBeingCompiled) {
10
11
  this.assembliesCurrentlyBeingCompiled = assembliesCurrentlyBeingCompiled;
@@ -100,12 +101,12 @@ class DotNetTypeResolver {
100
101
  return this.toDotNetCollection(typeref);
101
102
  }
102
103
  else if (spec.isNamedTypeReference(typeref)) {
103
- return this.toNativeFqn(typeref.fqn);
104
+ return (0, type_literals_1.literalTypeReference)(typeref) ?? this.toNativeFqn(typeref.fqn);
104
105
  }
105
- else if (typeref.union) {
106
+ else if (spec.isUnionTypeReference(typeref)) {
106
107
  return 'object';
107
108
  }
108
- throw new Error(`Invalid type reference: ${JSON.stringify(typeref)}`);
109
+ throw new Error(`Unresolvable type reference: ${JSON.stringify(typeref)}`);
109
110
  }
110
111
  /**
111
112
  * Translates any jsii type to the name of its corresponding .NET type (as a .NET string).
@@ -120,7 +121,7 @@ class DotNetTypeResolver {
120
121
  else if (spec.isNamedTypeReference(typeref)) {
121
122
  return `typeof(${this.toNativeFqn(typeref.fqn)}).FullName`;
122
123
  }
123
- else if (typeref.union) {
124
+ else if (spec.isUnionTypeReference(typeref)) {
124
125
  return '"object"';
125
126
  }
126
127
  throw new Error(`Invalid type reference: ${JSON.stringify(typeref)}`);
@@ -219,6 +220,43 @@ class DotNetTypeResolver {
219
220
  throw new Error(`Unsupported collection kind: ${ref.collection.kind}`);
220
221
  }
221
222
  }
223
+ /**
224
+ * Render generics for function parameters; updates parameters replacing generic types with type parameters
225
+ *
226
+ * FIXME: This is the wrong way around. It is better to have the renderer
227
+ * assign a unique name and return the fact that a type needs generics. That
228
+ * way it's trivially possible to represent "union-of-intersections", which
229
+ * otherwise will be hard. See the way it's done for Java.
230
+ */
231
+ renderGenericParameters(inParameters) {
232
+ const parameters = new Array();
233
+ const typeParameters = new Array();
234
+ const genericConstraints = new Array();
235
+ for (const p of inParameters ?? []) {
236
+ if (spec.isIntersectionTypeReference(p.type)) {
237
+ const typeParameterName = `T${Object.keys(genericConstraints).length + 1}`;
238
+ parameters.push({
239
+ name: p.name,
240
+ docs: p.docs,
241
+ optional: p.optional,
242
+ variadic: p.variadic,
243
+ type: (0, type_literals_1.makeLiteralTypeReference)(typeParameterName),
244
+ });
245
+ typeParameters.push(typeParameterName);
246
+ genericConstraints.push(`where ${typeParameterName}: ${p.type.intersection.types
247
+ .map((t) => this.toDotNetType(t))
248
+ .join(', ')}`);
249
+ }
250
+ else {
251
+ parameters.push(p);
252
+ }
253
+ }
254
+ return {
255
+ parameters,
256
+ typeParameters: typeParameters.length > 0 ? `<${typeParameters.join(', ')}>` : '',
257
+ whereClause: genericConstraints.length > 0 ? ` ${genericConstraints.join(' ')}` : '',
258
+ };
259
+ }
222
260
  }
223
261
  exports.DotNetTypeResolver = DotNetTypeResolver;
224
262
  //# sourceMappingURL=dotnettyperesolver.js.map
@@ -3,7 +3,7 @@ import { TargetBuilder, BuildOptions } from '../builder';
3
3
  import { JsiiModule } from '../packaging';
4
4
  import { PackageInfo, Target, TargetOptions } from '../target';
5
5
  import { DotNetGenerator } from './dotnet/dotnetgenerator';
6
- export declare const TARGET_FRAMEWORK = "netcoreapp3.1";
6
+ export declare const TARGET_FRAMEWORK = "net6.0";
7
7
  /**
8
8
  * Build .NET packages all together, by generating an aggregate solution file
9
9
  */
@@ -10,7 +10,7 @@ const util_1 = require("../util");
10
10
  const dotnetgenerator_1 = require("./dotnet/dotnetgenerator");
11
11
  const version_utils_1 = require("./version-utils");
12
12
  const _1 = require(".");
13
- exports.TARGET_FRAMEWORK = 'netcoreapp3.1';
13
+ exports.TARGET_FRAMEWORK = 'net6.0';
14
14
  /**
15
15
  * Build .NET packages all together, by generating an aggregate solution file
16
16
  */
@@ -36,7 +36,7 @@ class DotnetBuilder {
36
36
  scratchDirs.push(tempSourceDir);
37
37
  // Build solution
38
38
  logging.debug('Building .NET');
39
- await (0, util_1.shell)('dotnet', ['build', '--force', '--configuration', 'Release'], {
39
+ await (0, util_1.subprocess)('dotnet', ['build', '--force', '--configuration', 'Release'], {
40
40
  cwd: tempSourceDir.directory,
41
41
  retry: { maxAttempts: 5 },
42
42
  });
@@ -68,8 +68,10 @@ class DotnetBuilder {
68
68
  });
69
69
  }
70
70
  // Use 'dotnet' command line tool to build a solution file from these csprojs
71
- await (0, util_1.shell)('dotnet', ['new', 'sln', '-n', 'JsiiBuild'], { cwd: tmpDir });
72
- await (0, util_1.shell)('dotnet', ['sln', 'add', ...csProjs], { cwd: tmpDir });
71
+ await (0, util_1.subprocess)('dotnet', ['new', 'sln', '-n', 'JsiiBuild'], {
72
+ cwd: tmpDir,
73
+ });
74
+ await (0, util_1.subprocess)('dotnet', ['sln', 'add', ...csProjs], { cwd: tmpDir });
73
75
  await this.generateNuGetConfigForLocalDeps(tmpDir);
74
76
  return ret;
75
77
  });