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"