diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1405f2edef..db18c17191 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1159,6 +1159,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "ansgarm",
+ "name": "Ansgar Mertens",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1112056?v=4",
+ "profile": "https://ansgar.dev",
+ "contributions": [
+ "maintenance"
+ ]
}
],
"repoType": "github",
@@ -1168,4 +1177,4 @@
"README.md"
],
"contributorsPerLine": 7
-}
\ No newline at end of file
+}
diff --git a/.github/ISSUE_TEMPLATE/2-feature-request.md b/.github/ISSUE_TEMPLATE/2-feature-request.md
index 3b16e8408f..b1b1221ea7 100644
--- a/.github/ISSUE_TEMPLATE/2-feature-request.md
+++ b/.github/ISSUE_TEMPLATE/2-feature-request.md
@@ -10,7 +10,7 @@ labels: feature-request, needs-triage
- [ ] `TypeScript` or `Javascript`
- [ ] `Python`
diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml
index d8fb97fee7..da65a1d7e2 100644
--- a/.github/workflows/gh-pages.yml
+++ b/.github/workflows/gh-pages.yml
@@ -27,7 +27,7 @@ jobs:
run: |-
echo "::set-output name=pip-cache::$(python3 -m pip cache dir)"
- name: Cache
- uses: actions/cache@v2.1.5
+ uses: actions/cache@v2.1.6
with:
path: ${{ steps.cache-locations.outputs.pip-cache }}
key: ${{ runner.os }}-${{ hashFiles('**/requirements-dev.txt') }}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 913ff06988..16992c0f94 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -60,7 +60,7 @@ jobs:
echo "::set-output name=pip-cache::$(python3 -m pip cache dir)"
echo "::set-output name=yarn-cache::$(yarn cache dir)"
- name: Cache
- uses: actions/cache@v2.1.5
+ uses: actions/cache@v2.1.6
with:
path: |-
${{ steps.cache-locations.outputs.pip-cache }}
@@ -154,7 +154,7 @@ jobs:
echo "::set-output name=pip-cache::$(python3 -m pip cache dir)"
echo "::set-output name=yarn-cache::$(yarn cache dir)"
- name: Cache
- uses: actions/cache@v2.1.5
+ uses: actions/cache@v2.1.6
with:
path: |-
${{ steps.cache-locations.outputs.pip-cache }}
@@ -316,7 +316,7 @@ jobs:
echo "::set-output name=pip-cache::$(python3 -m pip cache dir)"
echo "::set-output name=yarn-cache::$(yarn cache dir)"
- name: Cache
- uses: actions/cache@v2.1.5
+ uses: actions/cache@v2.1.6
with:
path: |-
${{ steps.cache-locations.outputs.pip-cache }}
diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml
index 549333a7b8..ca27b7add3 100644
--- a/.github/workflows/yarn-upgrade.yml
+++ b/.github/workflows/yarn-upgrade.yml
@@ -27,7 +27,7 @@ jobs:
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Restore Yarn cache
- uses: actions/cache@v2.1.5
+ uses: actions/cache@v2.1.6
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41bb6d91eb..c3aa8a3138 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,21 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+## [1.31.0](https://github.com/aws/jsii/compare/v1.30.0...v1.31.0) (2021-07-09)
+
+
+### Features
+
+* **jsii-rosetta transliterate:** transliterate a jsii assembly ([#2869](https://github.com/aws/jsii/issues/2869)) ([d9028c8](https://github.com/aws/jsii/commit/d9028c8cf91297a44cd4b1f128f769716bf0e74e))
+* **rosetta:** transliterate loose mode ([#2892](https://github.com/aws/jsii/issues/2892)) ([43e6dfd](https://github.com/aws/jsii/commit/43e6dfd0591b0f38a8c636edd3896400c96676e3))
+
+
+### Bug Fixes
+
+* **pacmak/go:** missing go.sum entry ([#2893](https://github.com/aws/jsii/issues/2893)) ([6e6ad69](https://github.com/aws/jsii/commit/6e6ad693230e18f36990e8feaf3734da7c01dbd5))
+* **rosetta:** extract does not respect strict metadata entry ([#2863](https://github.com/aws/jsii/issues/2863)) ([5d2392b](https://github.com/aws/jsii/commit/5d2392b7713cb6dfea6092c4ac3ee45360a5d28a)), closes [#2861](https://github.com/aws/jsii/issues/2861)
+* **rosetta:** hangs on 'markdown' command when a file is provided ([#2871](https://github.com/aws/jsii/issues/2871)) ([e538b36](https://github.com/aws/jsii/commit/e538b36c6ccf53ace908ff4c342dc9a4435ce353))
+
## [1.30.0](https://github.com/aws/jsii/compare/v1.29.0...v1.30.0) (2021-05-27)
diff --git a/README.md b/README.md
index 49f1fdea94..c9a1b077c9 100644
--- a/README.md
+++ b/README.md
@@ -64,141 +64,142 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Andy Slezak π» |
+ Ansgar Mertens π§ |
Anshul Guleria π€ |
Ari Palo π€ |
Armaan Tobaccowalla π |
BartΕomiej Jurek π |
Ben Bridts π |
Ben Farr π |
- Ben Walters π€ |
+ Ben Walters π€ |
Benjamin Macher π |
Benjamin Maizels π» π |
Bill Cauchois π€ |
Brecht Verhoeve π€ |
Breland Miley π» |
CaerusKaru π» π§ |
- Camilo BermΓΊdez π |
+ Camilo BermΓΊdez π |
Campion Fellin π» |
Carter Van Deuren π |
Christophe Vico π |
Christopher Currie π» π€ |
Christopher Rybicki π |
Cory Hall π |
- Cristian MΔgheruΘan-Stanciu π |
+ Cristian MΔgheruΘan-Stanciu π |
CyrusNajmabadi π π€ |
Daniel Dinu π π» |
Daniel Schroeder π π» π π€ π§ |
Dave Slotnick π |
Donald Stufft π π» π€ π |
Dongie Agnir π» π |
- Eduardo Sena S. Rosa π |
+ Eduardo Sena S. Rosa π |
Elad Ben-Israel π π» π€ π§ π π’ |
Eli Polonsky π π» π€ π§ π |
Eric Z. Beard π |
Erik Karlsson π |
Eugene Kozlov π» |
Fabio Gentile π |
- Florian Eitel π€ |
+ Florian Eitel π€ |
Graham Lea π€ π |
Hamza Assyad π π» π€ π |
Hari Pachuveetil π π |
Hsing-Hui Hsu π» π π€ π |
James Kelley π |
James Mead π» |
- James Siri π» π§ |
+ James Siri π» π§ |
Jason Del Ponte π€ π |
Jason Fulghum π€ π π |
Jerry Kindall π π€ |
Jimmy Gaussen π€ |
Jon Steinich π π€ π» |
Joseph Lawson π |
- Joseph Martin π |
+ Joseph Martin π |
Junix π |
Justin Taylor π |
Kyle Thomson π» π |
Leandro Padua π |
Liang Zhou π π» |
Maja S Bratseth π |
- Marcos Diez π |
+ Marcos Diez π |
Mark Nielsen π» |
Matthew Bonig π π |
Matthew Pirocchi π» π€ π |
Mike Lane π |
Mitch Garnaat π π» π€ π |
Mitchell Valine π π» π€ π§ π |
- Mohamad Soufan π |
+ Mohamad Soufan π |
Neta Nir π» π€ π§ π |
Nick Lynch π π» π§ π |
Niranjan Jayakar π π» π€ π§ π |
Noah Litov π» π§ π |
PIDZ - Bart π€ |
Petr Kacer π |
- Petra Barus π» |
+ Petra Barus π» |
Philip Cali π€ |
Quentin Loos π€ |
Raphael π |
Richard H Boyd π |
Rico Huijbers π π» π€ π§ π |
Romain Marcadier π π» π¨ π€ π§ π π |
- SADIK KUZU π |
+ SADIK KUZU π |
SK π€ |
Sam Fink π» π |
Sam Goodwin π |
Sebastian Korfmann π π» π€ |
Shane Witbeck π€ |
Shiv Lakshminarayan π» π§ π |
- Somaya π» π€ π§ π |
+ Somaya π» π€ π§ π |
The Gitter Badger π» π§ |
Thomas Poignant π |
Thomas Steinbach π |
Thorsten Hoeger π» |
Tim Wagner π π€ |
Tobias Lidskog π» |
- Ty Coghlan π |
+ Ty Coghlan π |
Tyler van Hensbergen π€ |
Vlad Hrybok π |
Vladimir Shchur π |
Yan Zhulanow π» |
Yigong Liu π π€ |
ajnarang π€ |
- aniljava π» |
+ aniljava π» |
deccy-mcc π |
dependabot-preview[bot] π π§ |
dependabot[bot] π§ |
dheffx π |
gregswdl π |
guyroberts21 π |
- mattBrzezinski π |
+ mattBrzezinski π |
mergify[bot] π§ |
seiyashima42 π π» π |
sullis π» |
diff --git a/gh-pages/content/user-guides/lib-author/configuration/targets/dotnet.md b/gh-pages/content/user-guides/lib-author/configuration/targets/dotnet.md
index 53afbb9ffc..8ba69c550c 100644
--- a/gh-pages/content/user-guides/lib-author/configuration/targets/dotnet.md
+++ b/gh-pages/content/user-guides/lib-author/configuration/targets/dotnet.md
@@ -8,9 +8,6 @@ The `dotnet` target requires the following configuration:
transparent background is recommended. See the [.NET documentation] for more information.
- `versionSuffix` - an optional suffix that will be appended at the end of the NuGet package's `version` field. The
suffix must start with a `-`.
-- `signAssembly` - whether the assembly should be strong-name signed. Defaults to `false` when not specified.
-- `assemblyOriginatorKeyFile`- the path to the strong-name signing key to be used. When not specified or if the file
- referred to does not exist, the assembly will not be strong-name signed.
Example:
@@ -21,8 +18,6 @@ Example:
"namespace": "Acme.HelloJsii", // Required
"packageId": "Acme.HelloJsii", // Required
"iconUrl": "https://cdn.acme.com/icon.png", // Optional
- "signAssembly": true, // Optional
- "assemblyOriginatorKeyFile": "./key.snk", // Optional
"versionSuffix": "-preview" // Optional
},
// ...
diff --git a/gh-pages/requirements-dev.txt b/gh-pages/requirements-dev.txt
index 8901cebb10..68cf2c61b5 100644
--- a/gh-pages/requirements-dev.txt
+++ b/gh-pages/requirements-dev.txt
@@ -1,4 +1,4 @@
-mkdocs~=1.1.2
+mkdocs~=1.2.1
mkdocs-awesome-pages-plugin~=2.5.0
-mkdocs-material~=7.1.3
+mkdocs-material~=7.1.9
mkdocs-git-revision-date-plugin~=0.3.1
diff --git a/lerna.json b/lerna.json
index 36021b8eac..3fbac4bcab 100644
--- a/lerna.json
+++ b/lerna.json
@@ -10,5 +10,5 @@
"rejectCycles": true
}
},
- "version": "1.30.0"
+ "version": "1.31.0"
}
diff --git a/packages/@jsii/Directory.Build.targets b/packages/@jsii/Directory.Build.targets
index 236a616094..a17f284712 100644
--- a/packages/@jsii/Directory.Build.targets
+++ b/packages/@jsii/Directory.Build.targets
@@ -6,11 +6,11 @@
-
+
-
+
diff --git a/packages/@jsii/dotnet-runtime/NuGet.Metadata.props.t.js b/packages/@jsii/dotnet-runtime/NuGet.Metadata.props.t.js
index a001304303..0b4241725e 100644
--- a/packages/@jsii/dotnet-runtime/NuGet.Metadata.props.t.js
+++ b/packages/@jsii/dotnet-runtime/NuGet.Metadata.props.t.js
@@ -20,9 +20,6 @@ process.stdout.write(`
True
..\\..\\bin\\$(Configuration)\\NuGet\\
-
- key.snk
- True
`);
diff --git a/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/JsonModel/AssemblyTests.cs b/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/JsonModel/AssemblyTests.cs
index 75425a8687..e370163353 100644
--- a/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/JsonModel/AssemblyTests.cs
+++ b/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/JsonModel/AssemblyTests.cs
@@ -37,8 +37,6 @@ public void ShouldSerializeAllMembers()
targets: new AssemblyTargets(new AssemblyTargets.DotNetTarget(
@namespace: "Dot.Net.Namespace",
packageId: "Dot.Net.PackageId",
- signAssembly: true,
- assemblyOriginatorKeyFile: "key.snk",
iconUrl: "http://www.example.com/icon.png"
)),
dependencies: new Dictionary(),
@@ -92,8 +90,6 @@ public void ShouldSerializeAllMembers()
""dotnet"": {
""namespace"": ""Dot.Net.Namespace"",
""packageId"": ""Dot.Net.PackageId"",
- ""signAssembly"": true,
- ""assemblyOriginatorKeyFile"": ""key.snk"",
""iconUrl"": ""http://www.example.com/icon.png""
}
}
@@ -120,8 +116,6 @@ public void ShouldThrowOnMissingName()
targets: new AssemblyTargets(new AssemblyTargets.DotNetTarget(
@namespace: "Dot.Net.Namespace",
packageId: "Dot.Net.PackageId",
- signAssembly: true,
- assemblyOriginatorKeyFile: "key.snk",
iconUrl: "http://www.example.com/icon.png"
)),
dependencies: new Dictionary(),
@@ -149,8 +143,6 @@ public void ShouldThrowOnMissingVersion()
targets: new AssemblyTargets(new AssemblyTargets.DotNetTarget(
@namespace: "Dot.Net.Namespace",
packageId: "Dot.Net.PackageId",
- signAssembly: true,
- assemblyOriginatorKeyFile: "key.snk",
iconUrl: "http://www.example.com/icon.png"
)),
types: new Dictionary(),
@@ -176,8 +168,6 @@ public void ShouldNotSerializeMissingDependencies()
targets: new AssemblyTargets(new AssemblyTargets.DotNetTarget(
@namespace: "Dot.Net.Namespace",
packageId: "Dot.Net.PackageId",
- signAssembly: true,
- assemblyOriginatorKeyFile: "key.snk",
iconUrl: "http://www.example.com/icon.png"
)),
types: new Dictionary(),
@@ -210,8 +200,6 @@ public void ShouldNotSerializeMissingDependencies()
""dotnet"": {
""namespace"": ""Dot.Net.Namespace"",
""packageId"": ""Dot.Net.PackageId"",
- ""signAssembly"": true,
- ""assemblyOriginatorKeyFile"": ""key.snk"",
""iconUrl"": ""http://www.example.com/icon.png""
}
}
@@ -236,8 +224,6 @@ public void ShouldNotSerializeMissingBundled()
targets: new AssemblyTargets(new AssemblyTargets.DotNetTarget(
@namespace: "Dot.Net.Namespace",
packageId: "Dot.Net.PackageId",
- signAssembly: true,
- assemblyOriginatorKeyFile: "key.snk",
iconUrl: "http://www.example.com/icon.png"
)),
types: new Dictionary(),
@@ -270,8 +256,6 @@ public void ShouldNotSerializeMissingBundled()
""dotnet"": {
""namespace"": ""Dot.Net.Namespace"",
""packageId"": ""Dot.Net.PackageId"",
- ""signAssembly"": true,
- ""assemblyOriginatorKeyFile"": ""key.snk"",
""iconUrl"": ""http://www.example.com/icon.png""
}
}
@@ -296,8 +280,6 @@ public void ShouldNotSerializeMissingDocs()
targets: new AssemblyTargets(new AssemblyTargets.DotNetTarget(
@namespace: "Dot.Net.Namespace",
packageId: "Dot.Net.PackageId",
- signAssembly: true,
- assemblyOriginatorKeyFile: "key.snk",
iconUrl: "http://www.example.com/icon.png"
)),
types: new Dictionary(),
@@ -330,8 +312,6 @@ public void ShouldNotSerializeMissingDocs()
""dotnet"": {
""namespace"": ""Dot.Net.Namespace"",
""packageId"": ""Dot.Net.PackageId"",
- ""signAssembly"": true,
- ""assemblyOriginatorKeyFile"": ""key.snk"",
""iconUrl"": ""http://www.example.com/icon.png""
}
}
@@ -429,8 +409,6 @@ public void ShouldDeserializeAllMembersWithDotNetTarget()
""dotnet"": {
""namespace"": ""Dot.Net.Namespace"",
""packageId"": ""Dot.Net.PackageId"",
- ""signAssembly"": true,
- ""assemblyOriginatorKeyFile"": ""key.snk"",
""iconUrl"": ""http://www.example.com/icon.png""
},
""java"": { ""package"": ""com.amazonaws.cdk.Test"" }
@@ -463,8 +441,6 @@ public void ShouldDeserializeAllMembersWithDotNetTarget()
Assert.NotNull(dotNetTarget);
Assert.Equal("Dot.Net.Namespace", dotNetTarget?.Namespace);
Assert.Equal("Dot.Net.PackageId", dotNetTarget?.PackageId);
- Assert.True(dotNetTarget?.SignAssembly);
- Assert.Equal("key.snk", dotNetTarget?.AssemblyOriginatorKeyFile);
Assert.Equal("http://www.example.com/icon.png", dotNetTarget?.IconUrl);
Assert.Equal("myVersion", actual.Version, ignoreLineEndingDifferences: true);
diff --git a/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime/JsonModel/Spec/AssemblyTargets.cs b/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime/JsonModel/Spec/AssemblyTargets.cs
index 0c91a56b87..5e59dcac9b 100644
--- a/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime/JsonModel/Spec/AssemblyTargets.cs
+++ b/packages/@jsii/dotnet-runtime/src/Amazon.JSII.Runtime/JsonModel/Spec/AssemblyTargets.cs
@@ -23,8 +23,6 @@ public DotNetTarget
string @namespace,
string packageId,
string? title = null,
- bool signAssembly = false,
- string? assemblyOriginatorKeyFile = null,
string? iconUrl = null,
string? versionSuffix = null
)
@@ -33,8 +31,6 @@ public DotNetTarget
PackageId = packageId ?? throw new ArgumentNullException(nameof(packageId));
Title = title;
- SignAssembly = signAssembly;
- AssemblyOriginatorKeyFile = assemblyOriginatorKeyFile;
IconUrl = iconUrl;
VersionSuffix = versionSuffix;
@@ -53,12 +49,6 @@ public DotNetTarget
[JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
public string? Title { get; }
- [JsonProperty("signAssembly", NullValueHandling = NullValueHandling.Ignore)]
- public bool SignAssembly { get; }
-
- [JsonProperty("assemblyOriginatorKeyFile", NullValueHandling = NullValueHandling.Ignore)]
- public string? AssemblyOriginatorKeyFile { get; }
-
[JsonProperty("iconUrl", NullValueHandling = NullValueHandling.Ignore)]
public string? IconUrl { get; }
diff --git a/packages/@jsii/go-runtime/go.mod b/packages/@jsii/go-runtime/go.mod
index 73a39e3522..4f2974d796 100644
--- a/packages/@jsii/go-runtime/go.mod
+++ b/packages/@jsii/go-runtime/go.mod
@@ -4,5 +4,5 @@ go 1.15
require (
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5
- golang.org/x/tools v0.1.2
+ golang.org/x/tools v0.1.4
)
diff --git a/packages/@jsii/go-runtime/go.sum b/packages/@jsii/go-runtime/go.sum
index 053cc719ab..9e86be1b81 100644
--- a/packages/@jsii/go-runtime/go.sum
+++ b/packages/@jsii/go-runtime/go.sum
@@ -25,8 +25,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
-golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs=
+golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
diff --git a/packages/@jsii/python-runtime/requirements.txt b/packages/@jsii/python-runtime/requirements.txt
index 4ca967d642..a999873ac3 100644
--- a/packages/@jsii/python-runtime/requirements.txt
+++ b/packages/@jsii/python-runtime/requirements.txt
@@ -1,9 +1,9 @@
-black~=21.4b2
+black~=21.6b0
mypy==0.812
pip~=21.1
pytest~=6.2
pytest-mypy~=0.8
-setuptools~=56.0
+setuptools~=57.0
wheel~=0.36
-e .
diff --git a/packages/@jsii/spec/lib/configuration.ts b/packages/@jsii/spec/lib/configuration.ts
index b241b050ca..fdb0f23b52 100644
--- a/packages/@jsii/spec/lib/configuration.ts
+++ b/packages/@jsii/spec/lib/configuration.ts
@@ -77,16 +77,6 @@ export interface Config {
* version field
*/
versionSuffix?: string;
-
- /**
- * whether the assembly should be strong-name signed
- */
- signAssembly?: boolean;
-
- /**
- * path to the strong-name signing key to be used
- */
- assemblyOriginatorFile?: string;
};
};
diff --git a/packages/jsii-config/README.md b/packages/jsii-config/README.md
index 4235390e6e..9be91ece41 100644
--- a/packages/jsii-config/README.md
+++ b/packages/jsii-config/README.md
@@ -2,7 +2,7 @@
jsii-config is a command line utility for configuring [jsii enabled modules](../../README.md). It is useful to help convert an existing typescript module to a jsii module. It can also be used to revise existing jsii compiler configuration optiions, such as adding a new language target.
-[See the jsii documentation](../../docs/configuration.md) for more information on how the configuration options affect jsii's output.
+[See the jsii documentation](https://aws.github.io/jsii/user-guides/lib-author/configuration/) for more information on how the configuration options affect jsii's output.
## Usage
@@ -14,7 +14,7 @@ jsii-config requires an existing package.json with the following fields:
- main
- author
-For details on the content of these fields, [see the jsii documentation](../../docs/configuration.md#additional-requirements--extensions).
+For details on the content of these fields, [see the jsii documentation](https://aws.github.io/jsii/user-guides/lib-author/configuration/#additional-requirements-extensions).
jsii-config can be called via npx.
diff --git a/packages/jsii-config/lib/schema.ts b/packages/jsii-config/lib/schema.ts
index 24d2a7bb8c..9b51491e67 100644
--- a/packages/jsii-config/lib/schema.ts
+++ b/packages/jsii-config/lib/schema.ts
@@ -179,26 +179,6 @@ const schema: ConfigPromptsSchema = {
return true;
},
},
- signAssembly: {
- type: 'confirm',
- default: false,
- message:
- '.NET Sign Assembly - whether the assembly should be strong-name signed. Defaults to false when not specified',
- when: targetEnabled('dotnet'),
- },
- assemblyOriginatorKeyFile: {
- type: 'input',
- default: '',
- message:
- '.NET Assembly Originator Key File - path to the strong-name signing key to be used (e.g. "../../key.snk")',
- when: (answers: any) => {
- return (
- targetEnabled('dotnet')(answers) &&
- Boolean(answers.jsii.targets.dotnet.signAssembly)
- );
- },
- validate: hasLength,
- },
},
},
},
diff --git a/packages/jsii-config/test/index.test.ts b/packages/jsii-config/test/index.test.ts
index b5960b06d0..f93bee8fe7 100644
--- a/packages/jsii-config/test/index.test.ts
+++ b/packages/jsii-config/test/index.test.ts
@@ -98,7 +98,6 @@ describe('jsii-config', () => {
packageId: 'Amazon.Module',
iconUrl: undefined,
versionSuffix: '',
- signAssembly: false,
},
},
},
@@ -209,7 +208,6 @@ describe('jsii-config', () => {
'jsii.targets.dotnet.packageId',
'jsii.targets.dotnet.iconUrl',
'jsii.targets.dotnet.versionSuffix',
- 'jsii.targets.dotnet.signAssembly',
],
questions,
);
@@ -223,44 +221,10 @@ describe('jsii-config', () => {
});
});
- it('prompts for dotnet assembly originator file when target and signAssembly are enabled', async () => {
- await jsiiConfig('./package.json');
- const questions = promptMock.mock.calls[0][0];
- const subject = findQuestion(
- 'jsii.targets.dotnet.assemblyOriginatorKeyFile',
- questions,
- );
- const enabled = {
- jsiiTargets: ['dotnet'],
- jsii: {
- targets: {
- dotnet: {
- signAssembly: true,
- },
- },
- },
- };
-
- const disabled = {
- jsiiTargets: ['dotnet'],
- jsii: {
- targets: {
- dotnet: {
- signAssembly: false,
- },
- },
- },
- };
-
- expect(subject.when(enabled)).toBe(true);
- expect(subject.when(disabled)).toBe(false);
- });
-
it('returns new config with empty values removed', async () => {
const subject = await jsiiConfig('./package.json');
const expected = { ...configAnswers };
delete expected.jsii.targets.dotnet.iconUrl;
- delete expected.jsii.targets.dotnet.signAssembly;
delete expected.jsii.targets.dotnet.versionSuffix;
delete expected.jsii.targets.java.maven.versionSuffix;
@@ -280,7 +244,6 @@ describe('jsii-config', () => {
'jsii.targets.python.module',
'jsii.targets.dotnet.namespace',
'jsii.targets.dotnet.packageId',
- 'jsii.targets.dotnet.assemblyOriginatorKeyFile',
].forEach((field) => {
it(`shows error message when empty ${field} is submitted`, async () => {
await jsiiConfig('./package.json');
diff --git a/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts b/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts
index 193cad5a04..5e2ebb5491 100644
--- a/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts
+++ b/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts
@@ -2,6 +2,7 @@ import * as spec from '@jsii/spec';
import { CodeMaker } from 'codemaker';
import {
Rosetta,
+ TargetLanguage,
Translation,
enforcesStrictMode,
typeScriptSnippetFromSource,
@@ -166,7 +167,10 @@ export class DotNetDocGenerator {
'example',
enforcesStrictMode(this.assembly),
);
- const translated = this.rosetta.translateSnippet(snippet, 'csharp');
+ const translated = this.rosetta.translateSnippet(
+ snippet,
+ TargetLanguage.CSHARP,
+ );
if (!translated) {
return example;
}
@@ -176,7 +180,7 @@ export class DotNetDocGenerator {
private convertSamplesInMarkdown(markdown: string): string {
return this.rosetta.translateSnippetsInMarkdown(
markdown,
- 'csharp',
+ TargetLanguage.CSHARP,
enforcesStrictMode(this.assembly),
(trans) => ({
language: trans.language,
diff --git a/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts b/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts
index 929cc808f7..e1d44251b5 100644
--- a/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts
+++ b/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts
@@ -94,21 +94,6 @@ export class FileGenerator {
propertyGroup.ele('SymbolPackageFormat', 'snupkg');
propertyGroup.ele('TargetFramework', TARGET_FRAMEWORK);
- if (dotnetInfo!.signAssembly != null) {
- const signAssembly = propertyGroup.ele('SignAssembly');
- signAssembly.att(
- 'Condition',
- `Exists('${dotnetInfo!.assemblyOriginatorKeyFile}')`,
- );
- }
-
- if (dotnetInfo!.assemblyOriginatorKeyFile != null) {
- propertyGroup.ele(
- 'AssemblyOriginatorKeyFile',
- dotnetInfo!.assemblyOriginatorKeyFile,
- );
- }
-
const itemGroup1 = rootNode.ele('ItemGroup');
const embeddedResource = itemGroup1.ele('EmbeddedResource');
embeddedResource.att('Include', this.tarballFileName);
diff --git a/packages/jsii-pacmak/lib/targets/go.ts b/packages/jsii-pacmak/lib/targets/go.ts
index 478a9e81ef..4b69472b52 100644
--- a/packages/jsii-pacmak/lib/targets/go.ts
+++ b/packages/jsii-pacmak/lib/targets/go.ts
@@ -42,8 +42,12 @@ export class Golang extends Target {
try {
// run `go build` with local.go.mod, go 1.16 requires that we download
- // modules explicit so go.sum is updated.
- await go('mod', ['download', '-modfile', localGoMod.path], {
+ // modules explicit so go.sum is updated. We'd normally want to use
+ // `go mod download`, but because of a bug in go 1.16, we have to use
+ // `go mod tidy` instead.
+ //
+ // See: https://github.com/golang/go/issues/44129
+ await go('mod', ['tidy', '-modfile', localGoMod.path], {
cwd: pkgDir,
});
} catch (e) {
@@ -90,10 +94,11 @@ export class Golang extends Target {
// local build directory for this module. if
// we do, add a "replace" directive to point to it instead of download from
// the network.
- const visit = (pkg: RootPackage) => {
+ const visit = async (pkg: RootPackage) => {
for (const dep of pkg.packageDependencies) {
for (const baseDir of dirs) {
- const moduleDir = tryFindLocalModule(baseDir, dep);
+ // eslint-disable-next-line no-await-in-loop
+ const moduleDir = await tryFindLocalModule(baseDir, dep);
if (moduleDir) {
replace[dep.goModuleName] = moduleDir;
@@ -103,11 +108,12 @@ export class Golang extends Target {
}
// recurse to transitive deps ("replace" is only considered at the top level go.mod)
- visit(dep);
+ // eslint-disable-next-line no-await-in-loop
+ await visit(dep);
}
};
- visit(this.goGenerator.rootPackage);
+ await visit(this.goGenerator.rootPackage);
// write `local.go.mod`
@@ -125,6 +131,7 @@ export class Golang extends Target {
await fs.writeFile(path.join(pkgDir, localGoMod), content, {
encoding: 'utf-8',
});
+
return { path: localGoMod, content };
}
}
@@ -193,14 +200,14 @@ class GoGenerator implements IGenerator {
* @param baseDir the `dist/go` directory
* @returns `undefined` if not or the module directory otherwise.
*/
-function tryFindLocalModule(baseDir: string, pkg: RootPackage) {
+async function tryFindLocalModule(baseDir: string, pkg: RootPackage) {
const gomodPath = path.join(baseDir, pkg.packageName, GOMOD_FILENAME);
- if (!fs.pathExistsSync(gomodPath)) {
+ if (!(await fs.pathExists(gomodPath))) {
return undefined;
}
// read `go.mod` and check that it is for the correct module
- const gomod = fs.readFileSync(gomodPath, 'utf-8').split('\n');
+ const gomod = (await fs.readFile(gomodPath, 'utf-8')).split('\n');
const isExpectedModule = gomod.find(
(line) => line.trim() === `module ${pkg.goModuleName}`,
);
diff --git a/packages/jsii-pacmak/lib/targets/java.ts b/packages/jsii-pacmak/lib/targets/java.ts
index b7d939165f..154ed3dd75 100644
--- a/packages/jsii-pacmak/lib/targets/java.ts
+++ b/packages/jsii-pacmak/lib/targets/java.ts
@@ -5,6 +5,7 @@ import * as fs from 'fs-extra';
import * as reflect from 'jsii-reflect';
import {
Rosetta,
+ TargetLanguage,
typeScriptSnippetFromSource,
Translation,
enforcesStrictMode,
@@ -2916,7 +2917,10 @@ class JavaGenerator extends Generator {
'example',
enforcesStrictMode(this.assembly),
);
- const translated = this.rosetta.translateSnippet(snippet, 'java');
+ const translated = this.rosetta.translateSnippet(
+ snippet,
+ TargetLanguage.JAVA,
+ );
if (!translated) {
return example;
}
@@ -2926,7 +2930,7 @@ class JavaGenerator extends Generator {
private convertSamplesInMarkdown(markdown: string): string {
return this.rosetta.translateSnippetsInMarkdown(
markdown,
- 'java',
+ TargetLanguage.JAVA,
enforcesStrictMode(this.assembly),
(trans) => ({
language: trans.language,
diff --git a/packages/jsii-pacmak/lib/targets/python.ts b/packages/jsii-pacmak/lib/targets/python.ts
index 0a27664e29..9a0ac115eb 100644
--- a/packages/jsii-pacmak/lib/targets/python.ts
+++ b/packages/jsii-pacmak/lib/targets/python.ts
@@ -4,6 +4,7 @@ import * as escapeStringRegexp from 'escape-string-regexp';
import * as fs from 'fs-extra';
import * as reflect from 'jsii-reflect';
import {
+ TargetLanguage,
Translation,
Rosetta,
enforcesStrictMode,
@@ -2290,7 +2291,10 @@ class PythonGenerator extends Generator {
'example',
enforcesStrictMode(this.assembly),
);
- const translated = this.rosetta.translateSnippet(snippet, 'python');
+ const translated = this.rosetta.translateSnippet(
+ snippet,
+ TargetLanguage.PYTHON,
+ );
if (!translated) {
return example;
}
@@ -2300,7 +2304,7 @@ class PythonGenerator extends Generator {
public convertMarkdown(markdown: string): string {
return this.rosetta.translateSnippetsInMarkdown(
markdown,
- 'python',
+ TargetLanguage.PYTHON,
enforcesStrictMode(this.assembly),
(trans) => ({
language: trans.language,
diff --git a/packages/jsii-pacmak/test/generated-code/requirements-dev.txt b/packages/jsii-pacmak/test/generated-code/requirements-dev.txt
index 10316e95bc..13c640f740 100644
--- a/packages/jsii-pacmak/test/generated-code/requirements-dev.txt
+++ b/packages/jsii-pacmak/test/generated-code/requirements-dev.txt
@@ -1 +1 @@
-mypy==0.812
+mypy==0.910
diff --git a/packages/jsii-rosetta/bin/jsii-rosetta.ts b/packages/jsii-rosetta/bin/jsii-rosetta.ts
index 89cb949e75..4e0711074f 100644
--- a/packages/jsii-rosetta/bin/jsii-rosetta.ts
+++ b/packages/jsii-rosetta/bin/jsii-rosetta.ts
@@ -10,6 +10,8 @@ import {
import { translateMarkdown } from '../lib/commands/convert';
import { extractSnippets } from '../lib/commands/extract';
import { readTablet } from '../lib/commands/read';
+import { transliterateAssembly } from '../lib/commands/transliterate';
+import { TargetLanguage } from '../lib/languages';
import { PythonVisitor } from '../lib/languages/python';
import { VisualizeAstVisitor } from '../lib/languages/visualize';
import * as logging from '../lib/logging';
@@ -30,7 +32,7 @@ function main() {
'Translate a single snippet',
(command) =>
command
- .positional('file', {
+ .positional('FILE', {
type: 'string',
describe: 'The file to translate (leave out for stdin)',
})
@@ -41,7 +43,7 @@ function main() {
}),
wrapHandler(async (args) => {
const result = translateTypeScript(
- await makeFileSource(args.file ?? '-', 'stdin.ts'),
+ await makeFileSource(args.FILE ?? '-', 'stdin.ts'),
makeVisitor(args),
);
renderResult(result);
@@ -52,7 +54,7 @@ function main() {
'Translate a MarkDown file',
(command) =>
command
- .positional('file', {
+ .positional('FILE', {
type: 'string',
describe: 'The file to translate (leave out for stdin)',
})
@@ -63,7 +65,7 @@ function main() {
}),
wrapHandler(async (args) => {
const result = translateMarkdown(
- await makeFileSource(args.file ?? '-', 'stdin.md'),
+ await makeFileSource(args.FILE ?? '-', 'stdin.md'),
makeVisitor(args),
);
renderResult(result);
@@ -166,6 +168,68 @@ function main() {
}
}),
)
+ .command(
+ 'transliterate [ASSEMBLY..]',
+ '(EXPERIMENTAL) Transliterates the designated assemblies',
+ (command) =>
+ command
+ .positional('ASSEMBLY', {
+ type: 'string',
+ string: true,
+ default: new Array(),
+ required: true,
+ describe: 'Assembly to transliterate',
+ })
+ .option('language', {
+ alias: 'l',
+ type: 'string',
+ string: true,
+ default: new Array(),
+ describe: 'Language ID to transliterate to',
+ })
+ .options('strict', {
+ alias: 's',
+ conflicts: 'loose',
+ describe:
+ 'Fail if an example that needs live transliteration fails to compile (which could cause incorrect transpilation results)',
+ type: 'boolean',
+ })
+ .options('loose', {
+ alias: 'l',
+ conflicts: 'strict',
+ describe:
+ 'Ignore missing fixtures and literate markdown files instead of failing',
+ type: 'boolean',
+ })
+ .option('tablet', {
+ alias: 't',
+ type: 'string',
+ describe:
+ 'Language tablet containing pre-translated code examples to use (these are generated by the `extract` command)',
+ }),
+ wrapHandler((args) => {
+ const assemblies = (
+ args.ASSEMBLY.length > 0 ? args.ASSEMBLY : ['.']
+ ).map((dir) => path.resolve(process.cwd(), dir));
+ const languages =
+ args.language.length > 0
+ ? args.language.map((lang) => {
+ const target = Object.entries(TargetLanguage).find(
+ ([k]) => k === lang,
+ )?.[1];
+ if (target == null) {
+ throw new Error(
+ `Unknown target language: ${lang}. Expected one of ${Object.keys(
+ TargetLanguage,
+ ).join(', ')}`,
+ );
+ }
+ return target;
+ })
+ : Object.values(TargetLanguage);
+ return transliterateAssembly(assemblies, languages, args);
+ }),
+ )
.command(
'read [KEY] [LANGUAGE]',
'Display snippets in a language tablet file',
diff --git a/packages/jsii-rosetta/jest.config.ts b/packages/jsii-rosetta/jest.config.ts
index e37577d92f..e13e1670b0 100644
--- a/packages/jsii-rosetta/jest.config.ts
+++ b/packages/jsii-rosetta/jest.config.ts
@@ -1,3 +1,7 @@
-import config from '../../jest.config';
+import { join } from 'path';
-export default config;
+import { overriddenConfig } from '../../jest.config';
+
+export default overriddenConfig({
+ setupFiles: [join(__dirname, 'jestsetup.js')],
+});
diff --git a/packages/jsii-rosetta/jestsetup.js b/packages/jsii-rosetta/jestsetup.js
new file mode 100644
index 0000000000..566fd0feb0
--- /dev/null
+++ b/packages/jsii-rosetta/jestsetup.js
@@ -0,0 +1,4 @@
+// Require `mock-fs` before `jest` initializes, as `mock-fs` relies on
+// hijacking the `fs` module, which `jest` also hijacks (and that needs to
+// happen last).
+require('mock-fs');
diff --git a/packages/jsii-rosetta/lib/commands/extract.ts b/packages/jsii-rosetta/lib/commands/extract.ts
index 3ee8f971d2..f3637f7651 100644
--- a/packages/jsii-rosetta/lib/commands/extract.ts
+++ b/packages/jsii-rosetta/lib/commands/extract.ts
@@ -28,6 +28,7 @@ export interface ExtractOptions {
export async function extractSnippets(
assemblyLocations: string[],
options: ExtractOptions,
+ loose = false,
): Promise {
const only = options.only ?? [];
@@ -37,7 +38,7 @@ export async function extractSnippets(
options.validateAssemblies,
);
- let snippets = allTypeScriptSnippets(assemblies);
+ let snippets = allTypeScriptSnippets(assemblies, loose);
if (only.length > 0) {
snippets = filterSnippets(snippets, only);
}
diff --git a/packages/jsii-rosetta/lib/commands/transliterate.ts b/packages/jsii-rosetta/lib/commands/transliterate.ts
new file mode 100644
index 0000000000..2a50f1007f
--- /dev/null
+++ b/packages/jsii-rosetta/lib/commands/transliterate.ts
@@ -0,0 +1,214 @@
+import { Assembly, Docs, SPEC_FILE_NAME, Type, TypeKind } from '@jsii/spec';
+import { readJson, writeJson } from 'fs-extra';
+import { resolve } from 'path';
+
+import { fixturize } from '../fixtures';
+import { TargetLanguage } from '../languages';
+import { debug } from '../logging';
+import { Rosetta } from '../rosetta';
+import { SnippetParameters, typeScriptSnippetFromSource } from '../snippet';
+import { Translation } from '../tablets/tablets';
+
+export interface TransliterateAssemblyOptions {
+ /**
+ * Whether to ignore any missing fixture files or literate markdown documents
+ * referenced by the assembly, instead of failing.
+ *
+ * @default false
+ */
+ readonly loose?: boolean;
+
+ /**
+ * Whether transliteration should fail upon failing to compile an example that
+ * required live transliteration.
+ *
+ * @default false
+ */
+ readonly strict?: boolean;
+
+ /**
+ * A pre-build translation tablet (as produced by `jsii-rosetta extract`).
+ *
+ * @default - Only the default tablet (`.jsii.tabl.json`) files will be used.
+ */
+ readonly tablet?: string;
+}
+
+/**
+ * Prepares transliterated versions of the designated assemblies into the
+ * selected taregt languages.
+ *
+ * @param assemblyLocations the directories which contain assemblies to
+ * transliterate.
+ * @param targetLanguages the languages into which to transliterate.
+ * @param tabletLocation an optional Rosetta tablet file to source
+ * pre-transliterated snippets from.
+ *
+ * @experimental
+ */
+export async function transliterateAssembly(
+ assemblyLocations: readonly string[],
+ targetLanguages: readonly TargetLanguage[],
+ options: TransliterateAssemblyOptions = {},
+): Promise {
+ const rosetta = new Rosetta({
+ includeCompilerDiagnostics: true,
+ liveConversion: true,
+ loose: options.loose,
+ targetLanguages,
+ });
+ if (options.tablet) {
+ await rosetta.loadTabletFromFile(options.tablet);
+ }
+ const assemblies = await loadAssemblies(assemblyLocations, rosetta);
+
+ for (const [location, loadAssembly] of assemblies.entries()) {
+ for (const language of targetLanguages) {
+ const now = new Date().getTime();
+ // eslint-disable-next-line no-await-in-loop
+ const result = await loadAssembly();
+ if (result.readme?.markdown) {
+ result.readme.markdown = rosetta.translateSnippetsInMarkdown(
+ result.readme.markdown,
+ language,
+ true /* strict */,
+ (translation) => ({
+ language: translation.language,
+ source: prefixDisclaimer(translation),
+ }),
+ location,
+ );
+ }
+ for (const type of Object.values(result.types ?? {})) {
+ transliterateType(type, rosetta, language, location, options.loose);
+ }
+ // eslint-disable-next-line no-await-in-loop
+ await writeJson(
+ resolve(location, `${SPEC_FILE_NAME}.${language}`),
+ result,
+ { spaces: 2 },
+ );
+ const then = new Date().getTime();
+ debug(
+ `Done transliterating ${result.name}@${
+ result.version
+ } to ${language} after ${then - now} milliseconds`,
+ );
+ }
+ }
+
+ rosetta.printDiagnostics(process.stderr);
+ if (rosetta.hasErrors && options.strict) {
+ throw new Error(
+ 'Strict mode is enabled and some examples failed compilation!',
+ );
+ }
+}
+
+/**
+ * Given a set of directories containing `.jsii` assemblies, load all the
+ * assemblies into the provided `Rosetta` instance and return a map of
+ * directories to assembly-loading functions (the function re-loads the original
+ * assembly from disk on each invocation).
+ *
+ * @param directories the assembly-containing directories to traverse.
+ * @param rosetta the `Rosetta` instance in which to load assemblies.
+ *
+ * @returns a map of directories to a function that loads the `.jsii` assembly
+ * contained therein from disk.
+ */
+async function loadAssemblies(
+ directories: readonly string[],
+ rosetta: Rosetta,
+): Promise> {
+ const result = new Map();
+
+ for (const directory of directories) {
+ const loader = () => readJson(resolve(directory, SPEC_FILE_NAME));
+ // eslint-disable-next-line no-await-in-loop
+ await rosetta.addAssembly(await loader(), directory);
+ result.set(directory, loader);
+ }
+
+ return result;
+}
+
+type Mutable = { -readonly [K in keyof T]: Mutable };
+type AssemblyLoader = () => Promise>;
+
+function prefixDisclaimer(translation: Translation): string {
+ const message = translation.didCompile
+ ? 'Example automatically generated. See https://github.com/aws/jsii/issues/826'
+ : 'Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826';
+ return `${commentToken()} ${message}\n${translation.source}`;
+
+ function commentToken() {
+ // This is future-proofed a bit, but don't read too much in this...
+ switch (translation.language) {
+ case 'python':
+ case 'ruby':
+ return '#';
+ case 'csharp':
+ case 'java':
+ case 'go':
+ default:
+ return '//';
+ }
+ }
+}
+
+function transliterateType(
+ type: Type,
+ rosetta: Rosetta,
+ language: TargetLanguage,
+ workingDirectory: string,
+ loose = false,
+): void {
+ transliterateDocs(type.docs);
+ switch (type.kind) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore 7029
+ case TypeKind.Class:
+ transliterateDocs(type?.initializer?.docs);
+
+ // fallthrough
+ case TypeKind.Interface:
+ for (const method of type.methods ?? []) {
+ transliterateDocs(method.docs);
+ for (const parameter of method.parameters ?? []) {
+ transliterateDocs(parameter.docs);
+ }
+ }
+ for (const property of type.properties ?? []) {
+ transliterateDocs(property.docs);
+ }
+ break;
+
+ case TypeKind.Enum:
+ for (const member of type.members) {
+ transliterateDocs(member.docs);
+ }
+ break;
+
+ default:
+ throw new Error(`Unsupported type kind: ${(type as any).kind}`);
+ }
+
+ function transliterateDocs(docs: Docs | undefined) {
+ if (docs?.example) {
+ const snippet = fixturize(
+ typeScriptSnippetFromSource(
+ docs.example,
+ 'example',
+ true /* strict */,
+ { [SnippetParameters.$PROJECT_DIRECTORY]: workingDirectory },
+ ),
+ loose,
+ );
+ const translation = rosetta.translateSnippet(snippet, language);
+ if (translation != null) {
+ docs.example = prefixDisclaimer(translation);
+ }
+ }
+ }
+}
diff --git a/packages/jsii-rosetta/lib/fixtures.ts b/packages/jsii-rosetta/lib/fixtures.ts
index b12750361d..09fc28ad07 100644
--- a/packages/jsii-rosetta/lib/fixtures.ts
+++ b/packages/jsii-rosetta/lib/fixtures.ts
@@ -12,7 +12,10 @@ import { TypeScriptSnippet, SnippetParameters } from './snippet';
/**
* Complete snippets with fixtures, if required
*/
-export function fixturize(snippet: TypeScriptSnippet): TypeScriptSnippet {
+export function fixturize(
+ snippet: TypeScriptSnippet,
+ loose = false,
+): TypeScriptSnippet {
let source = snippet.visibleSource;
const parameters = snippet.parameters ?? {};
@@ -25,31 +28,42 @@ export function fixturize(snippet: TypeScriptSnippet): TypeScriptSnippet {
if (literateSource) {
// Compatibility with the "old school" example inclusion mechanism.
// Completely load this file and attach a parameter with its directory.
- source = loadLiterateSource(directory, literateSource);
+ source = loadLiterateSource(directory, literateSource, loose);
parameters[SnippetParameters.$COMPILATION_DIRECTORY] = path.join(
directory,
path.dirname(literateSource),
);
} else if (parameters[SnippetParameters.FIXTURE]) {
- // Explicitly request a fixture
- source = loadAndSubFixture(directory, parameters.fixture, source, true);
+ // Explicitly requested fixture must exist, unless we are operating in loose mode
+ source = loadAndSubFixture(directory, parameters.fixture, source, !loose);
} else if (parameters[SnippetParameters.NO_FIXTURE] === undefined) {
// Don't explicitly request no fixture
source = loadAndSubFixture(directory, 'default', source, false);
}
return {
- visibleSource: snippet.visibleSource,
+ ...snippet,
completeSource: source,
- where: snippet.where,
parameters,
};
}
-function loadLiterateSource(directory: string, literateFileName: string) {
+function loadLiterateSource(
+ directory: string,
+ literateFileName: string,
+ loose = false,
+) {
const fullPath = path.join(directory, literateFileName);
const exists = fs.existsSync(fullPath);
if (!exists) {
+ if (loose) {
+ // In loose mode, we'll fall back to the `.js` file if it exists...
+ const jsFile = fullPath.replace(/\.ts(x?)$/, '.js$1');
+ if (fs.existsSync(jsFile)) {
+ return fs.readFileSync(jsFile, { encoding: 'utf-8' });
+ }
+ return `Missing literate source file ${literateFileName}`;
+ }
// This couldn't really happen in practice, but do the check anyway
throw new Error(
`Sample uses literate source ${literateFileName}, but not found: ${fullPath}`,
diff --git a/packages/jsii-rosetta/lib/index.ts b/packages/jsii-rosetta/lib/index.ts
index 428e2f272f..f26bb05f93 100644
--- a/packages/jsii-rosetta/lib/index.ts
+++ b/packages/jsii-rosetta/lib/index.ts
@@ -1,5 +1,6 @@
export * from './translate';
export { renderTree } from './o-tree';
+export { TargetLanguage } from './languages/target-language';
export { CSharpVisitor } from './languages/csharp';
export { JavaVisitor } from './languages/java';
export { PythonVisitor } from './languages/python';
diff --git a/packages/jsii-rosetta/lib/jsii/assemblies.ts b/packages/jsii-rosetta/lib/jsii/assemblies.ts
index 0f3ab7545a..0b87fea897 100644
--- a/packages/jsii-rosetta/lib/jsii/assemblies.ts
+++ b/packages/jsii-rosetta/lib/jsii/assemblies.ts
@@ -134,6 +134,7 @@ function removeSlashes(x: string) {
export function* allTypeScriptSnippets(
assemblies: readonly LoadedAssembly[],
+ loose = false,
): IterableIterator {
for (const { assembly, directory } of assemblies) {
const strict = enforcesStrictMode(assembly);
@@ -146,7 +147,7 @@ export function* allTypeScriptSnippets(
[SnippetParameters.$PROJECT_DIRECTORY]: directory,
},
);
- yield fixturize(snippet);
+ yield fixturize(snippet, loose);
break;
case 'markdown':
for (const snippet of extractTypescriptSnippetsFromMarkdown(
@@ -157,7 +158,7 @@ export function* allTypeScriptSnippets(
const withDirectory = updateParameters(snippet, {
[SnippetParameters.$PROJECT_DIRECTORY]: directory,
});
- yield fixturize(withDirectory);
+ yield fixturize(withDirectory, loose);
}
}
}
diff --git a/packages/jsii-rosetta/lib/languages/csharp.ts b/packages/jsii-rosetta/lib/languages/csharp.ts
index 88e1bf8baf..4b00a61ee2 100644
--- a/packages/jsii-rosetta/lib/languages/csharp.ts
+++ b/packages/jsii-rosetta/lib/languages/csharp.ts
@@ -23,6 +23,7 @@ import {
} from '../typescript/types';
import { flat, partition, setExtend } from '../util';
import { DefaultVisitor } from './default';
+import { TargetLanguage } from './target-language';
interface CSharpLanguageContext {
/**
@@ -74,7 +75,7 @@ interface CSharpLanguageContext {
type CSharpRenderer = AstRenderer;
export class CSharpVisitor extends DefaultVisitor {
- public readonly language = 'csharp';
+ public readonly language = TargetLanguage.CSHARP;
public readonly defaultContext = {
propertyOrMethod: false,
diff --git a/packages/jsii-rosetta/lib/languages/index.ts b/packages/jsii-rosetta/lib/languages/index.ts
index 5e6759529f..8bfa9c34cd 100644
--- a/packages/jsii-rosetta/lib/languages/index.ts
+++ b/packages/jsii-rosetta/lib/languages/index.ts
@@ -2,8 +2,10 @@ import { AstHandler } from '../renderer';
import { CSharpVisitor } from './csharp';
import { JavaVisitor } from './java';
import { PythonVisitor } from './python';
+import { TargetLanguage } from './target-language';
+
+export { TargetLanguage };
-export type TargetLanguage = 'python' | 'csharp' | 'java';
export type VisitorFactory = () => AstHandler;
export const TARGET_LANGUAGES: { [key in TargetLanguage]: VisitorFactory } = {
diff --git a/packages/jsii-rosetta/lib/languages/java.ts b/packages/jsii-rosetta/lib/languages/java.ts
index ea0bef5328..2ada081a38 100644
--- a/packages/jsii-rosetta/lib/languages/java.ts
+++ b/packages/jsii-rosetta/lib/languages/java.ts
@@ -2,6 +2,7 @@ import * as ts from 'typescript';
import { isStructType } from '../jsii/jsii-utils';
import { jsiiTargetParam } from '../jsii/packages';
+import { TargetLanguage } from '../languages/target-language';
import { OTree, NO_SYNTAX } from '../o-tree';
import { AstRenderer } from '../renderer';
import {
@@ -102,7 +103,7 @@ interface InsideTypeDeclaration {
type JavaRenderer = AstRenderer;
export class JavaVisitor extends DefaultVisitor {
- public readonly language = 'java';
+ public readonly language = TargetLanguage.JAVA;
public readonly defaultContext = {};
public mergeContext(
diff --git a/packages/jsii-rosetta/lib/languages/python.ts b/packages/jsii-rosetta/lib/languages/python.ts
index f058af97e5..9e6749f406 100644
--- a/packages/jsii-rosetta/lib/languages/python.ts
+++ b/packages/jsii-rosetta/lib/languages/python.ts
@@ -7,6 +7,7 @@ import {
structPropertyAcceptsUndefined,
} from '../jsii/jsii-utils';
import { jsiiTargetParam } from '../jsii/packages';
+import { TargetLanguage } from '../languages/target-language';
import { NO_SYNTAX, OTree, renderTree } from '../o-tree';
import { AstRenderer, nimpl, CommentSyntax } from '../renderer';
import {
@@ -86,7 +87,7 @@ export interface PythonVisitorOptions {
}
export class PythonVisitor extends DefaultVisitor {
- public readonly language = 'python';
+ public readonly language = TargetLanguage.PYTHON;
public readonly defaultContext = {};
public constructor(private readonly options: PythonVisitorOptions = {}) {
diff --git a/packages/jsii-rosetta/lib/languages/target-language.ts b/packages/jsii-rosetta/lib/languages/target-language.ts
new file mode 100644
index 0000000000..29c30e963d
--- /dev/null
+++ b/packages/jsii-rosetta/lib/languages/target-language.ts
@@ -0,0 +1,5 @@
+export enum TargetLanguage {
+ PYTHON = 'python',
+ CSHARP = 'csharp',
+ JAVA = 'java',
+}
diff --git a/packages/jsii-rosetta/lib/rosetta.ts b/packages/jsii-rosetta/lib/rosetta.ts
index ffb9385505..afb126107d 100644
--- a/packages/jsii-rosetta/lib/rosetta.ts
+++ b/packages/jsii-rosetta/lib/rosetta.ts
@@ -9,7 +9,11 @@ import { transformMarkdown } from './markdown/markdown';
import { MarkdownRenderer } from './markdown/markdown-renderer';
import { ReplaceTypeScriptTransform } from './markdown/replace-typescript-transform';
import { CodeBlock } from './markdown/types';
-import { TypeScriptSnippet } from './snippet';
+import {
+ SnippetParameters,
+ TypeScriptSnippet,
+ updateParameters,
+} from './snippet';
import {
DEFAULT_TABLET_NAME,
LanguageTablet,
@@ -24,14 +28,27 @@ export interface RosettaOptions {
*
* @default false
*/
- liveConversion?: boolean;
+ readonly liveConversion?: boolean;
/**
* Target languages to use for live conversion
*
* @default All languages
*/
- targetLanguages?: TargetLanguage[];
+ readonly targetLanguages?: readonly TargetLanguage[];
+
+ /**
+ * Whether to include compiler diagnostics in the compilation results.
+ */
+ readonly includeCompilerDiagnostics?: boolean;
+
+ /**
+ * Whether this Rosetta should operate in "loose" mode, where missing literate
+ * source files and missing fixtures are ignored instead of failing.
+ *
+ * @default false
+ */
+ readonly loose?: boolean;
}
/**
@@ -49,10 +66,16 @@ export interface RosettaOptions {
export class Rosetta {
private readonly loadedTablets: LanguageTablet[] = [];
private readonly liveTablet = new LanguageTablet();
- private readonly extractedSnippets: Record = {};
- private readonly translator = new Translator(false);
-
- public constructor(private readonly options: RosettaOptions = {}) {}
+ private readonly extractedSnippets = new Map();
+ private readonly translator: Translator;
+ private readonly loose: boolean;
+
+ public constructor(private readonly options: RosettaOptions = {}) {
+ this.loose = !!options.loose;
+ this.translator = new Translator(
+ options.includeCompilerDiagnostics ?? false,
+ );
+ }
/**
* Diagnostics encountered while doing live translation
@@ -101,10 +124,11 @@ export class Rosetta {
}
if (this.options.liveConversion) {
- for (const tsnip of allTypeScriptSnippets([
- { assembly, directory: assemblyDir },
- ])) {
- this.extractedSnippets[tsnip.visibleSource] = tsnip;
+ for (const tsnip of allTypeScriptSnippets(
+ [{ assembly, directory: assemblyDir }],
+ this.loose,
+ )) {
+ this.extractedSnippets.set(tsnip.visibleSource, tsnip);
}
}
}
@@ -136,7 +160,7 @@ export class Rosetta {
}
// See if we're going to live-convert it with full source information
- const extracted = this.extractedSnippets[source.visibleSource];
+ const extracted = this.extractedSnippets.get(source.visibleSource);
if (extracted !== undefined) {
const snippet = this.translator.translate(
extracted,
@@ -159,12 +183,18 @@ export class Rosetta {
targetLang: TargetLanguage,
strict: boolean,
translationToCodeBlock: (x: Translation) => CodeBlock = id,
+ compileDirectory = process.cwd(),
): string {
return transformMarkdown(
markdown,
new MarkdownRenderer(),
new ReplaceTypeScriptTransform('markdown', strict, (tsSnip) => {
- const translated = this.translateSnippet(tsSnip, targetLang);
+ const translated = this.translateSnippet(
+ updateParameters(tsSnip, {
+ [SnippetParameters.$COMPILATION_DIRECTORY]: compileDirectory,
+ }),
+ targetLang,
+ );
if (!translated) {
return undefined;
}
diff --git a/packages/jsii-rosetta/lib/snippet.ts b/packages/jsii-rosetta/lib/snippet.ts
index 7c447d2f4b..ad23682d72 100644
--- a/packages/jsii-rosetta/lib/snippet.ts
+++ b/packages/jsii-rosetta/lib/snippet.ts
@@ -57,7 +57,11 @@ export function updateParameters(
): TypeScriptSnippet {
return {
...snippet,
- parameters: Object.assign({}, snippet.parameters ?? {}, params),
+ parameters: Object.assign(
+ Object.create(null),
+ snippet.parameters ?? {},
+ params,
+ ),
};
}
diff --git a/packages/jsii-rosetta/lib/tablets/tablets.ts b/packages/jsii-rosetta/lib/tablets/tablets.ts
index 248c367b29..6321b4a189 100644
--- a/packages/jsii-rosetta/lib/tablets/tablets.ts
+++ b/packages/jsii-rosetta/lib/tablets/tablets.ts
@@ -51,7 +51,7 @@ export class LanguageTablet {
if (!obj.toolVersion || !obj.snippets) {
throw new Error(`File '${filename}' does not seem to be a Tablet file`);
}
- if (obj.toolVersion !== TOOL_VERSION) {
+ if (obj.toolVersion !== TOOL_VERSION && TOOL_VERSION !== '0.0.0') {
throw new Error(
`Tablet file '${filename}' has been created with version '${obj.toolVersion}', cannot read with current version '${TOOL_VERSION}'`,
);
diff --git a/packages/jsii-rosetta/lib/translate.ts b/packages/jsii-rosetta/lib/translate.ts
index 20142ba337..9d917f6823 100644
--- a/packages/jsii-rosetta/lib/translate.ts
+++ b/packages/jsii-rosetta/lib/translate.ts
@@ -51,7 +51,7 @@ export class Translator {
public translate(
snip: TypeScriptSnippet,
- languages = Object.keys(TARGET_LANGUAGES) as TargetLanguage[],
+ languages: readonly TargetLanguage[] = Object.values(TargetLanguage),
) {
logging.debug(
`Translating ${snippetKey(snip)} ${inspect(snip.parameters ?? {})}`,
@@ -134,7 +134,8 @@ export class SnippetTranslator {
const source = completeSource(snippet);
const fakeCurrentDirectory =
- snippet.parameters?.[SnippetParameters.$COMPILATION_DIRECTORY];
+ snippet.parameters?.[SnippetParameters.$COMPILATION_DIRECTORY] ??
+ snippet.parameters?.[SnippetParameters.$PROJECT_DIRECTORY];
this.compilation = compiler.compileInMemory(
snippet.where,
source,
diff --git a/packages/jsii-rosetta/lib/util.ts b/packages/jsii-rosetta/lib/util.ts
index b2e326ae01..888cc672bb 100644
--- a/packages/jsii-rosetta/lib/util.ts
+++ b/packages/jsii-rosetta/lib/util.ts
@@ -38,7 +38,7 @@ export function printDiagnostic(
stream.write(message);
}
-const StrictBrand = Symbol('strict');
+export const StrictBrand = 'jsii.strict';
interface MaybeStrictDiagnostic {
readonly [StrictBrand]?: boolean;
}
@@ -46,7 +46,7 @@ interface MaybeStrictDiagnostic {
export function annotateStrictDiagnostic(diag: ts.Diagnostic) {
Object.defineProperty(diag, StrictBrand, {
configurable: false,
- enumerable: false,
+ enumerable: true,
value: true,
writable: false,
});
diff --git a/packages/jsii-rosetta/test/commands/transliterate.test.ts b/packages/jsii-rosetta/test/commands/transliterate.test.ts
new file mode 100644
index 0000000000..6f11824fbb
--- /dev/null
+++ b/packages/jsii-rosetta/test/commands/transliterate.test.ts
@@ -0,0 +1,1241 @@
+import { SPEC_FILE_NAME } from '@jsii/spec';
+import * as fs from 'fs-extra';
+import * as jsii from 'jsii';
+import * as os from 'os';
+import * as path from 'path';
+
+import { transliterateAssembly } from '../../lib/commands/transliterate';
+import { TargetLanguage } from '../../lib/languages/target-language';
+
+jest.setTimeout(60_000);
+
+test('single assembly, all languages', () =>
+ withTemporaryDirectory(async (tmpDir) => {
+ // GIVEN
+ const compilationResult = await jsii.compileJsiiForTest({
+ 'README.md': `
+# README
+\`\`\`ts
+const object: IInterface = new ClassName('this', 1337, { foo: 'bar' });
+object.property = EnumType.OPTION_A;
+object.methodCall();
+
+ClassName.staticMethod(EnumType.OPTION_B);
+\`\`\`
+`,
+ 'index.ts': `
+/**
+ * @example new ClassName('this', 1337, { property: EnumType.OPTION_B });
+ */
+export enum EnumType {
+ /**
+ * @example new ClassName('this', 1337, { property: EnumType.OPTION_A });
+ */
+ OPTION_A = 1,
+
+ /**
+ * @example new ClassName('this', 1337, { property: EnumType.OPTION_B });
+ */
+ OPTION_B = 2,
+}
+
+export interface IInterface {
+ /**
+ * A property value.
+ *
+ * @example
+ * iface.property = EnumType.OPTION_B;
+ */
+ property: EnumType;
+
+ /**
+ * An instance method call.
+ *
+ * @example
+ * iface.methodCall();
+ */
+ methodCall(): void;
+}
+
+export interface ClassNameProps {
+ readonly property?: EnumType;
+ readonly foo?: string;
+}
+
+export class ClassName implements IInterface {
+ /**
+ * A static method. It can be invoked easily.
+ *
+ * @example ClassName.staticMethod();
+ */
+ public static staticMethod(_enm?: EnumType): void {
+ // ...
+ }
+
+ public property: EnumType;
+
+ /**
+ * Create a new instance of ClassName.
+ *
+ * @example new ClassName('this', 1337, { property: EnumType.OPTION_B });
+ */
+ public constructor(_this: string, _elite: number, props: ClassNameProps) {
+ this.property = props.property ?? EnumType.OPTION_A;
+ }
+
+ public methodCall(): void {
+ // ...
+ }
+}`,
+ });
+ fs.writeJsonSync(
+ path.join(tmpDir, SPEC_FILE_NAME),
+ compilationResult.assembly,
+ {
+ spaces: 2,
+ },
+ );
+ for (const [file, content] of Object.entries(compilationResult.files)) {
+ fs.writeFileSync(path.resolve(tmpDir, file), content, 'utf-8');
+ }
+ fs.mkdirSync(path.resolve(tmpDir, 'rosetta'));
+ fs.writeFileSync(
+ path.resolve(tmpDir, 'rosetta', 'default.ts-fixture'),
+ `import { EnumType, IInterface, ClassName } from '.';\ndeclare const iface: IInterface\n/// here`,
+ 'utf-8',
+ );
+
+ // WHEN
+ await expect(
+ transliterateAssembly([tmpDir], Object.values(TargetLanguage), {
+ strict: true,
+ }),
+ ).resolves.not.toThrow();
+
+ // THEN
+ expect(
+ fs.readJsonSync(path.join(tmpDir, `${SPEC_FILE_NAME}.csharp`)),
+ ).toMatchInlineSnapshot(
+ {
+ fingerprint: expect.any(String),
+ jsiiVersion: expect.any(String),
+ },
+ `
+ Object {
+ "author": Object {
+ "name": "John Doe",
+ "roles": Array [
+ "author",
+ ],
+ },
+ "description": "testpkg",
+ "fingerprint": Any,
+ "homepage": "https://github.com/aws/jsii.git",
+ "jsiiVersion": Any,
+ "license": "Apache-2.0",
+ "metadata": Object {
+ "jsii": Object {
+ "pacmak": Object {
+ "hasDefaultInterfaces": true,
+ },
+ },
+ },
+ "name": "testpkg",
+ "readme": Object {
+ "markdown": "# README
+
+ \`\`\`csharp
+ // Example automatically generated. See https://github.com/aws/jsii/issues/826
+ IInterface object = new ClassName(\\"this\\", 1337, new ClassNameProps { Foo = \\"bar\\" });
+ object.Property = EnumType.OPTION_A;
+ object.MethodCall();
+
+ ClassName.StaticMethod(EnumType.OPTION_B);
+ \`\`\`",
+ },
+ "repository": Object {
+ "type": "git",
+ "url": "https://github.com/aws/jsii.git",
+ },
+ "schema": "jsii/0.10.0",
+ "targets": Object {
+ "js": Object {
+ "npm": "testpkg",
+ },
+ },
+ "types": Object {
+ "testpkg.ClassName": Object {
+ "assembly": "testpkg",
+ "fqn": "testpkg.ClassName",
+ "initializer": Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps { Property = EnumType.OPTION_B });",
+ "summary": "Create a new instance of ClassName.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 57,
+ },
+ "parameters": Array [
+ Object {
+ "name": "_this",
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ Object {
+ "name": "_elite",
+ "type": Object {
+ "primitive": "number",
+ },
+ },
+ Object {
+ "name": "props",
+ "type": Object {
+ "fqn": "testpkg.ClassNameProps",
+ },
+ },
+ ],
+ },
+ "interfaces": Array [
+ "testpkg.IInterface",
+ ],
+ "kind": "class",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 40,
+ },
+ "methods": Array [
+ Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName.StaticMethod();",
+ "remarks": "It can be invoked easily.",
+ "summary": "A static method.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 46,
+ },
+ "name": "staticMethod",
+ "parameters": Array [
+ Object {
+ "name": "_enm",
+ "optional": true,
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ "static": true,
+ },
+ Object {
+ "docs": Object {
+ "summary": "An instance method call.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 61,
+ },
+ "name": "methodCall",
+ "overrides": "testpkg.IInterface",
+ },
+ ],
+ "name": "ClassName",
+ "properties": Array [
+ Object {
+ "docs": Object {
+ "summary": "A property value.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 50,
+ },
+ "name": "property",
+ "overrides": "testpkg.IInterface",
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ "testpkg.ClassNameProps": Object {
+ "assembly": "testpkg",
+ "datatype": true,
+ "fqn": "testpkg.ClassNameProps",
+ "kind": "interface",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 35,
+ },
+ "name": "ClassNameProps",
+ "properties": Array [
+ Object {
+ "abstract": true,
+ "immutable": true,
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 37,
+ },
+ "name": "foo",
+ "optional": true,
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ Object {
+ "abstract": true,
+ "immutable": true,
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 36,
+ },
+ "name": "property",
+ "optional": true,
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ "testpkg.EnumType": Object {
+ "assembly": "testpkg",
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps { Property = EnumType.OPTION_B });",
+ },
+ "fqn": "testpkg.EnumType",
+ "kind": "enum",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 5,
+ },
+ "members": Array [
+ Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps { Property = EnumType.OPTION_A });",
+ },
+ "name": "OPTION_A",
+ },
+ Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps { Property = EnumType.OPTION_B });",
+ },
+ "name": "OPTION_B",
+ },
+ ],
+ "name": "EnumType",
+ },
+ "testpkg.IInterface": Object {
+ "assembly": "testpkg",
+ "fqn": "testpkg.IInterface",
+ "kind": "interface",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 17,
+ },
+ "methods": Array [
+ Object {
+ "abstract": true,
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ iface.MethodCall();",
+ "summary": "An instance method call.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 32,
+ },
+ "name": "methodCall",
+ },
+ ],
+ "name": "IInterface",
+ "properties": Array [
+ Object {
+ "abstract": true,
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ iface.Property = EnumType.OPTION_B;",
+ "summary": "A property value.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 24,
+ },
+ "name": "property",
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ },
+ "version": "0.0.1",
+ }
+ `,
+ );
+ expect(
+ fs.readJsonSync(path.join(tmpDir, `${SPEC_FILE_NAME}.java`)),
+ ).toMatchInlineSnapshot(
+ {
+ fingerprint: expect.any(String),
+ jsiiVersion: expect.any(String),
+ },
+ `
+ Object {
+ "author": Object {
+ "name": "John Doe",
+ "roles": Array [
+ "author",
+ ],
+ },
+ "description": "testpkg",
+ "fingerprint": Any,
+ "homepage": "https://github.com/aws/jsii.git",
+ "jsiiVersion": Any,
+ "license": "Apache-2.0",
+ "metadata": Object {
+ "jsii": Object {
+ "pacmak": Object {
+ "hasDefaultInterfaces": true,
+ },
+ },
+ },
+ "name": "testpkg",
+ "readme": Object {
+ "markdown": "# README
+
+ \`\`\`java
+ // Example automatically generated. See https://github.com/aws/jsii/issues/826
+ IInterface object = new ClassName(\\"this\\", 1337, new ClassNameProps().foo(\\"bar\\"));
+ object.getProperty() = EnumType.getOPTION_A();
+ object.methodCall();
+
+ ClassName.staticMethod(EnumType.getOPTION_B());
+ \`\`\`",
+ },
+ "repository": Object {
+ "type": "git",
+ "url": "https://github.com/aws/jsii.git",
+ },
+ "schema": "jsii/0.10.0",
+ "targets": Object {
+ "js": Object {
+ "npm": "testpkg",
+ },
+ },
+ "types": Object {
+ "testpkg.ClassName": Object {
+ "assembly": "testpkg",
+ "fqn": "testpkg.ClassName",
+ "initializer": Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps().property(EnumType.getOPTION_B()));",
+ "summary": "Create a new instance of ClassName.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 57,
+ },
+ "parameters": Array [
+ Object {
+ "name": "_this",
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ Object {
+ "name": "_elite",
+ "type": Object {
+ "primitive": "number",
+ },
+ },
+ Object {
+ "name": "props",
+ "type": Object {
+ "fqn": "testpkg.ClassNameProps",
+ },
+ },
+ ],
+ },
+ "interfaces": Array [
+ "testpkg.IInterface",
+ ],
+ "kind": "class",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 40,
+ },
+ "methods": Array [
+ Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName.staticMethod();",
+ "remarks": "It can be invoked easily.",
+ "summary": "A static method.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 46,
+ },
+ "name": "staticMethod",
+ "parameters": Array [
+ Object {
+ "name": "_enm",
+ "optional": true,
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ "static": true,
+ },
+ Object {
+ "docs": Object {
+ "summary": "An instance method call.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 61,
+ },
+ "name": "methodCall",
+ "overrides": "testpkg.IInterface",
+ },
+ ],
+ "name": "ClassName",
+ "properties": Array [
+ Object {
+ "docs": Object {
+ "summary": "A property value.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 50,
+ },
+ "name": "property",
+ "overrides": "testpkg.IInterface",
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ "testpkg.ClassNameProps": Object {
+ "assembly": "testpkg",
+ "datatype": true,
+ "fqn": "testpkg.ClassNameProps",
+ "kind": "interface",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 35,
+ },
+ "name": "ClassNameProps",
+ "properties": Array [
+ Object {
+ "abstract": true,
+ "immutable": true,
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 37,
+ },
+ "name": "foo",
+ "optional": true,
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ Object {
+ "abstract": true,
+ "immutable": true,
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 36,
+ },
+ "name": "property",
+ "optional": true,
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ "testpkg.EnumType": Object {
+ "assembly": "testpkg",
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps().property(EnumType.getOPTION_B()));",
+ },
+ "fqn": "testpkg.EnumType",
+ "kind": "enum",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 5,
+ },
+ "members": Array [
+ Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps().property(EnumType.getOPTION_A()));",
+ },
+ "name": "OPTION_A",
+ },
+ Object {
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ new ClassName(\\"this\\", 1337, new ClassNameProps().property(EnumType.getOPTION_B()));",
+ },
+ "name": "OPTION_B",
+ },
+ ],
+ "name": "EnumType",
+ },
+ "testpkg.IInterface": Object {
+ "assembly": "testpkg",
+ "fqn": "testpkg.IInterface",
+ "kind": "interface",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 17,
+ },
+ "methods": Array [
+ Object {
+ "abstract": true,
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ iface.methodCall();",
+ "summary": "An instance method call.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 32,
+ },
+ "name": "methodCall",
+ },
+ ],
+ "name": "IInterface",
+ "properties": Array [
+ Object {
+ "abstract": true,
+ "docs": Object {
+ "example": "// Example automatically generated. See https://github.com/aws/jsii/issues/826
+ iface.getProperty() = EnumType.getOPTION_B();",
+ "summary": "A property value.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 24,
+ },
+ "name": "property",
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ },
+ "version": "0.0.1",
+ }
+ `,
+ );
+ expect(
+ fs.readJsonSync(path.join(tmpDir, `${SPEC_FILE_NAME}.python`)),
+ ).toMatchInlineSnapshot(
+ {
+ fingerprint: expect.any(String),
+ jsiiVersion: expect.any(String),
+ },
+ `
+ Object {
+ "author": Object {
+ "name": "John Doe",
+ "roles": Array [
+ "author",
+ ],
+ },
+ "description": "testpkg",
+ "fingerprint": Any,
+ "homepage": "https://github.com/aws/jsii.git",
+ "jsiiVersion": Any,
+ "license": "Apache-2.0",
+ "metadata": Object {
+ "jsii": Object {
+ "pacmak": Object {
+ "hasDefaultInterfaces": true,
+ },
+ },
+ },
+ "name": "testpkg",
+ "readme": Object {
+ "markdown": "# README
+
+ \`\`\`python
+ # Example automatically generated. See https://github.com/aws/jsii/issues/826
+ object = ClassName(\\"this\\", 1337, foo=\\"bar\\")
+ object.property = EnumType.OPTION_A
+ object.method_call()
+
+ ClassName.static_method(EnumType.OPTION_B)
+ \`\`\`",
+ },
+ "repository": Object {
+ "type": "git",
+ "url": "https://github.com/aws/jsii.git",
+ },
+ "schema": "jsii/0.10.0",
+ "targets": Object {
+ "js": Object {
+ "npm": "testpkg",
+ },
+ },
+ "types": Object {
+ "testpkg.ClassName": Object {
+ "assembly": "testpkg",
+ "fqn": "testpkg.ClassName",
+ "initializer": Object {
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName(\\"this\\", 1337, property=EnumType.OPTION_B)",
+ "summary": "Create a new instance of ClassName.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 57,
+ },
+ "parameters": Array [
+ Object {
+ "name": "_this",
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ Object {
+ "name": "_elite",
+ "type": Object {
+ "primitive": "number",
+ },
+ },
+ Object {
+ "name": "props",
+ "type": Object {
+ "fqn": "testpkg.ClassNameProps",
+ },
+ },
+ ],
+ },
+ "interfaces": Array [
+ "testpkg.IInterface",
+ ],
+ "kind": "class",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 40,
+ },
+ "methods": Array [
+ Object {
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName.static_method()",
+ "remarks": "It can be invoked easily.",
+ "summary": "A static method.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 46,
+ },
+ "name": "staticMethod",
+ "parameters": Array [
+ Object {
+ "name": "_enm",
+ "optional": true,
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ "static": true,
+ },
+ Object {
+ "docs": Object {
+ "summary": "An instance method call.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 61,
+ },
+ "name": "methodCall",
+ "overrides": "testpkg.IInterface",
+ },
+ ],
+ "name": "ClassName",
+ "properties": Array [
+ Object {
+ "docs": Object {
+ "summary": "A property value.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 50,
+ },
+ "name": "property",
+ "overrides": "testpkg.IInterface",
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ "testpkg.ClassNameProps": Object {
+ "assembly": "testpkg",
+ "datatype": true,
+ "fqn": "testpkg.ClassNameProps",
+ "kind": "interface",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 35,
+ },
+ "name": "ClassNameProps",
+ "properties": Array [
+ Object {
+ "abstract": true,
+ "immutable": true,
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 37,
+ },
+ "name": "foo",
+ "optional": true,
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ Object {
+ "abstract": true,
+ "immutable": true,
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 36,
+ },
+ "name": "property",
+ "optional": true,
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ "testpkg.EnumType": Object {
+ "assembly": "testpkg",
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName(\\"this\\", 1337, property=EnumType.OPTION_B)",
+ },
+ "fqn": "testpkg.EnumType",
+ "kind": "enum",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 5,
+ },
+ "members": Array [
+ Object {
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName(\\"this\\", 1337, property=EnumType.OPTION_A)",
+ },
+ "name": "OPTION_A",
+ },
+ Object {
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ ClassName(\\"this\\", 1337, property=EnumType.OPTION_B)",
+ },
+ "name": "OPTION_B",
+ },
+ ],
+ "name": "EnumType",
+ },
+ "testpkg.IInterface": Object {
+ "assembly": "testpkg",
+ "fqn": "testpkg.IInterface",
+ "kind": "interface",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 17,
+ },
+ "methods": Array [
+ Object {
+ "abstract": true,
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ iface.method_call()",
+ "summary": "An instance method call.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 32,
+ },
+ "name": "methodCall",
+ },
+ ],
+ "name": "IInterface",
+ "properties": Array [
+ Object {
+ "abstract": true,
+ "docs": Object {
+ "example": "# Example automatically generated. See https://github.com/aws/jsii/issues/826
+ iface.property = EnumType.OPTION_B",
+ "summary": "A property value.",
+ },
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 24,
+ },
+ "name": "property",
+ "type": Object {
+ "fqn": "testpkg.EnumType",
+ },
+ },
+ ],
+ },
+ },
+ "version": "0.0.1",
+ }
+ `,
+ );
+ }));
+
+test('single assembly, loose mode', () =>
+ withTemporaryDirectory(async (tmpDir) => {
+ // GIVEN
+ const compilationResult = await jsii.compileJsiiForTest({
+ 'README.md': `
+# Missing literate source
+
+[example is not found](missing-example.lit.ts)
+
+# Missing fixture
+
+\`\`\`ts fixture=not-found
+new SampleClass('README.md');
+\`\`\`
+`,
+ 'index.ts': `
+/**
+ * @example
+ * /// fixture=not-found
+ * new DoesNotCompile(this, 'That', { foo: 1337 });
+ */
+export class SampleClass {
+ public constructor(_source: string){ }
+}
+`,
+ // The `lit.ts` source file will not be there in packaged form...
+ 'missing-example.lit.ts': `
+import { SampleClass } from './index';
+
+/// !show
+/// ## This is a heading within the literate file!
+new SampleClass('literate');
+ `,
+ });
+ fs.writeJsonSync(
+ path.join(tmpDir, SPEC_FILE_NAME),
+ compilationResult.assembly,
+ {
+ spaces: 2,
+ },
+ );
+ for (const [file, content] of Object.entries(compilationResult.files)) {
+ fs.writeFileSync(path.resolve(tmpDir, file), content, 'utf-8');
+ }
+
+ // WHEN
+ await expect(
+ transliterateAssembly([tmpDir], Object.values(TargetLanguage), {
+ loose: true,
+ }),
+ ).resolves.not.toThrow();
+
+ // THEN
+ expect(
+ fs.readJsonSync(path.join(tmpDir, `${SPEC_FILE_NAME}.csharp`)),
+ ).toMatchInlineSnapshot(
+ {
+ fingerprint: expect.any(String),
+ jsiiVersion: expect.any(String),
+ },
+ `
+ Object {
+ "author": Object {
+ "name": "John Doe",
+ "roles": Array [
+ "author",
+ ],
+ },
+ "description": "testpkg",
+ "fingerprint": Any,
+ "homepage": "https://github.com/aws/jsii.git",
+ "jsiiVersion": Any,
+ "license": "Apache-2.0",
+ "metadata": Object {
+ "jsii": Object {
+ "pacmak": Object {
+ "hasDefaultInterfaces": true,
+ },
+ },
+ },
+ "name": "testpkg",
+ "readme": Object {
+ "markdown": "# Missing literate source
+
+ ## This is a heading within the literate file!
+
+ \`\`\`csharp
+ // Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ new index_1.SampleClass(\\"literate\\");
+ \`\`\`
+
+ # Missing fixture
+
+ \`\`\`csharp
+ // Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ new SampleClass(\\"README.md\\");
+ \`\`\`",
+ },
+ "repository": Object {
+ "type": "git",
+ "url": "https://github.com/aws/jsii.git",
+ },
+ "schema": "jsii/0.10.0",
+ "targets": Object {
+ "js": Object {
+ "npm": "testpkg",
+ },
+ },
+ "types": Object {
+ "testpkg.SampleClass": Object {
+ "assembly": "testpkg",
+ "docs": Object {
+ "example": "// Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ new DoesNotCompile(this, \\"That\\", new Struct { Foo = 1337 });",
+ },
+ "fqn": "testpkg.SampleClass",
+ "initializer": Object {
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 8,
+ },
+ "parameters": Array [
+ Object {
+ "name": "_source",
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ ],
+ },
+ "kind": "class",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 7,
+ },
+ "name": "SampleClass",
+ },
+ },
+ "version": "0.0.1",
+ }
+ `,
+ );
+
+ expect(
+ fs.readJsonSync(path.join(tmpDir, `${SPEC_FILE_NAME}.java`)),
+ ).toMatchInlineSnapshot(
+ {
+ fingerprint: expect.any(String),
+ jsiiVersion: expect.any(String),
+ },
+ `
+ Object {
+ "author": Object {
+ "name": "John Doe",
+ "roles": Array [
+ "author",
+ ],
+ },
+ "description": "testpkg",
+ "fingerprint": Any,
+ "homepage": "https://github.com/aws/jsii.git",
+ "jsiiVersion": Any,
+ "license": "Apache-2.0",
+ "metadata": Object {
+ "jsii": Object {
+ "pacmak": Object {
+ "hasDefaultInterfaces": true,
+ },
+ },
+ },
+ "name": "testpkg",
+ "readme": Object {
+ "markdown": "# Missing literate source
+
+ ## This is a heading within the literate file!
+
+ \`\`\`java
+ // Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ new SampleClass(\\"literate\\");
+ \`\`\`
+
+ # Missing fixture
+
+ \`\`\`java
+ // Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ new SampleClass(\\"README.md\\");
+ \`\`\`",
+ },
+ "repository": Object {
+ "type": "git",
+ "url": "https://github.com/aws/jsii.git",
+ },
+ "schema": "jsii/0.10.0",
+ "targets": Object {
+ "js": Object {
+ "npm": "testpkg",
+ },
+ },
+ "types": Object {
+ "testpkg.SampleClass": Object {
+ "assembly": "testpkg",
+ "docs": Object {
+ "example": "// Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ DoesNotCompile.Builder.create(this, \\"That\\").foo(1337).build();",
+ },
+ "fqn": "testpkg.SampleClass",
+ "initializer": Object {
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 8,
+ },
+ "parameters": Array [
+ Object {
+ "name": "_source",
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ ],
+ },
+ "kind": "class",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 7,
+ },
+ "name": "SampleClass",
+ },
+ },
+ "version": "0.0.1",
+ }
+ `,
+ );
+
+ expect(
+ fs.readJsonSync(path.join(tmpDir, `${SPEC_FILE_NAME}.python`)),
+ ).toMatchInlineSnapshot(
+ {
+ fingerprint: expect.any(String),
+ jsiiVersion: expect.any(String),
+ },
+ `
+ Object {
+ "author": Object {
+ "name": "John Doe",
+ "roles": Array [
+ "author",
+ ],
+ },
+ "description": "testpkg",
+ "fingerprint": Any,
+ "homepage": "https://github.com/aws/jsii.git",
+ "jsiiVersion": Any,
+ "license": "Apache-2.0",
+ "metadata": Object {
+ "jsii": Object {
+ "pacmak": Object {
+ "hasDefaultInterfaces": true,
+ },
+ },
+ },
+ "name": "testpkg",
+ "readme": Object {
+ "markdown": "# Missing literate source
+
+ ## This is a heading within the literate file!
+
+ \`\`\`python
+ # Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ index_1.SampleClass(\\"literate\\")
+ \`\`\`
+
+ # Missing fixture
+
+ \`\`\`python
+ # Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ SampleClass(\\"README.md\\")
+ \`\`\`",
+ },
+ "repository": Object {
+ "type": "git",
+ "url": "https://github.com/aws/jsii.git",
+ },
+ "schema": "jsii/0.10.0",
+ "targets": Object {
+ "js": Object {
+ "npm": "testpkg",
+ },
+ },
+ "types": Object {
+ "testpkg.SampleClass": Object {
+ "assembly": "testpkg",
+ "docs": Object {
+ "example": "# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
+ DoesNotCompile(self, \\"That\\", foo=1337)",
+ },
+ "fqn": "testpkg.SampleClass",
+ "initializer": Object {
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 8,
+ },
+ "parameters": Array [
+ Object {
+ "name": "_source",
+ "type": Object {
+ "primitive": "string",
+ },
+ },
+ ],
+ },
+ "kind": "class",
+ "locationInModule": Object {
+ "filename": "index.ts",
+ "line": 7,
+ },
+ "name": "SampleClass",
+ },
+ },
+ "version": "0.0.1",
+ }
+ `,
+ );
+ }));
+
+async function withTemporaryDirectory(
+ callback: (dir: string) => Promise,
+): Promise {
+ const tmpdir = fs.mkdtempSync(
+ path.join(os.tmpdir(), path.basename(__filename)),
+ );
+ return callback(tmpdir).finally(() => fs.removeSync(tmpdir));
+}
diff --git a/packages/jsii-rosetta/test/fixtures.test.ts b/packages/jsii-rosetta/test/fixtures.test.ts
new file mode 100644
index 0000000000..92e9f9ff7c
--- /dev/null
+++ b/packages/jsii-rosetta/test/fixtures.test.ts
@@ -0,0 +1,19 @@
+import { fixturize } from '../lib/fixtures';
+import { SnippetParameters } from '../lib/snippet';
+
+describe('fixturize', () => {
+ test('snippet retains properties', () => {
+ const snippet = {
+ visibleSource: 'visibleSource',
+ where: 'where',
+ parameters: {
+ [SnippetParameters.$PROJECT_DIRECTORY]: 'directory',
+ [SnippetParameters.NO_FIXTURE]: '',
+ key: 'value',
+ },
+ strict: true,
+ };
+
+ expect(fixturize(snippet)).toEqual(expect.objectContaining(snippet));
+ });
+});
diff --git a/packages/jsii-rosetta/test/rosetta.test.ts b/packages/jsii-rosetta/test/rosetta.test.ts
index c9bcb7e920..dadcc54130 100644
--- a/packages/jsii-rosetta/test/rosetta.test.ts
+++ b/packages/jsii-rosetta/test/rosetta.test.ts
@@ -19,11 +19,14 @@ test('Rosetta object can do live translation', () => {
// GIVEN
const rosetta = new Rosetta({
liveConversion: true,
- targetLanguages: ['python'],
+ targetLanguages: [TargetLanguage.PYTHON],
});
// WHEN
- const translated = rosetta.translateSnippet(SAMPLE_CODE, 'python');
+ const translated = rosetta.translateSnippet(
+ SAMPLE_CODE,
+ TargetLanguage.PYTHON,
+ );
// THEN
expect(translated).toMatchObject({
@@ -47,7 +50,10 @@ test('Can use preloaded tablet', () => {
rosetta.addTablet(tablet);
// WHEN
- const translated = rosetta.translateSnippet(SAMPLE_CODE, 'python');
+ const translated = rosetta.translateSnippet(
+ SAMPLE_CODE,
+ TargetLanguage.PYTHON,
+ );
// THEN
expect(translated).toMatchObject({
@@ -60,11 +66,14 @@ test('Rosetta object can do live translation', () => {
// GIVEN
const rosetta = new Rosetta({
liveConversion: true,
- targetLanguages: ['python'],
+ targetLanguages: [TargetLanguage.PYTHON],
});
// WHEN
- const translated = rosetta.translateSnippet(SAMPLE_CODE, 'python');
+ const translated = rosetta.translateSnippet(
+ SAMPLE_CODE,
+ TargetLanguage.PYTHON,
+ );
// THEN
expect(translated).toMatchObject({
@@ -77,7 +86,7 @@ test('Rosetta object can do translation and annotation of snippets in MarkDown',
// GIVEN
const rosetta = new Rosetta({
liveConversion: true,
- targetLanguages: ['python'],
+ targetLanguages: [TargetLanguage.PYTHON],
});
// WHEN
@@ -91,7 +100,7 @@ test('Rosetta object can do translation and annotation of snippets in MarkDown',
'```',
'That was it, thank you for your attention.',
].join('\n'),
- 'python',
+ TargetLanguage.PYTHON,
false,
(trans) => {
return {
@@ -142,7 +151,10 @@ describe('with mocked filesystem', () => {
// WHEN
const rosetta = new Rosetta();
await rosetta.loadTabletFromFile('/test.tablet');
- const translated = rosetta.translateSnippet(SAMPLE_CODE, 'python');
+ const translated = rosetta.translateSnippet(
+ SAMPLE_CODE,
+ TargetLanguage.PYTHON,
+ );
// THEN
expect(translated).toMatchObject({
@@ -158,7 +170,10 @@ describe('with mocked filesystem', () => {
// WHEN
const rosetta = new Rosetta();
await rosetta.addAssembly(fakeAssembly({}), '/');
- const translated = rosetta.translateSnippet(SAMPLE_CODE, 'python');
+ const translated = rosetta.translateSnippet(
+ SAMPLE_CODE,
+ TargetLanguage.PYTHON,
+ );
// THEN
expect(translated).toMatchObject({
diff --git a/packages/jsii-rosetta/test/util.test.ts b/packages/jsii-rosetta/test/util.test.ts
new file mode 100644
index 0000000000..c565782502
--- /dev/null
+++ b/packages/jsii-rosetta/test/util.test.ts
@@ -0,0 +1,65 @@
+import * as ts from 'typescript';
+
+import {
+ StrictBrand,
+ annotateStrictDiagnostic,
+ isErrorDiagnostic,
+} from '../lib/util';
+
+describe(annotateStrictDiagnostic, () => {
+ const diagnostic = {
+ category: ts.DiagnosticCategory.Error,
+ code: 999,
+ messageText: 'messageText',
+ file: undefined,
+ start: undefined,
+ length: undefined,
+ };
+
+ test('adds strict property', () => {
+ annotateStrictDiagnostic(diagnostic);
+
+ expect(diagnostic).toHaveProperty([StrictBrand]);
+ });
+});
+
+describe(isErrorDiagnostic, () => {
+ const warningDiagnostic = makeDiagnostic(ts.DiagnosticCategory.Warning);
+ const errorDiagnostic = makeDiagnostic(ts.DiagnosticCategory.Error);
+ const strictErrorDiagnostic = {
+ ...makeDiagnostic(ts.DiagnosticCategory.Error),
+ [StrictBrand]: true,
+ };
+ const diagnostics = [
+ warningDiagnostic,
+ errorDiagnostic,
+ strictErrorDiagnostic,
+ ];
+
+ test('returns all error diagnostics if onlyStrict is false', () => {
+ const onlyStrict = false;
+
+ expect(
+ diagnostics.filter((diag) => isErrorDiagnostic(diag, { onlyStrict })),
+ ).toStrictEqual([errorDiagnostic, strictErrorDiagnostic]);
+ });
+
+ test('returns only strict error diagnostics if onlyStrict is true', () => {
+ const onlyStrict = true;
+
+ expect(
+ diagnostics.filter((diag) => isErrorDiagnostic(diag, { onlyStrict })),
+ ).toStrictEqual([strictErrorDiagnostic]);
+ });
+});
+
+function makeDiagnostic(category: ts.DiagnosticCategory): ts.Diagnostic {
+ return {
+ category: category,
+ code: 999,
+ messageText: 'messageText',
+ file: undefined,
+ start: undefined,
+ length: undefined,
+ };
+}
diff --git a/yarn.lock b/yarn.lock
index 7c15155408..f0949d74f2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8821,9 +8821,9 @@ write-pkg@^4.0.0:
write-json-file "^3.2.0"
ws@^7.4.4:
- version "7.4.5"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1"
- integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==
+ version "7.4.6"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
+ integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
xml-name-validator@^3.0.0:
version "3.0.0"