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.
- package/bin/jsii-pacmak.js +1 -1
- package/lib/index.js +2 -0
- package/lib/npm-modules.d.ts +1 -1
- package/lib/npm-modules.js +1 -3
- package/lib/packaging.d.ts +1 -5
- package/lib/packaging.js +12 -6
- package/lib/rosetta-assembly.d.ts +20 -0
- package/lib/rosetta-assembly.js +29 -0
- package/lib/targets/dotnet/dotnetdocgenerator.d.ts +4 -1
- package/lib/targets/dotnet/dotnetdocgenerator.js +69 -13
- package/lib/targets/dotnet/dotnetgenerator.d.ts +0 -4
- package/lib/targets/dotnet/dotnetgenerator.js +24 -14
- package/lib/targets/dotnet/dotnetruntimegenerator.js +11 -2
- package/lib/targets/dotnet/dotnettyperesolver.d.ts +13 -0
- package/lib/targets/dotnet/dotnettyperesolver.js +42 -4
- package/lib/targets/dotnet.d.ts +1 -1
- package/lib/targets/dotnet.js +6 -4
- package/lib/targets/go/runtime/runtime-type-checking.js +1 -0
- package/lib/targets/go/types/go-type-reference.d.ts +3 -0
- package/lib/targets/go/types/go-type-reference.js +20 -0
- package/lib/targets/go.js +1 -1
- package/lib/targets/java.d.ts +28 -4
- package/lib/targets/java.js +411 -219
- package/lib/targets/python/requirements-dev.txt +2 -2
- package/lib/targets/python/type-name.d.ts +18 -0
- package/lib/targets/python/type-name.js +59 -1
- package/lib/targets/python.d.ts +2 -1
- package/lib/targets/python.js +53 -18
- package/lib/targets/type-literals.d.ts +22 -0
- package/lib/targets/type-literals.js +39 -0
- package/lib/type-utils.d.ts +3 -0
- package/lib/type-utils.js +10 -0
- package/lib/type-visitor.d.ts +19 -0
- package/lib/type-visitor.js +47 -0
- package/lib/util.d.ts +18 -5
- package/lib/util.js +80 -13
- package/lib/version.d.ts +1 -1
- package/lib/version.js +3 -3
- package/package.json +15 -14
package/bin/jsii-pacmak.js
CHANGED
|
@@ -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
|
});
|
package/lib/npm-modules.d.ts
CHANGED
package/lib/npm-modules.js
CHANGED
|
@@ -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
|
|
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
|
}
|
package/lib/packaging.d.ts
CHANGED
|
@@ -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
|
-
|
|
25
|
+
packCommand += ` ${JSON.stringify(this.moduleDirectory)}`;
|
|
27
26
|
if (logging.level.valueOf() >= logging.LEVEL_VERBOSE) {
|
|
28
|
-
|
|
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,
|
|
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, {
|
|
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 < and >
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
// <code> 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
|
|
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
|
-
|
|
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, '<').replace(/>/g, '>');
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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
|
-
|
|
147
|
-
|
|
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
|
|
106
|
+
else if (spec.isUnionTypeReference(typeref)) {
|
|
106
107
|
return 'object';
|
|
107
108
|
}
|
|
108
|
-
throw new Error(`
|
|
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
|
|
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
|
package/lib/targets/dotnet.d.ts
CHANGED
|
@@ -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 = "
|
|
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
|
*/
|
package/lib/targets/dotnet.js
CHANGED
|
@@ -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 = '
|
|
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.
|
|
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.
|
|
72
|
-
|
|
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
|
});
|