diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index 7d76adb320..45f08fe91e 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -24,7 +24,7 @@ jobs: DEFAULT_NODE_MAJOR_VERSION: 12 steps: - name: Check out - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2.4.0 # Determine if we should run the validation or not - name: Should this run? diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index da65a1d7e2..2d3b74ad0e 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -21,7 +21,7 @@ jobs: with: python-version: '3.8' - name: Check out - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2.4.0 - name: Locate Caches id: cache-locations run: |- @@ -58,7 +58,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2.4.0 with: ref: gh-pages token: ${{ secrets.AUTO_APPROVE_GITHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 67ee3a571e..688c4518b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: steps: # Check out the code - name: Check out - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2.4.0 # Set up all of our standard runtimes - name: Set up .NET 5 uses: actions/setup-dotnet@v1 @@ -119,7 +119,7 @@ jobs: steps: # Check out the code - name: Check out - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2.4.0 # Set up all of our standard runtimes - name: Set up .NET 5 uses: actions/setup-dotnet@v1 diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 8fc1342dbc..9b597bde76 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -11,7 +11,8 @@ jobs: runs-on: ubuntu-latest permissions: pull-requests: write + issues: write steps: - run: gh pr edit ${{ github.event.pull_request.number }} --add-label "pr/auto-approve" -R ${{ github.repository }} env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index 6f2f8d769d..95fda35aac 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Check Out - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2.4.0 - name: Set up Node uses: actions/setup-node@v2.4.1 @@ -115,7 +115,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check Out - uses: actions/checkout@v2 + uses: actions/checkout@v2.4.0 - name: Download patch uses: actions/download-artifact@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 26fec9e68e..9c2c10ed96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ 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.44.0](https://github.com/aws/jsii/compare/v1.43.0...v1.44.0) (2021-11-15) + + +### Features + +* **rosetta:** expose the 'extract' API ([#3161](https://github.com/aws/jsii/issues/3161)) ([c3b30c0](https://github.com/aws/jsii/commit/c3b30c093515e8bce4922eed1a88536e8c2080e8)) + + +### Bug Fixes + +* dependency submodules may not be discovered ([#3151](https://github.com/aws/jsii/issues/3151)) ([5768bb9](https://github.com/aws/jsii/commit/5768bb9951856f4a051c24db7f56d23fd8573815)) +* deprecation warnings are generated even when one property is not deprecated ([#3157](https://github.com/aws/jsii/issues/3157)) ([e566f37](https://github.com/aws/jsii/commit/e566f37802438a929d66448c1d67b7a2c2e901a1)) +* **jsii:** incorrectly allowed unexported type in constructor params ([#3147](https://github.com/aws/jsii/issues/3147)) ([7cd59fc](https://github.com/aws/jsii/commit/7cd59fc180648b6c4b873364ef301b3228e69885)) +* **pacmak:** remove disclaimer on compiling examples ([#3148](https://github.com/aws/jsii/issues/3148)) ([75e4093](https://github.com/aws/jsii/commit/75e4093af9123f50b2ba92c1f70be6e9a2ed46b6)) +* **pacmak:** Support more than 255 properties for interfaces in Java ([#3133](https://github.com/aws/jsii/issues/3133)) ([ba4a20d](https://github.com/aws/jsii/commit/ba4a20df41e7298ba6518652a5046deaac490c3b)), closes [#3132](https://github.com/aws/jsii/issues/3132) [#3132](https://github.com/aws/jsii/issues/3132) +* **rosetta:** `didCompile` evaluates to true when compilation not attempted ([#3149](https://github.com/aws/jsii/issues/3149)) ([7ad9e0a](https://github.com/aws/jsii/commit/7ad9e0a9013316e730b89bdf3b9934ec0174c742)) +* **rosetta:** cache source file parses ([#3163](https://github.com/aws/jsii/issues/3163)) ([307d3ca](https://github.com/aws/jsii/commit/307d3ca09b6a2d1bae2754b9aaf1be98e77d016f)) +* **rosetta:** gets confused by type unions ([#3156](https://github.com/aws/jsii/issues/3156)) ([ca04dad](https://github.com/aws/jsii/commit/ca04dad3f54981d59177309b2d5c7626256ca3a9)) +* **rosetta:** snippet throughput incorrect ([#3145](https://github.com/aws/jsii/issues/3145)) ([91418d6](https://github.com/aws/jsii/commit/91418d60d5a0b10a32579a3393139d6f04853cde)) + ## [1.43.0](https://github.com/aws/jsii/compare/v1.42.0...v1.43.0) (2021-11-08) diff --git a/gh-pages/requirements-dev.txt b/gh-pages/requirements-dev.txt index 46f768e929..fa6c5b31c1 100644 --- a/gh-pages/requirements-dev.txt +++ b/gh-pages/requirements-dev.txt @@ -1,4 +1,4 @@ mkdocs~=1.2.3 mkdocs-awesome-pages-plugin~=2.6.0 -mkdocs-material~=7.3.2 +mkdocs-material~=7.3.6 mkdocs-git-revision-date-plugin~=0.3.1 diff --git a/lerna.json b/lerna.json index 04d06d604c..7feca2c485 100644 --- a/lerna.json +++ b/lerna.json @@ -3,12 +3,13 @@ "npmClient": "yarn", "useWorkspaces": true, "packages": [ - "packages/*" + "packages/*", + "regression-tests/@*/*" ], "command": { "bootstrap": { "rejectCycles": true } }, - "version": "1.43.0" + "version": "1.44.0" } diff --git a/package.json b/package.json index 90690b0f36..a663eca198 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "packages/*", "packages/@jsii/*", "packages/@scope/*", + "regression-tests/@*/*", "tools/*" ], "nohoist": [ diff --git a/packages/@jsii/Directory.Build.targets b/packages/@jsii/Directory.Build.targets index ae2682be84..5df07af12a 100644 --- a/packages/@jsii/Directory.Build.targets +++ b/packages/@jsii/Directory.Build.targets @@ -2,7 +2,7 @@ - + @@ -14,7 +14,7 @@ - + diff --git a/packages/@jsii/python-runtime/requirements.txt b/packages/@jsii/python-runtime/requirements.txt index aef6e3bbf6..825f29a79d 100644 --- a/packages/@jsii/python-runtime/requirements.txt +++ b/packages/@jsii/python-runtime/requirements.txt @@ -3,7 +3,7 @@ mypy==0.812 pip~=21.3 pytest~=6.2 pytest-mypy~=0.8 -setuptools~=58.2 +setuptools~=58.5 wheel~=0.37 -e . diff --git a/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts b/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts index 70711df95d..4b336c235c 100644 --- a/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts +++ b/packages/jsii-pacmak/lib/targets/dotnet/dotnetdocgenerator.ts @@ -10,10 +10,7 @@ import { } from 'jsii-rosetta'; import * as xmlbuilder from 'xmlbuilder'; -import { - INCOMPLETE_DISCLAIMER_COMPILING, - INCOMPLETE_DISCLAIMER_NONCOMPILING, -} from '..'; +import { INCOMPLETE_DISCLAIMER_NONCOMPILING } from '..'; import { renderSummary } from '../_utils'; import { DotNetNameUtils } from './nameutils'; @@ -188,9 +185,6 @@ export class DotNetDocGenerator { } private prefixDisclaimer(translated: Translation) { - if (translated.didCompile && INCOMPLETE_DISCLAIMER_COMPILING) { - return `// ${INCOMPLETE_DISCLAIMER_COMPILING}\n${translated.source}`; - } if (!translated.didCompile && INCOMPLETE_DISCLAIMER_NONCOMPILING) { return `// ${INCOMPLETE_DISCLAIMER_NONCOMPILING}\n${translated.source}`; } diff --git a/packages/jsii-pacmak/lib/targets/index.ts b/packages/jsii-pacmak/lib/targets/index.ts index 3e8f1d5b66..f404d02eb2 100644 --- a/packages/jsii-pacmak/lib/targets/index.ts +++ b/packages/jsii-pacmak/lib/targets/index.ts @@ -35,7 +35,5 @@ export const ALL_BUILDERS: { [key in TargetName]: BuilderFactory } = { new IndependentPackageBuilder(TargetName.PYTHON, Python, ms, o), }; -export const INCOMPLETE_DISCLAIMER_COMPILING = - 'Example automatically generated. See https://github.com/aws/jsii/issues/826'; export const INCOMPLETE_DISCLAIMER_NONCOMPILING = - 'Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826'; + 'Example automatically generated from non-compiling source. May contain errors.'; diff --git a/packages/jsii-pacmak/lib/targets/java.ts b/packages/jsii-pacmak/lib/targets/java.ts index f2bac01704..6b6351900a 100644 --- a/packages/jsii-pacmak/lib/targets/java.ts +++ b/packages/jsii-pacmak/lib/targets/java.ts @@ -30,11 +30,7 @@ import { VERSION, VERSION_DESC } from '../version'; import { stabilityPrefixFor, renderSummary } from './_utils'; import { toMavenVersionRange, toReleaseVersion } from './version-utils'; -import { - INCOMPLETE_DISCLAIMER_COMPILING, - INCOMPLETE_DISCLAIMER_NONCOMPILING, - TargetName, -} from '.'; +import { INCOMPLETE_DISCLAIMER_NONCOMPILING, TargetName } from '.'; // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports const spdxLicenseList = require('spdx-license-list'); @@ -2021,7 +2017,7 @@ class JavaGenerator extends Generator { ); props.forEach((prop) => - this.code.line(`private ${prop.fieldJavaType} ${prop.fieldName};`), + this.code.line(`${prop.fieldJavaType} ${prop.fieldName};`), ); props.forEach((prop) => this.emitBuilderSetter(prop, BUILDER_CLASS_NAME, classSpec), @@ -2040,9 +2036,7 @@ class JavaGenerator extends Generator { this.code.line('@Override'); this.code.openBlock(`public ${classSpec.name} build()`); - const propFields = props.map((prop) => prop.fieldName).join(', '); - - this.code.line(`return new ${constructorName}(${propFields});`); + this.code.line(`return new ${constructorName}(this);`); this.code.closeBlock(); // End build() @@ -2116,7 +2110,7 @@ class JavaGenerator extends Generator { this.code.closeBlock(); // End JSII reference constructor - // Start literal constructor + // Start builder constructor this.code.line(); this.code.line('/**'); this.code.line( @@ -2126,11 +2120,8 @@ class JavaGenerator extends Generator { if (props.some((prop) => prop.fieldJavaType !== prop.paramJavaType)) { this.code.line('@SuppressWarnings("unchecked")'); } - const constructorArgs = props - .map((prop) => `final ${prop.paramJavaType} ${prop.fieldName}`) - .join(', '); this.code.openBlock( - `protected ${INTERFACE_PROXY_CLASS_NAME}(${constructorArgs})`, + `protected ${INTERFACE_PROXY_CLASS_NAME}(final ${BUILDER_CLASS_NAME} builder)`, ); this.code.line( 'super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);', @@ -2142,7 +2133,7 @@ class JavaGenerator extends Generator { : ''; this.code.line( `this.${prop.fieldName} = ${explicitCast}${_validateIfNonOptional( - prop.fieldName, + `builder.${prop.fieldName}`, prop, )};`, ); @@ -3013,9 +3004,6 @@ class JavaGenerator extends Generator { } private prefixDisclaimer(translated: Translation) { - if (translated.didCompile && INCOMPLETE_DISCLAIMER_COMPILING) { - return `// ${INCOMPLETE_DISCLAIMER_COMPILING}\n${translated.source}`; - } if (!translated.didCompile && INCOMPLETE_DISCLAIMER_NONCOMPILING) { return `// ${INCOMPLETE_DISCLAIMER_NONCOMPILING}\n${translated.source}`; } diff --git a/packages/jsii-pacmak/lib/targets/python.ts b/packages/jsii-pacmak/lib/targets/python.ts index 077f8cec90..b8c6a84763 100644 --- a/packages/jsii-pacmak/lib/targets/python.ts +++ b/packages/jsii-pacmak/lib/targets/python.ts @@ -29,11 +29,7 @@ import { import { die, toPythonIdentifier } from './python/util'; import { toPythonVersionRange, toReleaseVersion } from './version-utils'; -import { - INCOMPLETE_DISCLAIMER_COMPILING, - INCOMPLETE_DISCLAIMER_NONCOMPILING, - TargetName, -} from '.'; +import { INCOMPLETE_DISCLAIMER_NONCOMPILING, TargetName } from '.'; // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports const spdxLicenseList = require('spdx-license-list'); @@ -2400,9 +2396,6 @@ class PythonGenerator extends Generator { } private prefixDisclaimer(translated: Translation) { - if (translated.didCompile && INCOMPLETE_DISCLAIMER_COMPILING) { - return `# ${INCOMPLETE_DISCLAIMER_COMPILING}\n${translated.source}`; - } if (!translated.didCompile && INCOMPLETE_DISCLAIMER_NONCOMPILING) { return `# ${INCOMPLETE_DISCLAIMER_NONCOMPILING}\n${translated.source}`; } diff --git a/packages/jsii-pacmak/lib/targets/python/requirements-dev.txt b/packages/jsii-pacmak/lib/targets/python/requirements-dev.txt index 7c5285d49a..ff95e1d96e 100644 --- a/packages/jsii-pacmak/lib/targets/python/requirements-dev.txt +++ b/packages/jsii-pacmak/lib/targets/python/requirements-dev.txt @@ -3,7 +3,7 @@ # be installed in the virtual environment used for building the distribution # package (wheel, sdist), but not declared as build-system dependencies. -setuptools~=58.3.0 # build-system +setuptools~=58.5.3 # build-system wheel~=0.37.0 # build-system -twine~=3.4.2 +twine~=3.5.0 diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/examples.test.ts.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/examples.test.ts.snap index 1f67e89b33..c4f1ca905f 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/examples.test.ts.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/examples.test.ts.snap @@ -731,9 +731,9 @@ public interface Baz extends software.amazon.jsii.JsiiSerializable, example.test * A builder for {@link Baz} */ public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Boolean baz; - private java.lang.Number foo; - private java.lang.String bar; + java.lang.Boolean baz; + java.lang.Number foo; + java.lang.String bar; /** * Sets the value of {@link Baz#getBaz} @@ -772,7 +772,7 @@ public interface Baz extends software.amazon.jsii.JsiiSerializable, example.test */ @Override public Baz build() { - return new Jsii$Proxy(baz, foo, bar); + return new Jsii$Proxy(this); } } @@ -799,11 +799,11 @@ public interface Baz extends software.amazon.jsii.JsiiSerializable, example.test /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Boolean baz, final java.lang.Number foo, final java.lang.String bar) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.baz = java.util.Objects.requireNonNull(baz, "baz is required"); - this.foo = java.util.Objects.requireNonNull(foo, "foo is required"); - this.bar = bar; + this.baz = java.util.Objects.requireNonNull(builder.baz, "baz is required"); + this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required"); + this.bar = builder.bar; } @Override @@ -909,7 +909,7 @@ public interface Foo extends software.amazon.jsii.JsiiSerializable { * A builder for {@link Foo} */ public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Number foo; + java.lang.Number foo; /** * Sets the value of {@link Foo#getFoo} @@ -928,7 +928,7 @@ public interface Foo extends software.amazon.jsii.JsiiSerializable { */ @Override public Foo build() { - return new Jsii$Proxy(foo); + return new Jsii$Proxy(this); } } @@ -951,9 +951,9 @@ public interface Foo extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Number foo) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.foo = java.util.Objects.requireNonNull(foo, "foo is required"); + this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required"); } @Override @@ -1023,8 +1023,8 @@ public interface FooBar extends software.amazon.jsii.JsiiSerializable { * A builder for {@link FooBar} */ public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Number foo; - private java.lang.String bar; + java.lang.Number foo; + java.lang.String bar; /** * Sets the value of {@link FooBar#getFoo} @@ -1053,7 +1053,7 @@ public interface FooBar extends software.amazon.jsii.JsiiSerializable { */ @Override public FooBar build() { - return new Jsii$Proxy(foo, bar); + return new Jsii$Proxy(this); } } @@ -1078,10 +1078,10 @@ public interface FooBar extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Number foo, final java.lang.String bar) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.foo = java.util.Objects.requireNonNull(foo, "foo is required"); - this.bar = bar; + this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required"); + this.bar = builder.bar; } @Override @@ -1147,7 +1147,7 @@ testpkg.FooBar=example.test.demo.FooBar exports[`diamond-struct-parameter.ts: /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -2247,7 +2247,7 @@ public class Namespace1 extends software.amazon.jsii.JsiiObject { * A builder for {@link Foo} */ public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String bar; + java.lang.String bar; /** * Sets the value of {@link Foo#getBar} @@ -2266,7 +2266,7 @@ public class Namespace1 extends software.amazon.jsii.JsiiObject { */ @Override public Foo build() { - return new Jsii$Proxy(bar); + return new Jsii$Proxy(this); } } @@ -2289,9 +2289,9 @@ public class Namespace1 extends software.amazon.jsii.JsiiObject { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String bar) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.bar = java.util.Objects.requireNonNull(bar, "bar is required"); + this.bar = java.util.Objects.requireNonNull(builder.bar, "bar is required"); } @Override @@ -2447,7 +2447,7 @@ testpkg.Namespace2.Foo.Final=example.test.demo.Namespace2$Foo.Final exports[`nested-types.ts: /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/prerelease-identifiers.test.ts.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/prerelease-identifiers.test.ts.snap index a0cef5e205..cf54ff1ed1 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/prerelease-identifiers.test.ts.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/prerelease-identifiers.test.ts.snap @@ -416,7 +416,7 @@ foo exports[`foo@1.2.3 depends on bar@^2.0.0-rc.42: /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -925,7 +925,7 @@ foo exports[`foo@1.2.3 depends on bar@^4.5.6-pre.1337: /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -1414,7 +1414,7 @@ foo exports[`foo@2.0.0-rc.42: /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -1900,7 +1900,7 @@ foo exports[`foo@4.5.6-pre.1337: /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.ts.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.ts.snap index 6e9756aa9e..812245c6e1 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.ts.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.ts.snap @@ -4129,7 +4129,6 @@ namespace Amazon.JSII.Tests.CalculatorNamespace /// Here's how you use it: /// /// /// - /// // Example automatically generated. See https://github.com/aws/jsii/issues/826 - /// Calculator calculator = new Calculator(); + /// Calculator calculator = new Calculator(); /// calculator.Add(5); /// calculator.Mul(3); /// Console.WriteLine(calculator.Expression.Value); @@ -4699,8 +4697,7 @@ namespace Amazon.JSII.Tests.CalculatorNamespace /// CustomAttribute: hasAValue /// /// - /// // Example automatically generated. See https://github.com/aws/jsii/issues/826 - /// public void AnExample() + /// public void AnExample() /// { /// } /// @@ -6233,8 +6230,7 @@ namespace Amazon.JSII.Tests.CalculatorNamespace /// Multiple paragraphs are separated by an empty line. /// /// - /// // Example automatically generated. See https://github.com/aws/jsii/issues/826 - /// int x = 12 + 44; + /// int x = 12 + 44; /// string s1 = "string"; /// string s2 = @"string /// with new newlines"; // see https://github.com/aws/jsii/issues/2569 @@ -13780,21 +13776,18 @@ namespace Amazon.JSII.Tests.CalculatorNamespace /// First, create a calculator: /// /// /// /// Then call some operations: /// /// /// ///

Code Samples

/// /// diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.ts.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.ts.snap index e15d97d6a0..cef9f9ae79 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.ts.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.ts.snap @@ -538,8 +538,8 @@ public interface BaseProps extends software.amazon.jsii.JsiiSerializable, softwa * A builder for {@link BaseProps} */ public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String bar; - private software.amazon.jsii.tests.calculator.baseofbase.Very foo; + java.lang.String bar; + software.amazon.jsii.tests.calculator.baseofbase.Very foo; /** * Sets the value of {@link BaseProps#getBar} @@ -568,7 +568,7 @@ public interface BaseProps extends software.amazon.jsii.JsiiSerializable, softwa */ @Override public BaseProps build() { - return new Jsii$Proxy(bar, foo); + return new Jsii$Proxy(this); } } @@ -593,10 +593,10 @@ public interface BaseProps extends software.amazon.jsii.JsiiSerializable, softwa /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String bar, final software.amazon.jsii.tests.calculator.baseofbase.Very foo) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.bar = java.util.Objects.requireNonNull(bar, "bar is required"); - this.foo = java.util.Objects.requireNonNull(foo, "foo is required"); + this.bar = java.util.Objects.requireNonNull(builder.bar, "bar is required"); + this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required"); } @Override @@ -1301,7 +1301,7 @@ public interface VeryBaseProps extends software.amazon.jsii.JsiiSerializable { * A builder for {@link VeryBaseProps} */ public static final class Builder implements software.amazon.jsii.Builder { - private software.amazon.jsii.tests.calculator.baseofbase.Very foo; + software.amazon.jsii.tests.calculator.baseofbase.Very foo; /** * Sets the value of {@link VeryBaseProps#getFoo} @@ -1320,7 +1320,7 @@ public interface VeryBaseProps extends software.amazon.jsii.JsiiSerializable { */ @Override public VeryBaseProps build() { - return new Jsii$Proxy(foo); + return new Jsii$Proxy(this); } } @@ -1343,9 +1343,9 @@ public interface VeryBaseProps extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final software.amazon.jsii.tests.calculator.baseofbase.Very foo) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.foo = java.util.Objects.requireNonNull(foo, "foo is required"); + this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required"); } @Override @@ -1954,7 +1954,7 @@ public class NestingClass extends software.amazon.jsii.JsiiObject { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String name; + java.lang.String name; /** * Sets the value of {@link NestedStruct#getName} @@ -1977,7 +1977,7 @@ public class NestingClass extends software.amazon.jsii.JsiiObject { @Deprecated @Override public NestedStruct build() { - return new Jsii$Proxy(name); + return new Jsii$Proxy(this); } } @@ -2002,9 +2002,9 @@ public class NestingClass extends software.amazon.jsii.JsiiObject { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String name) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.name = java.util.Objects.requireNonNull(name, "name is required"); + this.name = java.util.Objects.requireNonNull(builder.name, "name is required"); } @Override @@ -2089,8 +2089,8 @@ public interface ReflectableEntry extends software.amazon.jsii.JsiiSerializable @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String key; - private java.lang.Object value; + java.lang.String key; + java.lang.Object value; /** * Sets the value of {@link ReflectableEntry#getKey} @@ -2125,7 +2125,7 @@ public interface ReflectableEntry extends software.amazon.jsii.JsiiSerializable @Deprecated @Override public ReflectableEntry build() { - return new Jsii$Proxy(key, value); + return new Jsii$Proxy(this); } } @@ -2152,10 +2152,10 @@ public interface ReflectableEntry extends software.amazon.jsii.JsiiSerializable /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String key, final java.lang.Object value) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.key = java.util.Objects.requireNonNull(key, "key is required"); - this.value = java.util.Objects.requireNonNull(value, "value is required"); + this.key = java.util.Objects.requireNonNull(builder.key, "key is required"); + this.value = java.util.Objects.requireNonNull(builder.value, "value is required"); } @Override @@ -2419,8 +2419,8 @@ public interface DiamondLeft extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String hoistedTop; - private java.lang.Number left; + java.lang.String hoistedTop; + java.lang.Number left; /** * Sets the value of {@link DiamondLeft#getHoistedTop} @@ -2455,7 +2455,7 @@ public interface DiamondLeft extends software.amazon.jsii.JsiiSerializable { @Deprecated @Override public DiamondLeft build() { - return new Jsii$Proxy(hoistedTop, left); + return new Jsii$Proxy(this); } } @@ -2482,10 +2482,10 @@ public interface DiamondLeft extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String hoistedTop, final java.lang.Number left) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.hoistedTop = hoistedTop; - this.left = left; + this.hoistedTop = builder.hoistedTop; + this.left = builder.left; } @Override @@ -2585,8 +2585,8 @@ public interface DiamondRight extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String hoistedTop; - private java.lang.Boolean right; + java.lang.String hoistedTop; + java.lang.Boolean right; /** * Sets the value of {@link DiamondRight#getHoistedTop} @@ -2621,7 +2621,7 @@ public interface DiamondRight extends software.amazon.jsii.JsiiSerializable { @Deprecated @Override public DiamondRight build() { - return new Jsii$Proxy(hoistedTop, right); + return new Jsii$Proxy(this); } } @@ -2648,10 +2648,10 @@ public interface DiamondRight extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String hoistedTop, final java.lang.Boolean right) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.hoistedTop = hoistedTop; - this.right = right; + this.hoistedTop = builder.hoistedTop; + this.right = builder.right; } @Override @@ -2985,9 +2985,9 @@ public interface MyFirstStruct extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Number anumber; - private java.lang.String astring; - private java.util.List firstOptional; + java.lang.Number anumber; + java.lang.String astring; + java.util.List firstOptional; /** * Sets the value of {@link MyFirstStruct#getAnumber} @@ -3034,7 +3034,7 @@ public interface MyFirstStruct extends software.amazon.jsii.JsiiSerializable { @Deprecated @Override public MyFirstStruct build() { - return new Jsii$Proxy(anumber, astring, firstOptional); + return new Jsii$Proxy(this); } } @@ -3063,11 +3063,11 @@ public interface MyFirstStruct extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Number anumber, final java.lang.String astring, final java.util.List firstOptional) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.anumber = java.util.Objects.requireNonNull(anumber, "anumber is required"); - this.astring = java.util.Objects.requireNonNull(astring, "astring is required"); - this.firstOptional = firstOptional; + this.anumber = java.util.Objects.requireNonNull(builder.anumber, "anumber is required"); + this.astring = java.util.Objects.requireNonNull(builder.astring, "astring is required"); + this.firstOptional = builder.firstOptional; } @Override @@ -3368,9 +3368,9 @@ public interface StructWithOnlyOptionals extends software.amazon.jsii.JsiiSerial @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String optional1; - private java.lang.Number optional2; - private java.lang.Boolean optional3; + java.lang.String optional1; + java.lang.Number optional2; + java.lang.Boolean optional3; /** * Sets the value of {@link StructWithOnlyOptionals#getOptional1} @@ -3417,7 +3417,7 @@ public interface StructWithOnlyOptionals extends software.amazon.jsii.JsiiSerial @Deprecated @Override public StructWithOnlyOptionals build() { - return new Jsii$Proxy(optional1, optional2, optional3); + return new Jsii$Proxy(this); } } @@ -3446,11 +3446,11 @@ public interface StructWithOnlyOptionals extends software.amazon.jsii.JsiiSerial /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String optional1, final java.lang.Number optional2, final java.lang.Boolean optional3) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.optional1 = optional1; - this.optional2 = optional2; - this.optional3 = optional3; + this.optional1 = builder.optional1; + this.optional2 = builder.optional2; + this.optional3 = builder.optional3; } @Override @@ -5612,7 +5612,6 @@ package software.amazon.jsii.tests.calculator; * Here's how you use it: *

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * Calculator calculator = new Calculator();
  * calculator.add(5);
  * calculator.mul(3);
@@ -5624,7 +5623,6 @@ package software.amazon.jsii.tests.calculator;
  * Example:
  * 

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * Calculator calculator = new Calculator();
  * calculator.add(5);
  * calculator.mul(3);
@@ -5915,8 +5913,8 @@ public interface CalculatorProps extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number initialValue;
-        private java.lang.Number maximumValue;
+        java.lang.Number initialValue;
+        java.lang.Number maximumValue;
 
         /**
          * Sets the value of {@link CalculatorProps#getInitialValue}
@@ -5949,7 +5947,7 @@ public interface CalculatorProps extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public CalculatorProps build() {
-            return new Jsii$Proxy(initialValue, maximumValue);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -5975,10 +5973,10 @@ public interface CalculatorProps extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number initialValue, final java.lang.Number maximumValue) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.initialValue = initialValue;
-            this.maximumValue = maximumValue;
+            this.initialValue = builder.initialValue;
+            this.maximumValue = builder.maximumValue;
         }
 
         @Override
@@ -6064,8 +6062,8 @@ public interface ChildStruct982 extends software.amazon.jsii.JsiiSerializable, s
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number bar;
-        private java.lang.String foo;
+        java.lang.Number bar;
+        java.lang.String foo;
 
         /**
          * Sets the value of {@link ChildStruct982#getBar}
@@ -6097,7 +6095,7 @@ public interface ChildStruct982 extends software.amazon.jsii.JsiiSerializable, s
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public ChildStruct982 build() {
-            return new Jsii$Proxy(bar, foo);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -6123,10 +6121,10 @@ public interface ChildStruct982 extends software.amazon.jsii.JsiiSerializable, s
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number bar, final java.lang.String foo) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.bar = java.util.Objects.requireNonNull(bar, "bar is required");
-            this.foo = java.util.Objects.requireNonNull(foo, "foo is required");
+            this.bar = java.util.Objects.requireNonNull(builder.bar, "bar is required");
+            this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required");
         }
 
         @Override
@@ -6625,7 +6623,6 @@ package software.amazon.jsii.tests.calculator;
  * Example:
  * 

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * public void anExample() {
  * }
  * 
@@ -6888,7 +6885,7 @@ public interface ConfusingToJacksonStruct extends software.amazon.jsii.JsiiSeria */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Object unionProperty; + java.lang.Object unionProperty; /** * Sets the value of {@link ConfusingToJacksonStruct#getUnionProperty} @@ -6920,7 +6917,7 @@ public interface ConfusingToJacksonStruct extends software.amazon.jsii.JsiiSeria @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public ConfusingToJacksonStruct build() { - return new Jsii$Proxy(unionProperty); + return new Jsii$Proxy(this); } } @@ -6944,9 +6941,9 @@ public interface ConfusingToJacksonStruct extends software.amazon.jsii.JsiiSeria /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Object unionProperty) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.unionProperty = unionProperty; + this.unionProperty = builder.unionProperty; } @Override @@ -7351,9 +7348,9 @@ public interface ContainerProps extends software.amazon.jsii.JsiiSerializable { */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.util.List arrayProp; - private java.util.Map objProp; - private java.util.Map recordProp; + java.util.List arrayProp; + java.util.Map objProp; + java.util.Map recordProp; /** * Sets the value of {@link ContainerProps#getArrayProp} @@ -7399,7 +7396,7 @@ public interface ContainerProps extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public ContainerProps build() { - return new Jsii$Proxy(arrayProp, objProp, recordProp); + return new Jsii$Proxy(this); } } @@ -7428,11 +7425,11 @@ public interface ContainerProps extends software.amazon.jsii.JsiiSerializable { * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ @SuppressWarnings("unchecked") - protected Jsii$Proxy(final java.util.List arrayProp, final java.util.Map objProp, final java.util.Map recordProp) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.arrayProp = (java.util.List)java.util.Objects.requireNonNull(arrayProp, "arrayProp is required"); - this.objProp = (java.util.Map)java.util.Objects.requireNonNull(objProp, "objProp is required"); - this.recordProp = (java.util.Map)java.util.Objects.requireNonNull(recordProp, "recordProp is required"); + this.arrayProp = (java.util.List)java.util.Objects.requireNonNull(builder.arrayProp, "arrayProp is required"); + this.objProp = (java.util.Map)java.util.Objects.requireNonNull(builder.objProp, "objProp is required"); + this.recordProp = (java.util.Map)java.util.Objects.requireNonNull(builder.recordProp, "recordProp is required"); } @Override @@ -7866,7 +7863,7 @@ public interface DeprecatedStruct extends software.amazon.jsii.JsiiSerializable @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Deprecated) @Deprecated public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String readonlyProperty; + java.lang.String readonlyProperty; /** * Sets the value of {@link DeprecatedStruct#getReadonlyProperty} @@ -7890,7 +7887,7 @@ public interface DeprecatedStruct extends software.amazon.jsii.JsiiSerializable @Deprecated @Override public DeprecatedStruct build() { - return new Jsii$Proxy(readonlyProperty); + return new Jsii$Proxy(this); } } @@ -7915,9 +7912,9 @@ public interface DeprecatedStruct extends software.amazon.jsii.JsiiSerializable /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String readonlyProperty) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.readonlyProperty = java.util.Objects.requireNonNull(readonlyProperty, "readonlyProperty is required"); + this.readonlyProperty = java.util.Objects.requireNonNull(builder.readonlyProperty, "readonlyProperty is required"); } @Override @@ -8025,15 +8022,15 @@ public interface DerivedStruct extends software.amazon.jsii.JsiiSerializable, so */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.time.Instant anotherRequired; - private java.lang.Boolean bool; - private software.amazon.jsii.tests.calculator.DoubleTrouble nonPrimitive; - private java.util.Map anotherOptional; - private java.lang.Object optionalAny; - private java.util.List optionalArray; - private java.lang.Number anumber; - private java.lang.String astring; - private java.util.List firstOptional; + java.time.Instant anotherRequired; + java.lang.Boolean bool; + software.amazon.jsii.tests.calculator.DoubleTrouble nonPrimitive; + java.util.Map anotherOptional; + java.lang.Object optionalAny; + java.util.List optionalArray; + java.lang.Number anumber; + java.lang.String astring; + java.util.List firstOptional; /** * Sets the value of {@link DerivedStruct#getAnotherRequired} @@ -8146,7 +8143,7 @@ public interface DerivedStruct extends software.amazon.jsii.JsiiSerializable, so @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public DerivedStruct build() { - return new Jsii$Proxy(anotherRequired, bool, nonPrimitive, anotherOptional, optionalAny, optionalArray, anumber, astring, firstOptional); + return new Jsii$Proxy(this); } } @@ -8187,17 +8184,17 @@ public interface DerivedStruct extends software.amazon.jsii.JsiiSerializable, so * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ @SuppressWarnings("unchecked") - protected Jsii$Proxy(final java.time.Instant anotherRequired, final java.lang.Boolean bool, final software.amazon.jsii.tests.calculator.DoubleTrouble nonPrimitive, final java.util.Map anotherOptional, final java.lang.Object optionalAny, final java.util.List optionalArray, final java.lang.Number anumber, final java.lang.String astring, final java.util.List firstOptional) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.anotherRequired = java.util.Objects.requireNonNull(anotherRequired, "anotherRequired is required"); - this.bool = java.util.Objects.requireNonNull(bool, "bool is required"); - this.nonPrimitive = java.util.Objects.requireNonNull(nonPrimitive, "nonPrimitive is required"); - this.anotherOptional = (java.util.Map)anotherOptional; - this.optionalAny = optionalAny; - this.optionalArray = optionalArray; - this.anumber = java.util.Objects.requireNonNull(anumber, "anumber is required"); - this.astring = java.util.Objects.requireNonNull(astring, "astring is required"); - this.firstOptional = firstOptional; + this.anotherRequired = java.util.Objects.requireNonNull(builder.anotherRequired, "anotherRequired is required"); + this.bool = java.util.Objects.requireNonNull(builder.bool, "bool is required"); + this.nonPrimitive = java.util.Objects.requireNonNull(builder.nonPrimitive, "nonPrimitive is required"); + this.anotherOptional = (java.util.Map)builder.anotherOptional; + this.optionalAny = builder.optionalAny; + this.optionalArray = builder.optionalArray; + this.anumber = java.util.Objects.requireNonNull(builder.anumber, "anumber is required"); + this.astring = java.util.Objects.requireNonNull(builder.astring, "astring is required"); + this.firstOptional = builder.firstOptional; } @Override @@ -8354,10 +8351,10 @@ public interface DiamondBottom extends software.amazon.jsii.JsiiSerializable, so */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.time.Instant bottom; - private java.lang.String hoistedTop; - private java.lang.Number left; - private java.lang.Boolean right; + java.time.Instant bottom; + java.lang.String hoistedTop; + java.lang.Number left; + java.lang.Boolean right; /** * Sets the value of {@link DiamondBottom#getBottom} @@ -8414,7 +8411,7 @@ public interface DiamondBottom extends software.amazon.jsii.JsiiSerializable, so @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public DiamondBottom build() { - return new Jsii$Proxy(bottom, hoistedTop, left, right); + return new Jsii$Proxy(this); } } @@ -8444,12 +8441,12 @@ public interface DiamondBottom extends software.amazon.jsii.JsiiSerializable, so /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.time.Instant bottom, final java.lang.String hoistedTop, final java.lang.Number left, final java.lang.Boolean right) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.bottom = bottom; - this.hoistedTop = hoistedTop; - this.left = left; - this.right = right; + this.bottom = builder.bottom; + this.hoistedTop = builder.hoistedTop; + this.left = builder.left; + this.right = builder.right; } @Override @@ -8555,7 +8552,7 @@ public interface DiamondInheritanceBaseLevelStruct extends software.amazon.jsii. */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String baseLevelProperty; + java.lang.String baseLevelProperty; /** * Sets the value of {@link DiamondInheritanceBaseLevelStruct#getBaseLevelProperty} @@ -8576,7 +8573,7 @@ public interface DiamondInheritanceBaseLevelStruct extends software.amazon.jsii. @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public DiamondInheritanceBaseLevelStruct build() { - return new Jsii$Proxy(baseLevelProperty); + return new Jsii$Proxy(this); } } @@ -8600,9 +8597,9 @@ public interface DiamondInheritanceBaseLevelStruct extends software.amazon.jsii. /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String baseLevelProperty) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.baseLevelProperty = java.util.Objects.requireNonNull(baseLevelProperty, "baseLevelProperty is required"); + this.baseLevelProperty = java.util.Objects.requireNonNull(builder.baseLevelProperty, "baseLevelProperty is required"); } @Override @@ -8676,8 +8673,8 @@ public interface DiamondInheritanceFirstMidLevelStruct extends software.amazon.j */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String firstMidLevelProperty; - private java.lang.String baseLevelProperty; + java.lang.String firstMidLevelProperty; + java.lang.String baseLevelProperty; /** * Sets the value of {@link DiamondInheritanceFirstMidLevelStruct#getFirstMidLevelProperty} @@ -8709,7 +8706,7 @@ public interface DiamondInheritanceFirstMidLevelStruct extends software.amazon.j @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public DiamondInheritanceFirstMidLevelStruct build() { - return new Jsii$Proxy(firstMidLevelProperty, baseLevelProperty); + return new Jsii$Proxy(this); } } @@ -8735,10 +8732,10 @@ public interface DiamondInheritanceFirstMidLevelStruct extends software.amazon.j /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String firstMidLevelProperty, final java.lang.String baseLevelProperty) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.firstMidLevelProperty = java.util.Objects.requireNonNull(firstMidLevelProperty, "firstMidLevelProperty is required"); - this.baseLevelProperty = java.util.Objects.requireNonNull(baseLevelProperty, "baseLevelProperty is required"); + this.firstMidLevelProperty = java.util.Objects.requireNonNull(builder.firstMidLevelProperty, "firstMidLevelProperty is required"); + this.baseLevelProperty = java.util.Objects.requireNonNull(builder.baseLevelProperty, "baseLevelProperty is required"); } @Override @@ -8820,8 +8817,8 @@ public interface DiamondInheritanceSecondMidLevelStruct extends software.amazon. */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String secondMidLevelProperty; - private java.lang.String baseLevelProperty; + java.lang.String secondMidLevelProperty; + java.lang.String baseLevelProperty; /** * Sets the value of {@link DiamondInheritanceSecondMidLevelStruct#getSecondMidLevelProperty} @@ -8853,7 +8850,7 @@ public interface DiamondInheritanceSecondMidLevelStruct extends software.amazon. @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public DiamondInheritanceSecondMidLevelStruct build() { - return new Jsii$Proxy(secondMidLevelProperty, baseLevelProperty); + return new Jsii$Proxy(this); } } @@ -8879,10 +8876,10 @@ public interface DiamondInheritanceSecondMidLevelStruct extends software.amazon. /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String secondMidLevelProperty, final java.lang.String baseLevelProperty) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.secondMidLevelProperty = java.util.Objects.requireNonNull(secondMidLevelProperty, "secondMidLevelProperty is required"); - this.baseLevelProperty = java.util.Objects.requireNonNull(baseLevelProperty, "baseLevelProperty is required"); + this.secondMidLevelProperty = java.util.Objects.requireNonNull(builder.secondMidLevelProperty, "secondMidLevelProperty is required"); + this.baseLevelProperty = java.util.Objects.requireNonNull(builder.baseLevelProperty, "baseLevelProperty is required"); } @Override @@ -8969,10 +8966,10 @@ public interface DiamondInheritanceTopLevelStruct extends software.amazon.jsii.J */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String topLevelProperty; - private java.lang.String firstMidLevelProperty; - private java.lang.String baseLevelProperty; - private java.lang.String secondMidLevelProperty; + java.lang.String topLevelProperty; + java.lang.String firstMidLevelProperty; + java.lang.String baseLevelProperty; + java.lang.String secondMidLevelProperty; /** * Sets the value of {@link DiamondInheritanceTopLevelStruct#getTopLevelProperty} @@ -9026,7 +9023,7 @@ public interface DiamondInheritanceTopLevelStruct extends software.amazon.jsii.J @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public DiamondInheritanceTopLevelStruct build() { - return new Jsii$Proxy(topLevelProperty, firstMidLevelProperty, baseLevelProperty, secondMidLevelProperty); + return new Jsii$Proxy(this); } } @@ -9056,12 +9053,12 @@ public interface DiamondInheritanceTopLevelStruct extends software.amazon.jsii.J /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String topLevelProperty, final java.lang.String firstMidLevelProperty, final java.lang.String baseLevelProperty, final java.lang.String secondMidLevelProperty) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.topLevelProperty = java.util.Objects.requireNonNull(topLevelProperty, "topLevelProperty is required"); - this.firstMidLevelProperty = java.util.Objects.requireNonNull(firstMidLevelProperty, "firstMidLevelProperty is required"); - this.baseLevelProperty = java.util.Objects.requireNonNull(baseLevelProperty, "baseLevelProperty is required"); - this.secondMidLevelProperty = java.util.Objects.requireNonNull(secondMidLevelProperty, "secondMidLevelProperty is required"); + this.topLevelProperty = java.util.Objects.requireNonNull(builder.topLevelProperty, "topLevelProperty is required"); + this.firstMidLevelProperty = java.util.Objects.requireNonNull(builder.firstMidLevelProperty, "firstMidLevelProperty is required"); + this.baseLevelProperty = java.util.Objects.requireNonNull(builder.baseLevelProperty, "baseLevelProperty is required"); + this.secondMidLevelProperty = java.util.Objects.requireNonNull(builder.secondMidLevelProperty, "secondMidLevelProperty is required"); } @Override @@ -9298,7 +9295,6 @@ package software.amazon.jsii.tests.calculator; * Example: *

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * Number x = 12 + 44;
  * String s1 = "string";
  * String s2 = "string \\nwith new newlines"; // see https://github.com/aws/jsii/issues/2569
@@ -9477,7 +9473,7 @@ public interface DummyObj extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String example;
+        java.lang.String example;
 
         /**
          * Sets the value of {@link DummyObj#getExample}
@@ -9498,7 +9494,7 @@ public interface DummyObj extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public DummyObj build() {
-            return new Jsii$Proxy(example);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -9522,9 +9518,9 @@ public interface DummyObj extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String example) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.example = java.util.Objects.requireNonNull(example, "example is required");
+            this.example = java.util.Objects.requireNonNull(builder.example, "example is required");
         }
 
         @Override
@@ -9882,8 +9878,8 @@ public interface EraseUndefinedHashValuesOptions extends software.amazon.jsii.Js
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String option1;
-        private java.lang.String option2;
+        java.lang.String option1;
+        java.lang.String option2;
 
         /**
          * Sets the value of {@link EraseUndefinedHashValuesOptions#getOption1}
@@ -9915,7 +9911,7 @@ public interface EraseUndefinedHashValuesOptions extends software.amazon.jsii.Js
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public EraseUndefinedHashValuesOptions build() {
-            return new Jsii$Proxy(option1, option2);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -9941,10 +9937,10 @@ public interface EraseUndefinedHashValuesOptions extends software.amazon.jsii.Js
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String option1, final java.lang.String option2) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.option1 = option1;
-            this.option2 = option2;
+            this.option1 = builder.option1;
+            this.option2 = builder.option2;
         }
 
         @Override
@@ -10119,7 +10115,7 @@ public interface ExperimentalStruct extends software.amazon.jsii.JsiiSerializabl
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String readonlyProperty;
+        java.lang.String readonlyProperty;
 
         /**
          * Sets the value of {@link ExperimentalStruct#getReadonlyProperty}
@@ -10140,7 +10136,7 @@ public interface ExperimentalStruct extends software.amazon.jsii.JsiiSerializabl
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental)
         @Override
         public ExperimentalStruct build() {
-            return new Jsii$Proxy(readonlyProperty);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -10164,9 +10160,9 @@ public interface ExperimentalStruct extends software.amazon.jsii.JsiiSerializabl
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String readonlyProperty) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.readonlyProperty = java.util.Objects.requireNonNull(readonlyProperty, "readonlyProperty is required");
+            this.readonlyProperty = java.util.Objects.requireNonNull(builder.readonlyProperty, "readonlyProperty is required");
         }
 
         @Override
@@ -10282,8 +10278,8 @@ public interface ExtendsInternalInterface extends software.amazon.jsii.JsiiSeria
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Boolean boom;
-        private java.lang.String prop;
+        java.lang.Boolean boom;
+        java.lang.String prop;
 
         /**
          * Sets the value of {@link ExtendsInternalInterface#getBoom}
@@ -10315,7 +10311,7 @@ public interface ExtendsInternalInterface extends software.amazon.jsii.JsiiSeria
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public ExtendsInternalInterface build() {
-            return new Jsii$Proxy(boom, prop);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -10341,10 +10337,10 @@ public interface ExtendsInternalInterface extends software.amazon.jsii.JsiiSeria
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Boolean boom, final java.lang.String prop) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.boom = java.util.Objects.requireNonNull(boom, "boom is required");
-            this.prop = java.util.Objects.requireNonNull(prop, "prop is required");
+            this.boom = java.util.Objects.requireNonNull(builder.boom, "boom is required");
+            this.prop = java.util.Objects.requireNonNull(builder.prop, "prop is required");
         }
 
         @Override
@@ -10515,7 +10511,7 @@ public interface ExternalStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String readonlyProperty;
+        java.lang.String readonlyProperty;
 
         /**
          * Sets the value of {@link ExternalStruct#getReadonlyProperty}
@@ -10536,7 +10532,7 @@ public interface ExternalStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public ExternalStruct build() {
-            return new Jsii$Proxy(readonlyProperty);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -10560,9 +10556,9 @@ public interface ExternalStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String readonlyProperty) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.readonlyProperty = java.util.Objects.requireNonNull(readonlyProperty, "readonlyProperty is required");
+            this.readonlyProperty = java.util.Objects.requireNonNull(builder.readonlyProperty, "readonlyProperty is required");
         }
 
         @Override
@@ -10708,7 +10704,7 @@ public interface Greetee extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String name;
+        java.lang.String name;
 
         /**
          * Sets the value of {@link Greetee#getName}
@@ -10729,7 +10725,7 @@ public interface Greetee extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public Greetee build() {
-            return new Jsii$Proxy(name);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -10753,9 +10749,9 @@ public interface Greetee extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String name) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.name = name;
+            this.name = builder.name;
         }
 
         @Override
@@ -13781,9 +13777,9 @@ public interface ImplictBaseOfBase extends software.amazon.jsii.JsiiSerializable
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.time.Instant goo;
-        private java.lang.String bar;
-        private software.amazon.jsii.tests.calculator.baseofbase.Very foo;
+        java.time.Instant goo;
+        java.lang.String bar;
+        software.amazon.jsii.tests.calculator.baseofbase.Very foo;
 
         /**
          * Sets the value of {@link ImplictBaseOfBase#getGoo}
@@ -13824,7 +13820,7 @@ public interface ImplictBaseOfBase extends software.amazon.jsii.JsiiSerializable
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public ImplictBaseOfBase build() {
-            return new Jsii$Proxy(goo, bar, foo);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -13852,11 +13848,11 @@ public interface ImplictBaseOfBase extends software.amazon.jsii.JsiiSerializable
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.time.Instant goo, final java.lang.String bar, final software.amazon.jsii.tests.calculator.baseofbase.Very foo) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.goo = java.util.Objects.requireNonNull(goo, "goo is required");
-            this.bar = java.util.Objects.requireNonNull(bar, "bar is required");
-            this.foo = java.util.Objects.requireNonNull(foo, "foo is required");
+            this.goo = java.util.Objects.requireNonNull(builder.goo, "goo is required");
+            this.bar = java.util.Objects.requireNonNull(builder.bar, "bar is required");
+            this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required");
         }
 
         @Override
@@ -15079,7 +15075,7 @@ public class LevelOne extends software.amazon.jsii.JsiiObject {
          */
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         public static final class Builder implements software.amazon.jsii.Builder {
-            private java.lang.Boolean value;
+            java.lang.Boolean value;
 
             /**
              * Sets the value of {@link PropBooleanValue#getValue}
@@ -15100,7 +15096,7 @@ public class LevelOne extends software.amazon.jsii.JsiiObject {
             @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
             @Override
             public PropBooleanValue build() {
-                return new Jsii$Proxy(value);
+                return new Jsii$Proxy(this);
             }
         }
 
@@ -15124,9 +15120,9 @@ public class LevelOne extends software.amazon.jsii.JsiiObject {
             /**
              * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
              */
-            protected Jsii$Proxy(final java.lang.Boolean value) {
+            protected Jsii$Proxy(final Builder builder) {
                 super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-                this.value = java.util.Objects.requireNonNull(value, "value is required");
+                this.value = java.util.Objects.requireNonNull(builder.value, "value is required");
             }
 
             @Override
@@ -15193,7 +15189,7 @@ public class LevelOne extends software.amazon.jsii.JsiiObject {
          */
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         public static final class Builder implements software.amazon.jsii.Builder {
-            private software.amazon.jsii.tests.calculator.LevelOne.PropBooleanValue prop;
+            software.amazon.jsii.tests.calculator.LevelOne.PropBooleanValue prop;
 
             /**
              * Sets the value of {@link PropProperty#getProp}
@@ -15214,7 +15210,7 @@ public class LevelOne extends software.amazon.jsii.JsiiObject {
             @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
             @Override
             public PropProperty build() {
-                return new Jsii$Proxy(prop);
+                return new Jsii$Proxy(this);
             }
         }
 
@@ -15238,9 +15234,9 @@ public class LevelOne extends software.amazon.jsii.JsiiObject {
             /**
              * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
              */
-            protected Jsii$Proxy(final software.amazon.jsii.tests.calculator.LevelOne.PropBooleanValue prop) {
+            protected Jsii$Proxy(final Builder builder) {
                 super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-                this.prop = java.util.Objects.requireNonNull(prop, "prop is required");
+                this.prop = java.util.Objects.requireNonNull(builder.prop, "prop is required");
             }
 
             @Override
@@ -15356,7 +15352,7 @@ public interface LevelOneProps extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private software.amazon.jsii.tests.calculator.LevelOne.PropProperty prop;
+        software.amazon.jsii.tests.calculator.LevelOne.PropProperty prop;
 
         /**
          * Sets the value of {@link LevelOneProps#getProp}
@@ -15377,7 +15373,7 @@ public interface LevelOneProps extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public LevelOneProps build() {
-            return new Jsii$Proxy(prop);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -15401,9 +15397,9 @@ public interface LevelOneProps extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final software.amazon.jsii.tests.calculator.LevelOne.PropProperty prop) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.prop = java.util.Objects.requireNonNull(prop, "prop is required");
+            this.prop = java.util.Objects.requireNonNull(builder.prop, "prop is required");
         }
 
         @Override
@@ -15549,11 +15545,11 @@ public interface LoadBalancedFargateServiceProps extends software.amazon.jsii.Js
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number containerPort;
-        private java.lang.String cpu;
-        private java.lang.String memoryMiB;
-        private java.lang.Boolean publicLoadBalancer;
-        private java.lang.Boolean publicTasks;
+        java.lang.Number containerPort;
+        java.lang.String cpu;
+        java.lang.String memoryMiB;
+        java.lang.Boolean publicLoadBalancer;
+        java.lang.Boolean publicTasks;
 
         /**
          * Sets the value of {@link LoadBalancedFargateServiceProps#getContainerPort}
@@ -15641,7 +15637,7 @@ public interface LoadBalancedFargateServiceProps extends software.amazon.jsii.Js
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public LoadBalancedFargateServiceProps build() {
-            return new Jsii$Proxy(containerPort, cpu, memoryMiB, publicLoadBalancer, publicTasks);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -15673,13 +15669,13 @@ public interface LoadBalancedFargateServiceProps extends software.amazon.jsii.Js
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number containerPort, final java.lang.String cpu, final java.lang.String memoryMiB, final java.lang.Boolean publicLoadBalancer, final java.lang.Boolean publicTasks) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.containerPort = containerPort;
-            this.cpu = cpu;
-            this.memoryMiB = memoryMiB;
-            this.publicLoadBalancer = publicLoadBalancer;
-            this.publicTasks = publicTasks;
+            this.containerPort = builder.containerPort;
+            this.cpu = builder.cpu;
+            this.memoryMiB = builder.memoryMiB;
+            this.publicLoadBalancer = builder.publicLoadBalancer;
+            this.publicTasks = builder.publicTasks;
         }
 
         @Override
@@ -16022,7 +16018,7 @@ public interface NestedStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number numberProp;
+        java.lang.Number numberProp;
 
         /**
          * Sets the value of {@link NestedStruct#getNumberProp}
@@ -16043,7 +16039,7 @@ public interface NestedStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public NestedStruct build() {
-            return new Jsii$Proxy(numberProp);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -16067,9 +16063,9 @@ public interface NestedStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number numberProp) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.numberProp = java.util.Objects.requireNonNull(numberProp, "numberProp is required");
+            this.numberProp = java.util.Objects.requireNonNull(builder.numberProp, "numberProp is required");
         }
 
         @Override
@@ -16303,8 +16299,8 @@ public interface NullShouldBeTreatedAsUndefinedData extends software.amazon.jsii
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.util.List arrayWithThreeElementsAndUndefinedAsSecondArgument;
-        private java.lang.Object thisShouldBeUndefined;
+        java.util.List arrayWithThreeElementsAndUndefinedAsSecondArgument;
+        java.lang.Object thisShouldBeUndefined;
 
         /**
          * Sets the value of {@link NullShouldBeTreatedAsUndefinedData#getArrayWithThreeElementsAndUndefinedAsSecondArgument}
@@ -16337,7 +16333,7 @@ public interface NullShouldBeTreatedAsUndefinedData extends software.amazon.jsii
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public NullShouldBeTreatedAsUndefinedData build() {
-            return new Jsii$Proxy(arrayWithThreeElementsAndUndefinedAsSecondArgument, thisShouldBeUndefined);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -16364,10 +16360,10 @@ public interface NullShouldBeTreatedAsUndefinedData extends software.amazon.jsii
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
         @SuppressWarnings("unchecked")
-        protected Jsii$Proxy(final java.util.List arrayWithThreeElementsAndUndefinedAsSecondArgument, final java.lang.Object thisShouldBeUndefined) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.arrayWithThreeElementsAndUndefinedAsSecondArgument = (java.util.List)java.util.Objects.requireNonNull(arrayWithThreeElementsAndUndefinedAsSecondArgument, "arrayWithThreeElementsAndUndefinedAsSecondArgument is required");
-            this.thisShouldBeUndefined = thisShouldBeUndefined;
+            this.arrayWithThreeElementsAndUndefinedAsSecondArgument = (java.util.List)java.util.Objects.requireNonNull(builder.arrayWithThreeElementsAndUndefinedAsSecondArgument, "arrayWithThreeElementsAndUndefinedAsSecondArgument is required");
+            this.thisShouldBeUndefined = builder.thisShouldBeUndefined;
         }
 
         @Override
@@ -16741,7 +16737,7 @@ public interface OptionalStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String field;
+        java.lang.String field;
 
         /**
          * Sets the value of {@link OptionalStruct#getField}
@@ -16762,7 +16758,7 @@ public interface OptionalStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public OptionalStruct build() {
-            return new Jsii$Proxy(field);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -16786,9 +16782,9 @@ public interface OptionalStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String field) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.field = field;
+            this.field = builder.field;
         }
 
         @Override
@@ -17073,7 +17069,7 @@ public interface ParentStruct982 extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String foo;
+        java.lang.String foo;
 
         /**
          * Sets the value of {@link ParentStruct982#getFoo}
@@ -17094,7 +17090,7 @@ public interface ParentStruct982 extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public ParentStruct982 build() {
-            return new Jsii$Proxy(foo);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -17118,9 +17114,9 @@ public interface ParentStruct982 extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String foo) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.foo = java.util.Objects.requireNonNull(foo, "foo is required");
+            this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required");
         }
 
         @Override
@@ -17794,8 +17790,8 @@ public interface RootStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String stringProp;
-        private software.amazon.jsii.tests.calculator.NestedStruct nestedStruct;
+        java.lang.String stringProp;
+        software.amazon.jsii.tests.calculator.NestedStruct nestedStruct;
 
         /**
          * Sets the value of {@link RootStruct#getStringProp}
@@ -17827,7 +17823,7 @@ public interface RootStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public RootStruct build() {
-            return new Jsii$Proxy(stringProp, nestedStruct);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -17853,10 +17849,10 @@ public interface RootStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String stringProp, final software.amazon.jsii.tests.calculator.NestedStruct nestedStruct) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.stringProp = java.util.Objects.requireNonNull(stringProp, "stringProp is required");
-            this.nestedStruct = nestedStruct;
+            this.stringProp = java.util.Objects.requireNonNull(builder.stringProp, "stringProp is required");
+            this.nestedStruct = builder.nestedStruct;
         }
 
         @Override
@@ -18079,8 +18075,8 @@ public interface SecondLevelStruct extends software.amazon.jsii.JsiiSerializable
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String deeperRequiredProp;
-        private java.lang.String deeperOptionalProp;
+        java.lang.String deeperRequiredProp;
+        java.lang.String deeperOptionalProp;
 
         /**
          * Sets the value of {@link SecondLevelStruct#getDeeperRequiredProp}
@@ -18112,7 +18108,7 @@ public interface SecondLevelStruct extends software.amazon.jsii.JsiiSerializable
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public SecondLevelStruct build() {
-            return new Jsii$Proxy(deeperRequiredProp, deeperOptionalProp);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -18138,10 +18134,10 @@ public interface SecondLevelStruct extends software.amazon.jsii.JsiiSerializable
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String deeperRequiredProp, final java.lang.String deeperOptionalProp) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.deeperRequiredProp = java.util.Objects.requireNonNull(deeperRequiredProp, "deeperRequiredProp is required");
-            this.deeperOptionalProp = deeperOptionalProp;
+            this.deeperRequiredProp = java.util.Objects.requireNonNull(builder.deeperRequiredProp, "deeperRequiredProp is required");
+            this.deeperOptionalProp = builder.deeperOptionalProp;
         }
 
         @Override
@@ -18380,8 +18376,8 @@ public interface SmellyStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String property;
-        private java.lang.Boolean yetAnoterOne;
+        java.lang.String property;
+        java.lang.Boolean yetAnoterOne;
 
         /**
          * Sets the value of {@link SmellyStruct#getProperty}
@@ -18413,7 +18409,7 @@ public interface SmellyStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public SmellyStruct build() {
-            return new Jsii$Proxy(property, yetAnoterOne);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -18439,10 +18435,10 @@ public interface SmellyStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String property, final java.lang.Boolean yetAnoterOne) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.property = java.util.Objects.requireNonNull(property, "property is required");
-            this.yetAnoterOne = java.util.Objects.requireNonNull(yetAnoterOne, "yetAnoterOne is required");
+            this.property = java.util.Objects.requireNonNull(builder.property, "property is required");
+            this.yetAnoterOne = java.util.Objects.requireNonNull(builder.yetAnoterOne, "yetAnoterOne is required");
         }
 
         @Override
@@ -18656,7 +18652,7 @@ public interface StableStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String readonlyProperty;
+        java.lang.String readonlyProperty;
 
         /**
          * Sets the value of {@link StableStruct#getReadonlyProperty}
@@ -18677,7 +18673,7 @@ public interface StableStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public StableStruct build() {
-            return new Jsii$Proxy(readonlyProperty);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -18701,9 +18697,9 @@ public interface StableStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String readonlyProperty) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.readonlyProperty = java.util.Objects.requireNonNull(readonlyProperty, "readonlyProperty is required");
+            this.readonlyProperty = java.util.Objects.requireNonNull(builder.readonlyProperty, "readonlyProperty is required");
         }
 
         @Override
@@ -19106,9 +19102,9 @@ public interface StructA extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String requiredString;
-        private java.lang.Number optionalNumber;
-        private java.lang.String optionalString;
+        java.lang.String requiredString;
+        java.lang.Number optionalNumber;
+        java.lang.String optionalString;
 
         /**
          * Sets the value of {@link StructA#getRequiredString}
@@ -19151,7 +19147,7 @@ public interface StructA extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public StructA build() {
-            return new Jsii$Proxy(requiredString, optionalNumber, optionalString);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -19179,11 +19175,11 @@ public interface StructA extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String requiredString, final java.lang.Number optionalNumber, final java.lang.String optionalString) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.requiredString = java.util.Objects.requireNonNull(requiredString, "requiredString is required");
-            this.optionalNumber = optionalNumber;
-            this.optionalString = optionalString;
+            this.requiredString = java.util.Objects.requireNonNull(builder.requiredString, "requiredString is required");
+            this.optionalNumber = builder.optionalNumber;
+            this.optionalString = builder.optionalString;
         }
 
         @Override
@@ -19292,9 +19288,9 @@ public interface StructB extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String requiredString;
-        private java.lang.Boolean optionalBoolean;
-        private software.amazon.jsii.tests.calculator.StructA optionalStructA;
+        java.lang.String requiredString;
+        java.lang.Boolean optionalBoolean;
+        software.amazon.jsii.tests.calculator.StructA optionalStructA;
 
         /**
          * Sets the value of {@link StructB#getRequiredString}
@@ -19337,7 +19333,7 @@ public interface StructB extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public StructB build() {
-            return new Jsii$Proxy(requiredString, optionalBoolean, optionalStructA);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -19365,11 +19361,11 @@ public interface StructB extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String requiredString, final java.lang.Boolean optionalBoolean, final software.amazon.jsii.tests.calculator.StructA optionalStructA) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.requiredString = java.util.Objects.requireNonNull(requiredString, "requiredString is required");
-            this.optionalBoolean = optionalBoolean;
-            this.optionalStructA = optionalStructA;
+            this.requiredString = java.util.Objects.requireNonNull(builder.requiredString, "requiredString is required");
+            this.optionalBoolean = builder.optionalBoolean;
+            this.optionalStructA = builder.optionalStructA;
         }
 
         @Override
@@ -19473,8 +19469,8 @@ public interface StructParameterType extends software.amazon.jsii.JsiiSerializab
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String scope;
-        private java.lang.Boolean props;
+        java.lang.String scope;
+        java.lang.Boolean props;
 
         /**
          * Sets the value of {@link StructParameterType#getScope}
@@ -19506,7 +19502,7 @@ public interface StructParameterType extends software.amazon.jsii.JsiiSerializab
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public StructParameterType build() {
-            return new Jsii$Proxy(scope, props);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -19532,10 +19528,10 @@ public interface StructParameterType extends software.amazon.jsii.JsiiSerializab
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String scope, final java.lang.Boolean props) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.scope = java.util.Objects.requireNonNull(scope, "scope is required");
-            this.props = props;
+            this.scope = java.util.Objects.requireNonNull(builder.scope, "scope is required");
+            this.props = builder.props;
         }
 
         @Override
@@ -19715,8 +19711,8 @@ public interface StructWithEnum extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private software.amazon.jsii.tests.calculator.StringEnum foo;
-        private software.amazon.jsii.tests.calculator.AllTypesEnum bar;
+        software.amazon.jsii.tests.calculator.StringEnum foo;
+        software.amazon.jsii.tests.calculator.AllTypesEnum bar;
 
         /**
          * Sets the value of {@link StructWithEnum#getFoo}
@@ -19748,7 +19744,7 @@ public interface StructWithEnum extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public StructWithEnum build() {
-            return new Jsii$Proxy(foo, bar);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -19774,10 +19770,10 @@ public interface StructWithEnum extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final software.amazon.jsii.tests.calculator.StringEnum foo, final software.amazon.jsii.tests.calculator.AllTypesEnum bar) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.foo = java.util.Objects.requireNonNull(foo, "foo is required");
-            this.bar = bar;
+            this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required");
+            this.bar = builder.bar;
         }
 
         @Override
@@ -19882,10 +19878,10 @@ public interface StructWithJavaReservedWords extends software.amazon.jsii.JsiiSe
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String defaultValue;
-        private java.lang.String assertValue;
-        private java.lang.String result;
-        private java.lang.String that;
+        java.lang.String defaultValue;
+        java.lang.String assertValue;
+        java.lang.String result;
+        java.lang.String that;
 
         /**
          * Sets the value of {@link StructWithJavaReservedWords#getDefaultValue}
@@ -19939,7 +19935,7 @@ public interface StructWithJavaReservedWords extends software.amazon.jsii.JsiiSe
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public StructWithJavaReservedWords build() {
-            return new Jsii$Proxy(defaultValue, assertValue, result, that);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -19969,12 +19965,12 @@ public interface StructWithJavaReservedWords extends software.amazon.jsii.JsiiSe
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String defaultValue, final java.lang.String assertValue, final java.lang.String result, final java.lang.String that) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.defaultValue = java.util.Objects.requireNonNull(defaultValue, "defaultValue is required");
-            this.assertValue = assertValue;
-            this.result = result;
-            this.that = that;
+            this.defaultValue = java.util.Objects.requireNonNull(builder.defaultValue, "defaultValue is required");
+            this.assertValue = builder.assertValue;
+            this.result = builder.result;
+            this.that = builder.that;
         }
 
         @Override
@@ -20278,8 +20274,8 @@ public interface SupportsNiceJavaBuilderProps extends software.amazon.jsii.JsiiS
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number bar;
-        private java.lang.String id;
+        java.lang.Number bar;
+        java.lang.String id;
 
         /**
          * Sets the value of {@link SupportsNiceJavaBuilderProps#getBar}
@@ -20312,7 +20308,7 @@ public interface SupportsNiceJavaBuilderProps extends software.amazon.jsii.JsiiS
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public SupportsNiceJavaBuilderProps build() {
-            return new Jsii$Proxy(bar, id);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -20338,10 +20334,10 @@ public interface SupportsNiceJavaBuilderProps extends software.amazon.jsii.JsiiS
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number bar, final java.lang.String id) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.bar = java.util.Objects.requireNonNull(bar, "bar is required");
-            this.id = id;
+            this.bar = java.util.Objects.requireNonNull(builder.bar, "bar is required");
+            this.id = builder.id;
         }
 
         @Override
@@ -20836,9 +20832,9 @@ public interface TopLevelStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String required;
-        private java.lang.Object secondLevel;
-        private java.lang.String optional;
+        java.lang.String required;
+        java.lang.Object secondLevel;
+        java.lang.String optional;
 
         /**
          * Sets the value of {@link TopLevelStruct#getRequired}
@@ -20892,7 +20888,7 @@ public interface TopLevelStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public TopLevelStruct build() {
-            return new Jsii$Proxy(required, secondLevel, optional);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -20920,11 +20916,11 @@ public interface TopLevelStruct extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String required, final java.lang.Object secondLevel, final java.lang.String optional) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.required = java.util.Objects.requireNonNull(required, "required is required");
-            this.secondLevel = java.util.Objects.requireNonNull(secondLevel, "secondLevel is required");
-            this.optional = optional;
+            this.required = java.util.Objects.requireNonNull(builder.required, "required is required");
+            this.secondLevel = java.util.Objects.requireNonNull(builder.secondLevel, "secondLevel is required");
+            this.optional = builder.optional;
         }
 
         @Override
@@ -21196,8 +21192,8 @@ public interface UnionProperties extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Object bar;
-        private java.lang.Object foo;
+        java.lang.Object bar;
+        java.lang.Object foo;
 
         /**
          * Sets the value of {@link UnionProperties#getBar}
@@ -21262,7 +21258,7 @@ public interface UnionProperties extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public UnionProperties build() {
-            return new Jsii$Proxy(bar, foo);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -21288,10 +21284,10 @@ public interface UnionProperties extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Object bar, final java.lang.Object foo) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.bar = java.util.Objects.requireNonNull(bar, "bar is required");
-            this.foo = foo;
+            this.bar = java.util.Objects.requireNonNull(builder.bar, "bar is required");
+            this.foo = builder.foo;
         }
 
         @Override
@@ -22189,7 +22185,7 @@ public interface Hello extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number foo;
+        java.lang.Number foo;
 
         /**
          * Sets the value of {@link Hello#getFoo}
@@ -22210,7 +22206,7 @@ public interface Hello extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public Hello build() {
-            return new Jsii$Proxy(foo);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -22234,9 +22230,9 @@ public interface Hello extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number foo) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.foo = java.util.Objects.requireNonNull(foo, "foo is required");
+            this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required");
         }
 
         @Override
@@ -22310,7 +22306,7 @@ public interface Hello extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.Number foo;
+        java.lang.Number foo;
 
         /**
          * Sets the value of {@link Hello#getFoo}
@@ -22331,7 +22327,7 @@ public interface Hello extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public Hello build() {
-            return new Jsii$Proxy(foo);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -22355,9 +22351,9 @@ public interface Hello extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.Number foo) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.foo = java.util.Objects.requireNonNull(foo, "foo is required");
+            this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required");
         }
 
         @Override
@@ -22701,8 +22697,8 @@ public interface MyStruct extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.util.Map baseMap;
-        private java.util.List numbers;
+        java.util.Map baseMap;
+        java.util.List numbers;
 
         /**
          * Sets the value of {@link MyStruct#getBaseMap}
@@ -22736,7 +22732,7 @@ public interface MyStruct extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public MyStruct build() {
-            return new Jsii$Proxy(baseMap, numbers);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -22763,10 +22759,10 @@ public interface MyStruct extends software.amazon.jsii.JsiiSerializable {
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
         @SuppressWarnings("unchecked")
-        protected Jsii$Proxy(final java.util.Map baseMap, final java.util.List numbers) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.baseMap = (java.util.Map)java.util.Objects.requireNonNull(baseMap, "baseMap is required");
-            this.numbers = (java.util.List)java.util.Objects.requireNonNull(numbers, "numbers is required");
+            this.baseMap = (java.util.Map)java.util.Objects.requireNonNull(builder.baseMap, "baseMap is required");
+            this.numbers = (java.util.List)java.util.Objects.requireNonNull(builder.numbers, "numbers is required");
         }
 
         @Override
@@ -22848,7 +22844,7 @@ public interface Bar extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String bar1;
+        java.lang.String bar1;
 
         /**
          * Sets the value of {@link Bar#getBar1}
@@ -22869,7 +22865,7 @@ public interface Bar extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public Bar build() {
-            return new Jsii$Proxy(bar1);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -22893,9 +22889,9 @@ public interface Bar extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String bar1) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.bar1 = java.util.Objects.requireNonNull(bar1, "bar1 is required");
+            this.bar1 = java.util.Objects.requireNonNull(builder.bar1, "bar1 is required");
         }
 
         @Override
@@ -22969,7 +22965,7 @@ public interface Bar extends software.amazon.jsii.JsiiSerializable {
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String bar2;
+        java.lang.String bar2;
 
         /**
          * Sets the value of {@link Bar#getBar2}
@@ -22990,7 +22986,7 @@ public interface Bar extends software.amazon.jsii.JsiiSerializable {
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public Bar build() {
-            return new Jsii$Proxy(bar2);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -23014,9 +23010,9 @@ public interface Bar extends software.amazon.jsii.JsiiSerializable {
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String bar2) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.bar2 = java.util.Objects.requireNonNull(bar2, "bar2 is required");
+            this.bar2 = java.util.Objects.requireNonNull(builder.bar2, "bar2 is required");
         }
 
         @Override
@@ -23090,9 +23086,9 @@ public interface Foo extends software.amazon.jsii.JsiiSerializable, software.ama
      */
     @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
     public static final class Builder implements software.amazon.jsii.Builder {
-        private java.lang.String foo2;
-        private java.lang.String bar2;
-        private java.lang.String bar1;
+        java.lang.String foo2;
+        java.lang.String bar2;
+        java.lang.String bar1;
 
         /**
          * Sets the value of {@link Foo#getFoo2}
@@ -23135,7 +23131,7 @@ public interface Foo extends software.amazon.jsii.JsiiSerializable, software.ama
         @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable)
         @Override
         public Foo build() {
-            return new Jsii$Proxy(foo2, bar2, bar1);
+            return new Jsii$Proxy(this);
         }
     }
 
@@ -23163,11 +23159,11 @@ public interface Foo extends software.amazon.jsii.JsiiSerializable, software.ama
         /**
          * Constructor that initializes the object based on literal property values passed by the {@link Builder}.
          */
-        protected Jsii$Proxy(final java.lang.String foo2, final java.lang.String bar2, final java.lang.String bar1) {
+        protected Jsii$Proxy(final Builder builder) {
             super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
-            this.foo2 = java.util.Objects.requireNonNull(foo2, "foo2 is required");
-            this.bar2 = java.util.Objects.requireNonNull(bar2, "bar2 is required");
-            this.bar1 = java.util.Objects.requireNonNull(bar1, "bar1 is required");
+            this.foo2 = java.util.Objects.requireNonNull(builder.foo2, "foo2 is required");
+            this.bar2 = java.util.Objects.requireNonNull(builder.bar2, "bar2 is required");
+            this.bar1 = java.util.Objects.requireNonNull(builder.bar1, "bar1 is required");
         }
 
         @Override
@@ -24119,21 +24115,18 @@ exports[`Generated code for "jsii-calc": /java/src/main/java/software/am
  * First, create a calculator:
  * 

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * Calculator calculator = new Calculator();
  * 
*

* Then call some operations: *

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * calculator.add(10);
  * 
*

*

Code Samples

*

*

- * // Example automatically generated. See https://github.com/aws/jsii/issues/826
  * /* This is totes a magic comment in here, just you wait! */
  * String foo = "bar";
  * 
@@ -24349,7 +24342,7 @@ public interface StructWithSelf extends software.amazon.jsii.JsiiSerializable { */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String self; + java.lang.String self; /** * Sets the value of {@link StructWithSelf#getSelf} @@ -24370,7 +24363,7 @@ public interface StructWithSelf extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public StructWithSelf build() { - return new Jsii$Proxy(self); + return new Jsii$Proxy(this); } } @@ -24394,9 +24387,9 @@ public interface StructWithSelf extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String self) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.self = java.util.Objects.requireNonNull(self, "self is required"); + this.self = java.util.Objects.requireNonNull(builder.self, "self is required"); } @Override @@ -24473,7 +24466,7 @@ public interface Default extends software.amazon.jsii.JsiiSerializable { */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Number foo; + java.lang.Number foo; /** * Sets the value of {@link Default#getFoo} @@ -24494,7 +24487,7 @@ public interface Default extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public Default build() { - return new Jsii$Proxy(foo); + return new Jsii$Proxy(this); } } @@ -24518,9 +24511,9 @@ public interface Default extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Number foo) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.foo = java.util.Objects.requireNonNull(foo, "foo is required"); + this.foo = java.util.Objects.requireNonNull(builder.foo, "foo is required"); } @Override @@ -24716,7 +24709,7 @@ public interface MyClassReference extends software.amazon.jsii.JsiiSerializable */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private software.amazon.jsii.tests.calculator.submodule.MyClass reference; + software.amazon.jsii.tests.calculator.submodule.MyClass reference; /** * Sets the value of {@link MyClassReference#getReference} @@ -24737,7 +24730,7 @@ public interface MyClassReference extends software.amazon.jsii.JsiiSerializable @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public MyClassReference build() { - return new Jsii$Proxy(reference); + return new Jsii$Proxy(this); } } @@ -24761,9 +24754,9 @@ public interface MyClassReference extends software.amazon.jsii.JsiiSerializable /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final software.amazon.jsii.tests.calculator.submodule.MyClass reference) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.reference = java.util.Objects.requireNonNull(reference, "reference is required"); + this.reference = java.util.Objects.requireNonNull(builder.reference, "reference is required"); } @Override @@ -24923,8 +24916,8 @@ public interface KwargsProps extends software.amazon.jsii.JsiiSerializable, soft */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String extra; - private software.amazon.jsii.tests.calculator.submodule.child.SomeEnum prop; + java.lang.String extra; + software.amazon.jsii.tests.calculator.submodule.child.SomeEnum prop; /** * Sets the value of {@link KwargsProps#getExtra} @@ -24956,7 +24949,7 @@ public interface KwargsProps extends software.amazon.jsii.JsiiSerializable, soft @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public KwargsProps build() { - return new Jsii$Proxy(extra, prop); + return new Jsii$Proxy(this); } } @@ -24982,10 +24975,10 @@ public interface KwargsProps extends software.amazon.jsii.JsiiSerializable, soft /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String extra, final software.amazon.jsii.tests.calculator.submodule.child.SomeEnum prop) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.extra = extra; - this.prop = java.util.Objects.requireNonNull(prop, "prop is required"); + this.extra = builder.extra; + this.prop = java.util.Objects.requireNonNull(builder.prop, "prop is required"); } @Override @@ -25125,7 +25118,7 @@ public interface SomeStruct extends software.amazon.jsii.JsiiSerializable { */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private software.amazon.jsii.tests.calculator.submodule.child.SomeEnum prop; + software.amazon.jsii.tests.calculator.submodule.child.SomeEnum prop; /** * Sets the value of {@link SomeStruct#getProp} @@ -25146,7 +25139,7 @@ public interface SomeStruct extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public SomeStruct build() { - return new Jsii$Proxy(prop); + return new Jsii$Proxy(this); } } @@ -25170,9 +25163,9 @@ public interface SomeStruct extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final software.amazon.jsii.tests.calculator.submodule.child.SomeEnum prop) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.prop = java.util.Objects.requireNonNull(prop, "prop is required"); + this.prop = java.util.Objects.requireNonNull(builder.prop, "prop is required"); } @Override @@ -25246,7 +25239,7 @@ public interface Structure extends software.amazon.jsii.JsiiSerializable { */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.Boolean bool; + java.lang.Boolean bool; /** * Sets the value of {@link Structure#getBool} @@ -25267,7 +25260,7 @@ public interface Structure extends software.amazon.jsii.JsiiSerializable { @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public Structure build() { - return new Jsii$Proxy(bool); + return new Jsii$Proxy(this); } } @@ -25291,9 +25284,9 @@ public interface Structure extends software.amazon.jsii.JsiiSerializable { /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.Boolean bool) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.bool = java.util.Objects.requireNonNull(bool, "bool is required"); + this.bool = java.util.Objects.requireNonNull(builder.bool, "bool is required"); } @Override @@ -25528,7 +25521,7 @@ public interface SpecialParameter extends software.amazon.jsii.JsiiSerializable */ @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) public static final class Builder implements software.amazon.jsii.Builder { - private java.lang.String value; + java.lang.String value; /** * Sets the value of {@link SpecialParameter#getValue} @@ -25549,7 +25542,7 @@ public interface SpecialParameter extends software.amazon.jsii.JsiiSerializable @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) @Override public SpecialParameter build() { - return new Jsii$Proxy(value); + return new Jsii$Proxy(this); } } @@ -25573,9 +25566,9 @@ public interface SpecialParameter extends software.amazon.jsii.JsiiSerializable /** * Constructor that initializes the object based on literal property values passed by the {@link Builder}. */ - protected Jsii$Proxy(final java.lang.String value) { + protected Jsii$Proxy(final Builder builder) { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); - this.value = java.util.Objects.requireNonNull(value, "value is required"); + this.value = java.util.Objects.requireNonNull(builder.value, "value is required"); } @Override diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.ts.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.ts.snap index 888260baf2..6485f5a72f 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.ts.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.ts.snap @@ -243,7 +243,7 @@ scope.jsii-calc-base exports[`Generated code for "@scope/jsii-calc-base": /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -723,7 +723,7 @@ scope.jsii-calc-base-of-base exports[`Generated code for "@scope/jsii-calc-base-of-base": /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -1176,7 +1176,7 @@ scope.jsii-calc-lib exports[`Generated code for "@scope/jsii-calc-lib": /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -2383,21 +2383,18 @@ This library is used to demonstrate and test the features of JSII First, create a calculator: \`\`\`python -# Example automatically generated. See https://github.com/aws/jsii/issues/826 calculator = calc.Calculator() \`\`\` Then call some operations: \`\`\`python -# Example automatically generated. See https://github.com/aws/jsii/issues/826 calculator.add(10) \`\`\` ## Code Samples \`\`\`python -# Example automatically generated. See https://github.com/aws/jsii/issues/826 # This is totes a magic comment in here, just you wait! foo = "bar" \`\`\` @@ -2406,7 +2403,7 @@ foo = "bar" exports[`Generated code for "jsii-calc": /python/pyproject.toml 1`] = ` [build-system] -requires = ["setuptools~=58.3.0", "wheel~=0.37.0"] +requires = ["setuptools~=58.5.3", "wheel~=0.37.0"] build-backend = "setuptools.build_meta" `; @@ -2525,21 +2522,18 @@ This library is used to demonstrate and test the features of JSII First, create a calculator: \`\`\`python -# Example automatically generated. See https://github.com/aws/jsii/issues/826 calculator = calc.Calculator() \`\`\` Then call some operations: \`\`\`python -# Example automatically generated. See https://github.com/aws/jsii/issues/826 calculator.add(10) \`\`\` ## Code Samples \`\`\`python -# Example automatically generated. See https://github.com/aws/jsii/issues/826 # This is totes a magic comment in here, just you wait! foo = "bar" \`\`\` @@ -3119,7 +3113,6 @@ class Calculator( Here's how you use it:: - # Example automatically generated. See https://github.com/aws/jsii/issues/826 calculator = calc.Calculator() calculator.add(5) calculator.mul(3) @@ -3129,7 +3122,6 @@ class Calculator( Example:: - # Example automatically generated. See https://github.com/aws/jsii/issues/826 calculator = calc.Calculator() calculator.add(5) calculator.mul(3) @@ -3419,7 +3411,6 @@ class ClassWithDocs(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.ClassWithDocs" Example:: - # Example automatically generated. See https://github.com/aws/jsii/issues/826 def an_example(): pass ''' @@ -4525,7 +4516,6 @@ class DocumentedClass(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.DocumentedCl Example:: - # Example automatically generated. See https://github.com/aws/jsii/issues/826 x = 12 + 44 s1 = "string" s2 = """string diff --git a/packages/jsii-rosetta/README.md b/packages/jsii-rosetta/README.md index 19949fca4e..d05d0973c2 100644 --- a/packages/jsii-rosetta/README.md +++ b/packages/jsii-rosetta/README.md @@ -199,3 +199,57 @@ If you get out of memory errors running too many workers, run a command like thi $ /sbin/sysctl -w vm.max_map_count=2251954 ``` +## Infuse + +The `rosetta infuse` feature will copy code samples (for example, as found in +the README), to the classes that are referenced in the code sample. This will make +sure the same examples are rendered in multiple places, and increases their visibility +without additional work on the author's part. + +The infuse command will modify the relevant assemblies and tablet files: + +- Assembly: it will add new `example` sections to types in the assembly. +- Tablet: every newly added `example` will require a new copy of the example (with + a unique identifier) added to the tablet. + +### Data flow + +The diagram below shows how data flows through the jsii tools when used together: + +```text +┌───────────┐ +│ │ +│ Source ├───┐ +│ │ │ ╔══════════╗ ┌────────────┐ ╔═══════════════╗ ┌──────────┐ +└───────────┘ │ ║ ║ │ │ ║ rosetta ║ │ │ + ├───▶║ jsii ║───▶│ assembly │────▶║ extract ║───▶│ tablet │ +┌───────────┐ │ ║ ║ │ │ ║ ║ │ │ +│ │ │ ╚══════════╝ └────────────┘ ╚═══════════════╝ └──────────┘ +│ README │───┘ │ │ +│ │ │ │ +└───────────┘ │ ╔═══════════════╗ │ + │ ║ rosetta ║ │ + └──────────▶║ infuse ║◀─────────┘ + ║ ║ + ╚═══════════════╝ + │ + ┌───────────────────┴───────────────────┐ + │ │ + ▼ ▼ + ┌────────────┐ ┌──────────┐ + │ │ │ │ + │ assembly' │ │ tablet' │ + │ │ │ │ + └────────────┘ └──────────┘ + │ │ + │ │ + │ ▼ ┌─────────────┐ + │ ╔═══════════════╗ ┌┴────────────┐│ + │ ║ ║ │ ││ + └──────────────────────────────▶║ pacmak ║────▶│ packages ││ + ║ ║ │ ├┘ + ╚═══════════════╝ └─────────────┘ + (potentially + live-translates) +``` + diff --git a/packages/jsii-rosetta/lib/commands/extract.ts b/packages/jsii-rosetta/lib/commands/extract.ts index c896367ea8..57234b9361 100644 --- a/packages/jsii-rosetta/lib/commands/extract.ts +++ b/packages/jsii-rosetta/lib/commands/extract.ts @@ -1,16 +1,10 @@ -import * as os from 'os'; -import * as path from 'path'; -import * as workerpool from 'workerpool'; - import { loadAssemblies, allTypeScriptSnippets } from '../jsii/assemblies'; -import { TypeFingerprinter } from '../jsii/fingerprinting'; -import { TARGET_LANGUAGES } from '../languages'; import * as logging from '../logging'; -import { TypeScriptSnippet, completeSource } from '../snippet'; +import { RosettaTranslator, RosettaTranslatorOptions } from '../rosetta-translator'; +import { TypeScriptSnippet } from '../snippet'; import { snippetKey } from '../tablets/key'; -import { LanguageTablet, TranslatedSnippet } from '../tablets/tablets'; -import { RosettaDiagnostic, Translator, makeRosettaDiagnostic } from '../translate'; -import type { TranslateBatchRequest, TranslateBatchResponse } from './extract_worker'; +import { LanguageTablet } from '../tablets/tablets'; +import { RosettaDiagnostic } from '../translate'; export interface ExtractResult { diagnostics: RosettaDiagnostic[]; @@ -29,15 +23,11 @@ export interface ExtractOptions { readonly cacheTabletFile?: string; /** - * Call the given translation function on the snippets. - * - * Optional, only for testing. Uses `translateAll` by default. + * Make a translator (just for testing) */ - readonly translationFunction?: TranslationFunc; + readonly translatorFactory?: (opts: RosettaTranslatorOptions) => RosettaTranslator; } -type TranslationFunc = typeof translateAll; - /** * Extract all samples from the given assemblies into a tablet */ @@ -50,35 +40,39 @@ export async function extractSnippets( logging.info(`Loading ${assemblyLocations.length} assemblies`); const assemblies = await loadAssemblies(assemblyLocations, options.validateAssemblies); - const fingerprinter = new TypeFingerprinter(assemblies.map((a) => a.assembly)); let snippets = Array.from(allTypeScriptSnippets(assemblies, loose)); if (only.length > 0) { snippets = filterSnippets(snippets, only); } - const tablet = new LanguageTablet(); + const translatorOptions: RosettaTranslatorOptions = { + assemblies: assemblies.map((a) => a.assembly), + }; + + const translator = options.translatorFactory + ? options.translatorFactory(translatorOptions) + : new RosettaTranslator(translatorOptions); if (options.cacheTabletFile) { - await reuseTranslationsFromCache(snippets, tablet, options.cacheTabletFile, fingerprinter); + await translator.loadCache(options.cacheTabletFile); + const { translations, remaining } = translator.readFromCache(snippets); + logging.info(`Reused ${translations.length} translations from cache ${options.cacheTabletFile}`); + snippets = remaining; } - const translateCount = snippets.length; const diagnostics = []; - if (translateCount > 0) { + if (snippets.length > 0) { logging.info('Translating'); const startTime = Date.now(); - const result = await (options.translationFunction ?? translateAll)(snippets, options.includeCompilerDiagnostics); - - for (const snippet of result.translatedSnippets) { - const fingerprinted = snippet.withFingerprint(fingerprinter.fingerprintAll(snippet.fqnsReferenced())); - tablet.addSnippet(fingerprinted); - } + const result = await translator.translateAll(snippets); const delta = (Date.now() - startTime) / 1000; logging.info( - `Translated ${translateCount} snippets in ${delta} seconds (${(delta / tablet.count).toPrecision(3)}s/snippet)`, + `Translated ${snippets.length} snippets in ${delta} seconds (${(delta / snippets.length).toPrecision( + 3, + )}s/snippet)`, ); diagnostics.push(...result.diagnostics); } else { @@ -86,14 +80,9 @@ export async function extractSnippets( } logging.info(`Saving language tablet to ${options.outputFile}`); - await tablet.save(options.outputFile); + await translator.tablet.save(options.outputFile); - return { diagnostics, tablet }; -} - -interface TranslateAllResult { - translatedSnippets: TranslatedSnippet[]; - diagnostics: RosettaDiagnostic[]; + return { diagnostics, tablet: translator.tablet }; } /** @@ -102,174 +91,3 @@ interface TranslateAllResult { function filterSnippets(ts: TypeScriptSnippet[], includeIds: string[]) { return ts.filter((t) => includeIds.includes(snippetKey(t))); } - -/** - * Translate all snippets - * - * We are now always using workers, as we are targeting Node 12+. - */ -async function translateAll( - snippets: TypeScriptSnippet[], - includeCompilerDiagnostics: boolean, -): Promise { - return workerBasedTranslateAll(snippets, includeCompilerDiagnostics); -} - -/** - * Translate the given snippets using a single compiler - * - * Used both here (directly) and via extract_worker to translate a batch of - * snippets in parallel. - */ -export function singleThreadedTranslateAll( - snippets: TypeScriptSnippet[], - includeCompilerDiagnostics: boolean, -): TranslateAllResult { - const translatedSnippets = new Array(); - - const failures = new Array(); - - const translator = new Translator(includeCompilerDiagnostics); - for (const block of snippets) { - try { - translatedSnippets.push(translator.translate(block)); - } catch (e) { - failures.push( - makeRosettaDiagnostic(true, `rosetta: error translating snippet: ${e}\n${e.stack}\n${block.completeSource}`), - ); - } - } - - return { - translatedSnippets, - diagnostics: [...translator.diagnostics, ...failures], - }; -} - -/** - * Divide the work evenly over all processors by running 'extract_worker' in Worker Threads, then combine results - * - * The workers are fed small queues of work each. We used to divide the entire queue into N - * but since the work is divided unevenly that led to some workers stopping early, idling while - * waiting for more work. - * - * Never include 'extract_worker' directly, only do TypeScript type references (so that in - * the script we may assume that 'worker_threads' successfully imports). - */ -async function workerBasedTranslateAll( - snippets: TypeScriptSnippet[], - includeCompilerDiagnostics: boolean, -): Promise { - // Use about half the advertised cores because hyperthreading doesn't seem to - // help that much, or we become I/O-bound at some point. On my machine, using - // more than half the cores actually makes it slower. - // Cap to a reasonable top-level limit to prevent thrash on machines with many, many cores. - const maxWorkers = parseInt(process.env.JSII_ROSETTA_MAX_WORKER_COUNT ?? '16'); - const N = Math.min(maxWorkers, Math.max(1, Math.ceil(os.cpus().length / 2))); - const snippetArr = Array.from(snippets); - logging.info(`Translating ${snippetArr.length} snippets using ${N} workers`); - - const pool = workerpool.pool(path.join(__dirname, 'extract_worker.js'), { - maxWorkers: N, - }); - - try { - const requests = batchSnippets(snippetArr, includeCompilerDiagnostics); - - const responses: TranslateBatchResponse[] = await Promise.all( - requests.map((request) => pool.exec('translateBatch', [request])), - ); - - const diagnostics = new Array(); - const translatedSnippets = new Array(); - - // Combine results - for (const response of responses) { - diagnostics.push(...response.diagnostics); - translatedSnippets.push(...response.translatedSchemas.map(TranslatedSnippet.fromSchema)); - } - return { diagnostics, translatedSnippets }; - } finally { - // Not waiting on purpose - void pool.terminate(); - } -} - -function batchSnippets( - snippets: TypeScriptSnippet[], - includeCompilerDiagnostics: boolean, - batchSize = 10, -): TranslateBatchRequest[] { - const ret = []; - - for (let i = 0; i < snippets.length; i += batchSize) { - ret.push({ - snippets: snippets.slice(i, i + batchSize), - includeCompilerDiagnostics, - }); - } - - return ret; -} - -/** - * Try and read as many snippet translations from the cache as possible, adding them to the target tablet - * - * Removes the already translated snippets from the input array. - */ -async function reuseTranslationsFromCache( - snippets: TypeScriptSnippet[], - tablet: LanguageTablet, - cacheFile: string, - fingerprinter: TypeFingerprinter, -) { - try { - const cache = await LanguageTablet.fromFile(cacheFile); - - let snippetsFromCacheCtr = 0; - let i = 0; - while (i < snippets.length) { - const fromCache = tryReadFromCache(snippets[i], cache, fingerprinter); - if (fromCache) { - tablet.addSnippet(fromCache); - snippets.splice(i, 1); - snippetsFromCacheCtr += 1; - } else { - i += 1; - } - } - - logging.info(`Reused ${snippetsFromCacheCtr} translations from cache ${cacheFile}`); - } catch (e) { - logging.warn(`Error reading cache ${cacheFile}: ${e.message}`); - } -} - -/** - * Try to find the translation for the given snippet in the given cache - * - * Rules for cacheability are: - * - id is the same (== visible source didn't change) - * - complete source is the same (== fixture didn't change) - * - all types involved have the same fingerprint (== API surface didn't change) - * - the versions of all translations match the versions on the available translators (== translator itself didn't change) - * - * For the versions check: we could have selectively picked some translations - * from the cache while performing others. However, since the big work is in - * parsing the TypeScript, and the rendering itself is peanutes (assumption), it - * doesn't really make a lot of difference. So, for simplification's sake, - * we'll regen all translations if there's at least one that's outdated. - */ -function tryReadFromCache(sourceSnippet: TypeScriptSnippet, cache: LanguageTablet, fingerprinter: TypeFingerprinter) { - const fromCache = cache.tryGetSnippet(snippetKey(sourceSnippet)); - - const cacheable = - fromCache && - completeSource(sourceSnippet) === fromCache.snippet.fullSource && - Object.entries(TARGET_LANGUAGES).every( - ([lang, translator]) => fromCache.snippet.translations?.[lang]?.version === translator.version, - ) && - fingerprinter.fingerprintAll(fromCache.fqnsReferenced()) === fromCache.snippet.fqnsFingerprint; - - return cacheable ? fromCache : undefined; -} diff --git a/packages/jsii-rosetta/lib/commands/extract_worker.ts b/packages/jsii-rosetta/lib/commands/extract_worker.ts deleted file mode 100644 index 9a46ac924e..0000000000 --- a/packages/jsii-rosetta/lib/commands/extract_worker.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Pool worker for extract.ts - */ -import * as workerpool from 'workerpool'; - -import { TypeScriptSnippet } from '../snippet'; -import { TranslatedSnippetSchema } from '../tablets/schema'; -import { RosettaDiagnostic } from '../translate'; -import { singleThreadedTranslateAll } from './extract'; - -export interface TranslateBatchRequest { - readonly snippets: TypeScriptSnippet[]; - readonly includeCompilerDiagnostics: boolean; -} - -export interface TranslateBatchResponse { - // Cannot be 'TranslatedSnippet' because needs to be serializable - readonly translatedSchemas: TranslatedSnippetSchema[]; - readonly diagnostics: RosettaDiagnostic[]; -} - -function translateBatch(request: TranslateBatchRequest): TranslateBatchResponse { - const result = singleThreadedTranslateAll(request.snippets, request.includeCompilerDiagnostics); - - return { - translatedSchemas: result.translatedSnippets.map((s) => s.snippet), - diagnostics: result.diagnostics, - }; -} - -workerpool.worker({ translateBatch }); diff --git a/packages/jsii-rosetta/lib/commands/transliterate.ts b/packages/jsii-rosetta/lib/commands/transliterate.ts index 082c5a85f5..e92eb5f2e7 100644 --- a/packages/jsii-rosetta/lib/commands/transliterate.ts +++ b/packages/jsii-rosetta/lib/commands/transliterate.ts @@ -5,7 +5,7 @@ import { resolve } from 'path'; import { fixturize } from '../fixtures'; import { TargetLanguage } from '../languages'; import { debug } from '../logging'; -import { Rosetta, UnknownSnippetMode } from '../rosetta'; +import { RosettaTabletReader, UnknownSnippetMode } from '../rosetta-reader'; import { SnippetParameters, typeScriptSnippetFromSource, ApiLocation } from '../snippet'; import { Translation } from '../tablets/tablets'; @@ -51,7 +51,7 @@ export async function transliterateAssembly( targetLanguages: readonly TargetLanguage[], options: TransliterateAssemblyOptions = {}, ): Promise { - const rosetta = new Rosetta({ + const rosetta = new RosettaTabletReader({ includeCompilerDiagnostics: true, unknownSnippets: UnknownSnippetMode.TRANSLATE, loose: options.loose, @@ -110,7 +110,7 @@ export async function transliterateAssembly( */ async function loadAssemblies( directories: readonly string[], - rosetta: Rosetta, + rosetta: RosettaTabletReader, ): Promise> { const result = new Map(); @@ -157,7 +157,7 @@ function prefixDisclaimer(translation: Translation): string { function transliterateType( type: Type, - rosetta: Rosetta, + rosetta: RosettaTabletReader, language: TargetLanguage, workingDirectory: string, loose = false, diff --git a/packages/jsii-rosetta/lib/index.ts b/packages/jsii-rosetta/lib/index.ts index f26bb05f93..7d9710639b 100644 --- a/packages/jsii-rosetta/lib/index.ts +++ b/packages/jsii-rosetta/lib/index.ts @@ -5,7 +5,8 @@ export { CSharpVisitor } from './languages/csharp'; export { JavaVisitor } from './languages/java'; export { PythonVisitor } from './languages/python'; export * from './tablets/tablets'; -export * from './rosetta'; +export * from './rosetta-reader'; +export * from './rosetta-translator'; export * from './snippet'; export * from './markdown'; export * from './strict'; diff --git a/packages/jsii-rosetta/lib/jsii/jsii-types.ts b/packages/jsii-rosetta/lib/jsii/jsii-types.ts index d7ce8066e3..a3345cc590 100644 --- a/packages/jsii-rosetta/lib/jsii/jsii-types.ts +++ b/packages/jsii-rosetta/lib/jsii/jsii-types.ts @@ -61,7 +61,10 @@ export function determineJsiiType(typeChecker: ts.TypeChecker, type: ts.Type): J } if (type.isUnion() || type.isIntersection()) { - return { kind: 'error', message: 'Type unions or intersections are not supported in examples' }; + return { + kind: 'error', + message: `Type unions or intersections are not supported in examples, got: ${typeChecker.typeToString(type)}`, + }; } return { kind: 'unknown' }; } @@ -94,10 +97,15 @@ export function analyzeObjectLiteral( return isDeclaredCall ? { kind: 'map' } : { kind: 'unknown' }; } - const structType = analyzeStructType(type); - if (structType) { - return { kind: structType, type }; + // If the type is a union between a struct and something else, return the first possible struct + const structCandidates = type.isUnion() ? type.types : [type]; + for (const candidate of structCandidates) { + const structType = analyzeStructType(candidate); + if (structType) { + return { kind: structType, type: candidate }; + } } + return { kind: 'map' }; } diff --git a/packages/jsii-rosetta/lib/rosetta.ts b/packages/jsii-rosetta/lib/rosetta-reader.ts similarity index 95% rename from packages/jsii-rosetta/lib/rosetta.ts rename to packages/jsii-rosetta/lib/rosetta-reader.ts index 77e60f7c02..5e823965e2 100644 --- a/packages/jsii-rosetta/lib/rosetta.ts +++ b/packages/jsii-rosetta/lib/rosetta-reader.ts @@ -69,7 +69,7 @@ export interface RosettaOptions { } /** - * Entry point class for consumers for Rosetta functionality + * Entry point class for consumers of Rosetta tablets (primarily: pacmak) * * Rosetta can work in one of two modes: * @@ -80,7 +80,7 @@ export interface RosettaOptions { * sample compilation and is recommended, but the first method will do * when the second one is not necessary. */ -export class Rosetta { +export class RosettaTabletReader { /** * Newly translated samples * @@ -110,6 +110,10 @@ export class Rosetta { /** * Load a tablet as a source for translateable snippets + * + * Note: the snippets loaded from this tablet will NOT be validated for + * their fingerprints or translator versions! If a matching snippet is found + * in the tablet, it will always be returned, whether or not it is stale. */ public async loadTabletFromFile(tabletFile: string) { const tablet = new LanguageTablet(); @@ -298,3 +302,10 @@ export class Rosetta { function id(x: Translation) { return x; } + +/** + * Backwards compatibility + * + * @deprecated use RosettaTabletReader instead + */ +export class Rosetta extends RosettaTabletReader {} diff --git a/packages/jsii-rosetta/lib/rosetta-translator.ts b/packages/jsii-rosetta/lib/rosetta-translator.ts new file mode 100644 index 0000000000..4257a92f02 --- /dev/null +++ b/packages/jsii-rosetta/lib/rosetta-translator.ts @@ -0,0 +1,141 @@ +import * as spec from '@jsii/spec'; + +import { TypeFingerprinter } from './jsii/fingerprinting'; +import { TARGET_LANGUAGES } from './languages'; +import * as logging from './logging'; +import { TypeScriptSnippet, completeSource } from './snippet'; +import { snippetKey } from './tablets/key'; +import { LanguageTablet, TranslatedSnippet } from './tablets/tablets'; +import { translateAll, TranslateAllResult } from './translate_all'; + +export interface RosettaTranslatorOptions { + /** + * Assemblies to use for fingerprinting + * + * The set of assemblies here are used to invalidate the cache. Any types that are + * used in snippets are looked up in this set of assemblies. If found, their type + * information is fingerprinted and compared to the type information at the time + * compilation of the cached sample. If different, this is considered to be a cache + * miss. + * + * You must use the same set of assemblies when generating and reading the cache + * file, otherwise the fingerprint is guaranteed to be different and the cache will + * be useless (e.g. if you generate the cache WITH assembly information but + * read it without, or vice versa). + * + * @default No assemblies. + */ + readonly assemblies?: spec.Assembly[]; + + /** + * Whether to include compiler diagnostics in the compilation results. + * + * @default false + */ + readonly includeCompilerDiagnostics?: boolean; +} + +/** + * Entry point for consumers that want to translate code on-the-fly + * + * If you want to generate and translate code on-the-fly, in ways that cannot + * be achieved by the rosetta CLI, use this class. + */ +export class RosettaTranslator { + public readonly tablet = new LanguageTablet(); + private readonly fingerprinter: TypeFingerprinter; + private readonly cache = new LanguageTablet(); + private readonly includeCompilerDiagnostics: boolean; + + public constructor(options: RosettaTranslatorOptions = {}) { + this.fingerprinter = new TypeFingerprinter(options?.assemblies ?? []); + this.includeCompilerDiagnostics = options.includeCompilerDiagnostics ?? false; + } + + public async loadCache(fileName: string) { + try { + await this.cache.load(fileName); + } catch (e) { + logging.warn(`Error reading cache ${fileName}: ${e.message}`); + } + } + + /** + * For all the given snippets, try to read translations from the cache + * + * Will remove the cached snippets from the input array. + */ + public readFromCache(snippets: TypeScriptSnippet[], addToTablet = true): ReadFromCacheResults { + const remaining = [...snippets]; + const translations = new Array(); + + let i = 0; + while (i < remaining.length) { + const fromCache = tryReadFromCache(remaining[i], this.cache, this.fingerprinter); + if (fromCache) { + if (addToTablet) { + this.tablet.addSnippet(fromCache); + } + remaining.splice(i, 1); + translations.push(fromCache); + } else { + i += 1; + } + } + + return { translations, remaining }; + } + + public async translateAll(snippets: TypeScriptSnippet[], addToTablet = true): Promise { + const result = await translateAll(snippets, this.includeCompilerDiagnostics); + + const fingerprinted = result.translatedSnippets.map((snippet) => + snippet.withFingerprint(this.fingerprinter.fingerprintAll(snippet.fqnsReferenced())), + ); + + if (addToTablet) { + for (const translation of fingerprinted) { + this.tablet.addSnippet(translation); + } + } + + return { + translatedSnippets: fingerprinted, + diagnostics: result.diagnostics, + }; + } +} + +/** + * Try to find the translation for the given snippet in the given cache + * + * Rules for cacheability are: + * - id is the same (== visible source didn't change) + * - complete source is the same (== fixture didn't change) + * - all types involved have the same fingerprint (== API surface didn't change) + * - the versions of all translations match the versions on the available translators (== translator itself didn't change) + * + * For the versions check: we could have selectively picked some translations + * from the cache while performing others. However, since the big work is in + * parsing the TypeScript, and the rendering itself is peanutes (assumption), it + * doesn't really make a lot of difference. So, for simplification's sake, + * we'll regen all translations if there's at least one that's outdated. + */ +function tryReadFromCache(sourceSnippet: TypeScriptSnippet, cache: LanguageTablet, fingerprinter: TypeFingerprinter) { + const fromCache = cache.tryGetSnippet(snippetKey(sourceSnippet)); + + const cacheable = + fromCache && + completeSource(sourceSnippet) === fromCache.snippet.fullSource && + Object.entries(TARGET_LANGUAGES).every( + ([lang, translator]) => fromCache.snippet.translations?.[lang]?.version === translator.version, + ) && + fingerprinter.fingerprintAll(fromCache.fqnsReferenced()) === fromCache.snippet.fqnsFingerprint; + + return cacheable ? fromCache : undefined; +} + +export interface ReadFromCacheResults { + readonly translations: TranslatedSnippet[]; + readonly remaining: TypeScriptSnippet[]; +} diff --git a/packages/jsii-rosetta/lib/snippet.ts b/packages/jsii-rosetta/lib/snippet.ts index c8d1a6d07c..88c1d74c7a 100644 --- a/packages/jsii-rosetta/lib/snippet.ts +++ b/packages/jsii-rosetta/lib/snippet.ts @@ -1,3 +1,5 @@ +import { trimCompleteSourceToVisible } from './typescript/visible-spans'; + /** * A piece of TypeScript code found in an assembly, ready to be translated */ @@ -100,20 +102,77 @@ export function renderApiLocation(apiLoc: ApiLocation): string { } } +/** + * Construct a TypeScript snippet from visible source + * + * Will parse parameters from a directive in the given source, but will not + * interpret `/// !show` and `/// !hide` directives. + * + * `/// !show` and `/// !hide` directives WILL affect what gets displayed by + * the translator, but they will NOT affect the snippet's cache key (i.e. the + * cache key will be based on the full source given here). + * + * Use this if you are looking up a snippet in a tablet, which has been translated + * previously using a fixture. + */ +export function typeScriptSnippetFromVisibleSource( + typeScriptSource: string, + location: SnippetLocation, + strict: boolean, + parameters: Record = {}, +): TypeScriptSnippet { + const [source, sourceParameters] = parametersFromSourceDirectives(typeScriptSource); + const visibleSource = source.trimRight(); + + return { + visibleSource, + location, + parameters: Object.assign({}, parameters, sourceParameters), + strict, + }; +} + /** * Construct a TypeScript snippet from literal source * - * Will parse parameters from a directive in the given source. + * @deprecated Use `typeScriptSnippetFromVisibleSource` */ export function typeScriptSnippetFromSource( typeScriptSource: string, location: SnippetLocation, strict: boolean, parameters: Record = {}, +): TypeScriptSnippet { + return typeScriptSnippetFromVisibleSource(typeScriptSource, location, strict, parameters); +} + +/** + * Construct a TypeScript snippet from complete source + * + * Will parse parameters from a directive in the given source, and will + * interpret `/// !show` and `/// !hide` directives. + * + * The snippet's cache key will be based on the source that remains after + * these directives are processed. + * + * Use this if you are building a snippet to be translated, and take care + * to store the return object's `visibleSource` in the assembly (not the original + * source you passed in). + */ +export function typeScriptSnippetFromCompleteSource( + typeScriptSource: string, + location: SnippetLocation, + strict: boolean, + parameters: Record = {}, ): TypeScriptSnippet { const [source, sourceParameters] = parametersFromSourceDirectives(typeScriptSource); + const completeSource = source.trimRight(); + + const visibleSource = trimCompleteSourceToVisible(completeSource); + return { - visibleSource: source.trimRight(), + visibleSource, + completeSource: visibleSource !== completeSource ? completeSource : undefined, location, parameters: Object.assign({}, parameters, sourceParameters), strict, diff --git a/packages/jsii-rosetta/lib/tablets/tablets.ts b/packages/jsii-rosetta/lib/tablets/tablets.ts index 38e192906e..ff13c60673 100644 --- a/packages/jsii-rosetta/lib/tablets/tablets.ts +++ b/packages/jsii-rosetta/lib/tablets/tablets.ts @@ -2,7 +2,7 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import { TargetLanguage } from '../languages'; -import { TypeScriptSnippet, SnippetLocation } from '../snippet'; +import { TypeScriptSnippet, SnippetLocation, completeSource } from '../snippet'; import { mapValues } from '../util'; import { snippetKey } from './key'; import { TabletSchema, TranslatedSnippetSchema, ORIGINAL_SNIPPET_KEY } from './schema'; @@ -18,12 +18,28 @@ export const CURRENT_SCHEMA_VERSION = '2'; * A tablet containing various snippets in multiple languages */ export class LanguageTablet { + /** + * Load a tablet from a file + */ public static async fromFile(filename: string) { const ret = new LanguageTablet(); await ret.load(filename); return ret; } + /** + * Load a tablet from a file that may not exist + * + * Will return an empty tablet if the file does not exist + */ + public static async fromOptionalFile(filename: string) { + const ret = new LanguageTablet(); + if (fs.existsSync(filename)) { + await ret.load(filename); + } + return ret; + } + private readonly snippets: Record = {}; public addSnippet(snippet: TranslatedSnippet) { @@ -35,15 +51,46 @@ export class LanguageTablet { return Object.keys(this.snippets); } + /** + * Add all snippets from the given tablet into this one + */ + public addTablet(tablet: LanguageTablet) { + for (const snippet of Object.values(tablet.snippets)) { + this.addSnippet(snippet); + } + } + public tryGetSnippet(key: string): TranslatedSnippet | undefined { return this.snippets[key]; } + /** + * Look up a single translation of a source snippet + * + * @deprecated Use `lookupTranslationBySource` instead. + */ public lookup(typeScriptSource: TypeScriptSnippet, language: TargetLanguage): Translation | undefined { + return this.lookupTranslationBySource(typeScriptSource, language); + } + + /** + * Look up a single translation of a source snippet + */ + public lookupTranslationBySource( + typeScriptSource: TypeScriptSnippet, + language: TargetLanguage, + ): Translation | undefined { const snippet = this.snippets[snippetKey(typeScriptSource)]; return snippet?.get(language); } + /** + * Lookup the translated verion of a TypeScript snippet + */ + public lookupBySource(typeScriptSource: TypeScriptSnippet): TranslatedSnippet | undefined { + return this.snippets[snippetKey(typeScriptSource)]; + } + public async load(filename: string) { const obj = (await fs.readJson(filename, { encoding: 'utf-8' })) as TabletSchema; @@ -101,7 +148,7 @@ export class TranslatedSnippet { }, didCompile: didCompile, location: original.location, - fullSource: original.completeSource, + fullSource: completeSource(original), }); } diff --git a/packages/jsii-rosetta/lib/translate.ts b/packages/jsii-rosetta/lib/translate.ts index c12ae6046d..5232512979 100644 --- a/packages/jsii-rosetta/lib/translate.ts +++ b/packages/jsii-rosetta/lib/translate.ts @@ -67,7 +67,7 @@ export class Translator { location: snip.location, didCompile: translator.didSuccessfullyCompile, fqnsReferenced: translator.fqnsReferenced(), - fullSource: snip.completeSource, + fullSource: completeSource(snip), syntaxKindCounter: translator.syntaxKindCounter(), }); } @@ -152,6 +152,7 @@ export class SnippetTranslator { public readonly compileDiagnostics: ts.Diagnostic[] = []; private readonly visibleSpans: Spans; private readonly compilation!: CompilationResult; + private readonly tryCompile: boolean; public constructor(snippet: TypeScriptSnippet, private readonly options: SnippetTranslatorOptions = {}) { const compiler = options.compiler ?? new TypeScriptCompiler(); @@ -170,7 +171,9 @@ export class SnippetTranslator { this.visibleSpans = Spans.visibleSpansFromSource(source); // This makes it about 5x slower, so only do it on demand - if (options.includeCompilerDiagnostics || snippet.strict) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + this.tryCompile = (options.includeCompilerDiagnostics || snippet.strict) ?? false; + if (this.tryCompile) { const program = this.compilation.program; const diagnostics = [ ...neverThrowing(program.getGlobalDiagnostics)(), @@ -196,7 +199,7 @@ export class SnippetTranslator { try { return call(...args); } catch (err) { - const isExpectedTypescriptError = err.message.includes('Error: Debug Failure'); + const isExpectedTypescriptError = err.message.includes('Debug Failure'); if (!isExpectedTypescriptError) { console.error(`Failed to execute ${call.name}: ${err}`); @@ -208,8 +211,11 @@ export class SnippetTranslator { } } + /** + * Returns a boolean if compilation was attempted, and undefined if it was not. + */ public get didSuccessfullyCompile() { - return this.compileDiagnostics.length === 0; + return this.tryCompile ? this.compileDiagnostics.length === 0 : undefined; } public renderUsing(visitor: AstHandler) { diff --git a/packages/jsii-rosetta/lib/translate_all.ts b/packages/jsii-rosetta/lib/translate_all.ts new file mode 100644 index 0000000000..84081689e6 --- /dev/null +++ b/packages/jsii-rosetta/lib/translate_all.ts @@ -0,0 +1,80 @@ +import * as os from 'os'; +import * as path from 'path'; +import * as workerpool from 'workerpool'; + +import * as logging from './logging'; +import { TypeScriptSnippet } from './snippet'; +import { TranslatedSnippet } from './tablets/tablets'; +import { RosettaDiagnostic } from './translate'; +import type { TranslateBatchRequest, TranslateBatchResponse } from './translate_all_worker'; + +/** + * Divide the work evenly over all processors by running 'translate_all_worker' in Worker Threads, then combine results + * + * The workers are fed small queues of work each. We used to divide the entire queue into N + * but since the work is divided unevenly that led to some workers stopping early, idling while + * waiting for more work. + * + * Never include 'translate_all_worker' directly, only do TypeScript type references (so that in + * the script we may assume that 'worker_threads' successfully imports). + */ +export async function translateAll( + snippets: TypeScriptSnippet[], + includeCompilerDiagnostics: boolean, +): Promise { + // Use about half the advertised cores because hyperthreading doesn't seem to + // help that much, or we become I/O-bound at some point. On my machine, using + // more than half the cores actually makes it slower. + // Cap to a reasonable top-level limit to prevent thrash on machines with many, many cores. + const maxWorkers = parseInt(process.env.JSII_ROSETTA_MAX_WORKER_COUNT ?? '16'); + const N = Math.min(maxWorkers, Math.max(1, Math.ceil(os.cpus().length / 2))); + const snippetArr = Array.from(snippets); + logging.info(`Translating ${snippetArr.length} snippets using ${N} workers`); + + const pool = workerpool.pool(path.join(__dirname, 'translate_all_worker.js'), { + maxWorkers: N, + }); + + try { + const requests = batchSnippets(snippetArr, includeCompilerDiagnostics); + + const responses: TranslateBatchResponse[] = await Promise.all( + requests.map((request) => pool.exec('translateBatch', [request])), + ); + + const diagnostics = new Array(); + const translatedSnippets = new Array(); + + // Combine results + for (const response of responses) { + diagnostics.push(...response.diagnostics); + translatedSnippets.push(...response.translatedSchemas.map(TranslatedSnippet.fromSchema)); + } + return { diagnostics, translatedSnippets }; + } finally { + // Not waiting on purpose + void pool.terminate(); + } +} + +function batchSnippets( + snippets: TypeScriptSnippet[], + includeCompilerDiagnostics: boolean, + batchSize = 10, +): TranslateBatchRequest[] { + const ret = []; + + for (let i = 0; i < snippets.length; i += batchSize) { + ret.push({ + snippets: snippets.slice(i, i + batchSize), + includeCompilerDiagnostics, + }); + } + + return ret; +} + +export interface TranslateAllResult { + translatedSnippets: TranslatedSnippet[]; + diagnostics: RosettaDiagnostic[]; +} diff --git a/packages/jsii-rosetta/lib/translate_all_worker.ts b/packages/jsii-rosetta/lib/translate_all_worker.ts new file mode 100644 index 0000000000..b7f1d1bc58 --- /dev/null +++ b/packages/jsii-rosetta/lib/translate_all_worker.ts @@ -0,0 +1,60 @@ +/** + * Pool worker for extract.ts + */ +import * as workerpool from 'workerpool'; + +import { TypeScriptSnippet } from './snippet'; +import { TranslatedSnippetSchema } from './tablets/schema'; +import { TranslatedSnippet } from './tablets/tablets'; +import { RosettaDiagnostic, Translator, makeRosettaDiagnostic } from './translate'; +import { TranslateAllResult } from './translate_all'; + +export interface TranslateBatchRequest { + readonly snippets: TypeScriptSnippet[]; + readonly includeCompilerDiagnostics: boolean; +} + +export interface TranslateBatchResponse { + // Cannot be 'TranslatedSnippet' because needs to be serializable + readonly translatedSchemas: TranslatedSnippetSchema[]; + readonly diagnostics: RosettaDiagnostic[]; +} + +function translateBatch(request: TranslateBatchRequest): TranslateBatchResponse { + const result = singleThreadedTranslateAll(request.snippets, request.includeCompilerDiagnostics); + + return { + translatedSchemas: result.translatedSnippets.map((s) => s.snippet), + diagnostics: result.diagnostics, + }; +} + +/** + * Translate the given snippets using a single compiler + */ +export function singleThreadedTranslateAll( + snippets: TypeScriptSnippet[], + includeCompilerDiagnostics: boolean, +): TranslateAllResult { + const translatedSnippets = new Array(); + + const failures = new Array(); + + const translator = new Translator(includeCompilerDiagnostics); + for (const block of snippets) { + try { + translatedSnippets.push(translator.translate(block)); + } catch (e) { + failures.push( + makeRosettaDiagnostic(true, `rosetta: error translating snippet: ${e}\n${e.stack}\n${block.completeSource}`), + ); + } + } + + return { + translatedSnippets, + diagnostics: [...translator.diagnostics, ...failures], + }; +} + +workerpool.worker({ translateBatch }); diff --git a/packages/jsii-rosetta/lib/typescript/ts-compiler.ts b/packages/jsii-rosetta/lib/typescript/ts-compiler.ts index 0ad5b91637..134c5adf3a 100644 --- a/packages/jsii-rosetta/lib/typescript/ts-compiler.ts +++ b/packages/jsii-rosetta/lib/typescript/ts-compiler.ts @@ -3,6 +3,11 @@ import * as ts from 'typescript'; export class TypeScriptCompiler { private readonly realHost = ts.createCompilerHost(STANDARD_COMPILER_OPTIONS, true); + /** + * A compiler-scoped cache to avoid having to re-parse the same library files for every compilation + */ + private readonly fileCache = new Map(); + public createInMemoryCompilerHost( sourcePath: string, sourceContents: string, @@ -13,12 +18,23 @@ export class TypeScriptCompiler { return { ...realHost, - fileExists: (filePath) => filePath === sourcePath || realHost.fileExists(filePath), + fileExists: (filePath) => + filePath === sourcePath || this.fileCache.has(filePath) || realHost.fileExists(filePath), getCurrentDirectory: currentDirectory != null ? () => currentDirectory : realHost.getCurrentDirectory, - getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => - fileName === sourcePath - ? sourceFile - : realHost.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile), + getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { + if (fileName === sourcePath) { + return sourceFile; + } + + const existing = this.fileCache.get(fileName); + if (existing) { + return existing; + } + + const parsed = realHost.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); + this.fileCache.set(fileName, parsed); + return parsed; + }, readFile: (filePath) => (filePath === sourcePath ? sourceContents : realHost.readFile(filePath)), writeFile: () => void undefined, }; diff --git a/packages/jsii-rosetta/lib/typescript/visible-spans.ts b/packages/jsii-rosetta/lib/typescript/visible-spans.ts index d7fb6cb7b1..3a69280ef5 100644 --- a/packages/jsii-rosetta/lib/typescript/visible-spans.ts +++ b/packages/jsii-rosetta/lib/typescript/visible-spans.ts @@ -85,6 +85,15 @@ export class Spans { } } +export function trimCompleteSourceToVisible(source: string): string { + const spans = Spans.visibleSpansFromSource(source); + + return spans.spans + .map((span) => source.substring(span.start, span.end)) + .join('') + .trimRight(); +} + export interface MarkedSpan { start: number; end: number; @@ -92,7 +101,7 @@ export interface MarkedSpan { } function calculateMarkedSpans(source: string): MarkedSpan[] { - const regEx = /[/]{3}[ \t]*(!(?:show|hide))[ \t]*$/gm; + const regEx = /^[ \t]*[/]{3}[ \t]*(!(?:show|hide))[ \t]*$/gm; const ret = new Array(); let match; @@ -111,7 +120,9 @@ function calculateMarkedSpans(source: string): MarkedSpan[] { ret.push({ start: spanStart, end: directiveStart, visible }); } visible = isShow; - spanStart = match.index + match[0].length; + + // A directive eats its trailing newline. + spanStart = match.index + match[0].length + 1; } } @@ -119,7 +130,7 @@ function calculateMarkedSpans(source: string): MarkedSpan[] { ret.push({ start: spanStart ?? 0, end: source.length, visible }); // Filter empty spans and return - return ret.filter((s) => s.start !== s.end); + return ret.filter((s) => s.start < s.end); } /** diff --git a/packages/jsii-rosetta/lib/util.ts b/packages/jsii-rosetta/lib/util.ts index 9642757a9d..9ae8f9db6a 100644 --- a/packages/jsii-rosetta/lib/util.ts +++ b/packages/jsii-rosetta/lib/util.ts @@ -12,9 +12,16 @@ export interface File { } export function printDiagnostics(diags: readonly RosettaDiagnostic[], stream: NodeJS.WritableStream) { - for (const diag of diags) { + // Don't print too much, at some point it just clogs up the log + const maxDiags = 50; + + for (const diag of diags.slice(maxDiags)) { stream.write(diag.formattedMessage); } + + if (diags.length > maxDiags) { + stream.write(`(...and ${maxDiags - diags.length} more diagnostics not shown)`); + } } export const StrictBrand = 'jsii.strict'; diff --git a/packages/jsii-rosetta/test/commands/extract.test.ts b/packages/jsii-rosetta/test/commands/extract.test.ts index 089de4f40b..0969adb715 100644 --- a/packages/jsii-rosetta/test/commands/extract.test.ts +++ b/packages/jsii-rosetta/test/commands/extract.test.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { LanguageTablet } from '../../lib'; +import { LanguageTablet, RosettaTranslator, RosettaTranslatorOptions } from '../../lib'; import * as extract from '../../lib/commands/extract'; import { TARGET_LANGUAGES } from '../../lib/languages'; import { TestJsiiModule, DUMMY_ASSEMBLY_TARGETS } from '../testutil'; @@ -71,7 +71,7 @@ describe('with cache file', () => { await extract.extractSnippets([assembly.moduleDirectory], { outputFile: path.join(assembly.moduleDirectory, 'dummy.tabl.json'), cacheTabletFile, - translationFunction, + translatorFactory: (o) => new MockTranslator(o, translationFunction), ...defaultExtractOptions, }); @@ -87,7 +87,7 @@ describe('with cache file', () => { await extract.extractSnippets([assembly.moduleDirectory], { outputFile: path.join(assembly.moduleDirectory, 'dummy.tabl.json'), cacheTabletFile, - translationFunction, + translatorFactory: (o) => new MockTranslator(o, translationFunction), ...defaultExtractOptions, }); @@ -133,3 +133,10 @@ test('do not ignore example strings', async () => { await assembly.cleanup(); } }); + +class MockTranslator extends RosettaTranslator { + public constructor(opts: RosettaTranslatorOptions, translatorFn: jest.Mock) { + super(opts); + this.translateAll = translatorFn; + } +} diff --git a/packages/jsii-rosetta/test/commands/transliterate.test.ts b/packages/jsii-rosetta/test/commands/transliterate.test.ts index 3fcd5d8109..86fbac3a16 100644 --- a/packages/jsii-rosetta/test/commands/transliterate.test.ts +++ b/packages/jsii-rosetta/test/commands/transliterate.test.ts @@ -1,11 +1,11 @@ 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'; +import { withTemporaryDirectory } from '../testutil'; jest.setTimeout(60_000); @@ -1339,8 +1339,3 @@ new SampleClass('omitted-literate'); `, ); })); - -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/jsii/visible-spans.test.ts b/packages/jsii-rosetta/test/jsii/visible-spans.test.ts index 3adb5e63c6..d8bf05dc69 100644 --- a/packages/jsii-rosetta/test/jsii/visible-spans.test.ts +++ b/packages/jsii-rosetta/test/jsii/visible-spans.test.ts @@ -1,4 +1,4 @@ -import { Spans } from '../../lib/typescript/visible-spans'; +import { Spans, trimCompleteSourceToVisible } from '../../lib/typescript/visible-spans'; test('full text visible by default', () => { const vis = Spans.visibleSpansFromSource('asdf'); @@ -11,8 +11,11 @@ test('initial span visible if directive is hiding', () => { }); test('initial span invisible if directive is showing', () => { + const s = 'asdf\n/// !show\nxyz'; const vis = Spans.visibleSpansFromSource('asdf\n/// !show\nxyz'); - expect(vis.spans).toEqual([{ start: 14, end: 18, visible: true }]); + + expect(s.substring(vis.spans[0].start, vis.spans[0].end)).toEqual('xyz'); + expect(vis.spans).toEqual([{ start: 15, end: 18, visible: true }]); }); test('merge adjacent spans', () => { @@ -23,3 +26,27 @@ test('merge adjacent spans', () => { expect(spans.spans).toEqual([{ start: 10, end: 20 }]); }); + +test('trim source to spans', () => { + const source = ['a', '/// !show', 'b', 'c', '/// !hide', 'd'].join('\n'); + + const trimmed = trimCompleteSourceToVisible(source); + + expect(trimmed).toEqual('b\nc'); +}); + +test('trim source to spans with leading whitespace ', () => { + const source = ['a', ' /// !show', 'b', 'c', ' /// !hide', 'd'].join('\n'); + + const trimmed = trimCompleteSourceToVisible(source); + + expect(trimmed).toEqual('b\nc'); +}); + +test('trim source to spans with trailing whitespace ', () => { + const source = ['a', '/// !show ', 'b', 'c', ' /// !hide ', 'd'].join('\n'); + + const trimmed = trimCompleteSourceToVisible(source); + + expect(trimmed).toEqual('b\nc'); +}); diff --git a/packages/jsii-rosetta/test/rosetta-translator.test.ts b/packages/jsii-rosetta/test/rosetta-translator.test.ts new file mode 100644 index 0000000000..3397dc40d1 --- /dev/null +++ b/packages/jsii-rosetta/test/rosetta-translator.test.ts @@ -0,0 +1,39 @@ +import { RosettaTranslator, typeScriptSnippetFromVisibleSource, SnippetLocation, TargetLanguage } from '../lib'; +import { withTemporaryDirectory } from './testutil'; + +const location: SnippetLocation = { api: { api: 'file', fileName: 'test.ts' } }; + +test('translator can translate', async () => { + const translator = new RosettaTranslator({ + includeCompilerDiagnostics: true, + }); + + const snippet = typeScriptSnippetFromVisibleSource('console.log("hello world");', location, true); + + const { translatedSnippets } = await translator.translateAll([snippet]); + + expect(translatedSnippets).toHaveLength(1); + expect(translatedSnippets[0].get(TargetLanguage.PYTHON)?.source).toEqual('print("hello world")'); + + expect(translator.tablet.snippetKeys).toHaveLength(1); +}); + +test('translator can read from cache', async () => { + await withTemporaryDirectory(async () => { + // GIVEN: prepare cache + const cacheBuilder = new RosettaTranslator({ includeCompilerDiagnostics: true }); + const snippet = typeScriptSnippetFromVisibleSource('console.log("hello world");', location, true); + await cacheBuilder.translateAll([snippet]); + await cacheBuilder.tablet.save('temp.tabl.json'); + + // WHEN: new translatro + const translator = new RosettaTranslator({ includeCompilerDiagnostics: true }); + await translator.loadCache('temp.tabl.json'); + + const cached = translator.readFromCache([snippet]); + + expect(cached.translations).toHaveLength(1); + expect(cached.remaining).toHaveLength(0); + expect(translator.tablet.snippetKeys).toHaveLength(1); + }); +}); diff --git a/packages/jsii-rosetta/test/snippet.test.ts b/packages/jsii-rosetta/test/snippet.test.ts new file mode 100644 index 0000000000..7c38288f6b --- /dev/null +++ b/packages/jsii-rosetta/test/snippet.test.ts @@ -0,0 +1,20 @@ +import { typeScriptSnippetFromVisibleSource, SnippetLocation, typeScriptSnippetFromCompleteSource } from '../lib'; + +describe('construct TypeScriptSnippets', () => { + const source = ['a', '/// !show', 'b', '/// !hide', 'c'].join('\n'); + const location: SnippetLocation = { api: { api: 'file', fileName: 'x' } }; + + test('using typeScriptSnippetFromVisibleSource', () => { + const snippet = typeScriptSnippetFromVisibleSource(source, location, true); + + expect(snippet.visibleSource).toEqual(source); + expect(snippet.completeSource).toEqual(undefined); + }); + + test('using typeScriptSnippetFromCompleteSource', () => { + const snippet = typeScriptSnippetFromCompleteSource(source, location, true); + + expect(snippet.visibleSource).toEqual('b'); + expect(snippet.completeSource).toEqual(source); + }); +}); diff --git a/packages/jsii-rosetta/test/testutil.ts b/packages/jsii-rosetta/test/testutil.ts index 130b4a4514..ff39f98007 100644 --- a/packages/jsii-rosetta/test/testutil.ts +++ b/packages/jsii-rosetta/test/testutil.ts @@ -103,3 +103,8 @@ export const DUMMY_ASSEMBLY_TARGETS = { module: 'example_test_demo', }, }; + +export 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/translate.test.ts b/packages/jsii-rosetta/test/translate.test.ts index e3b2733b6e..7643b9caab 100644 --- a/packages/jsii-rosetta/test/translate.test.ts +++ b/packages/jsii-rosetta/test/translate.test.ts @@ -112,3 +112,35 @@ test('Snippets from different locations have different keys', () => { expect(snippetKey(snippet1)).not.toEqual(snippetKey(snippet2)); }); + +test('didSuccessfullyCompile is true when compilation is attempted', () => { + const visibleSource = 'console.log("banana");'; + + const snippet: TypeScriptSnippet = { + visibleSource, + location: { api: { api: 'type', fqn: 'my.class' } }, + }; + + // WHEN + const subject = new SnippetTranslator(snippet, { + includeCompilerDiagnostics: true, + }); + subject.renderUsing(new PythonVisitor()); + + expect(subject.didSuccessfullyCompile).toBeTruthy(); +}); + +test('didSuccessfullyCompile is undefined when compilation is not attempted', () => { + const visibleSource = 'console.log("banana");'; + + const snippet: TypeScriptSnippet = { + visibleSource, + location: { api: { api: 'type', fqn: 'my.class' } }, + }; + + // WHEN + const subject = new SnippetTranslator(snippet); + subject.renderUsing(new PythonVisitor()); + + expect(subject.didSuccessfullyCompile).toBeUndefined(); +}); diff --git a/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.cs b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.cs new file mode 100644 index 0000000000..c025c12f76 --- /dev/null +++ b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.cs @@ -0,0 +1,6 @@ +Takes(new MyProps { + Struct = new SomeStruct { + Enabled = false, + Option = "option" + } +}); \ No newline at end of file diff --git a/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.java b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.java new file mode 100644 index 0000000000..63cae00c12 --- /dev/null +++ b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.java @@ -0,0 +1,6 @@ +takes(MyProps.builder() + .struct(SomeStruct.builder() + .enabled(false) + .option("option") + .build()) + .build()); \ No newline at end of file diff --git a/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.py b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.py new file mode 100644 index 0000000000..262592b3f4 --- /dev/null +++ b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.py @@ -0,0 +1,6 @@ +takes( + struct=SomeStruct( + enabled=False, + option="option" + ) +) \ No newline at end of file diff --git a/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.ts b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.ts new file mode 100644 index 0000000000..a03ae03f9b --- /dev/null +++ b/packages/jsii-rosetta/test/translations/structs/infer_struct_from_union.ts @@ -0,0 +1,29 @@ +/// !hide +/// fake-from-jsii +interface IResolvable { + resolve(): any; +} + +/// fake-from-jsii +interface SomeStruct { + readonly enabled: boolean | IResolvable; + readonly option?: string | IResolvable; +} + +/// fake-from-jsii +interface MyProps { + readonly struct?: IResolvable | SomeStruct; +} + +function takes(props: MyProps) { +} +/// !show + +takes({ + struct: { + enabled: false, + option: 'option', + }, +}); + + diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index 675653ad4e..c3c0de3c53 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -3213,7 +3213,13 @@ function inferRootDir(program: ts.Program): string | undefined { .map((fileName) => path.relative(program.getCurrentDirectory(), path.dirname(fileName)), ) - .map(segmentPath); + .map(segmentPath) + // Dependency entry points are in this path, and they MAY resolve from the + // same mono-repo, in which case they won't appear to be external libraries, + // as there may not be a `/node_modules/` segment in their canonical path. + // They well however come from a parent directory, so their path segments + // will start with "..". + .filter(([head]) => head !== '..'); const maxPrefix = Math.min( ...directories.map((segments) => segments.length - 1), diff --git a/packages/jsii/lib/compiler.ts b/packages/jsii/lib/compiler.ts index aaae7f1799..7f443f3ee9 100644 --- a/packages/jsii/lib/compiler.ts +++ b/packages/jsii/lib/compiler.ts @@ -133,11 +133,15 @@ export class Compiler implements Emitter { const pi = this.options.projectInfo; const projectRoot = pi.projectRoot; const host = ts.createWatchCompilerHost( - this.configPath, + this.rootFiles, { ...pi.tsc, ...BASE_COMPILER_OPTIONS, noEmitOnError: false, + tsBuildInfoFile: path.join( + pi.tsc?.outDir ?? pi.tsc?.rootDir ?? pi.projectRoot, + 'tsconfig.tsbuildinfo', + ), }, { ...ts.sys, @@ -148,6 +152,7 @@ export class Compiler implements Emitter { ts.createEmitAndSemanticDiagnosticsBuilderProgram, opts?.reportDiagnostics, opts?.reportWatchStatus, + this.typescriptConfig?.references, ); if (!host.getDefaultLibLocation) { throw new Error( @@ -495,23 +500,47 @@ export class Compiler implements Emitter { * This makes it so that running 'tsc' and running 'jsii' has the same behavior. */ private determineSources(files: string[]): string[] { - const ret = new Array(); + const ret = new Set(); if (files.length > 0) { - ret.push(...files); + for (const file of files) { + ret.add(path.resolve(this.options.projectInfo.projectRoot, file)); + } } else { const parseConfigHost = parseConfigHostFromCompilerHost( this.compilerHost, ); - const parsed = ts.parseJsonConfigFileContent( + // Note: the fileNames here are resolved by the parseConfigHost. + const { fileNames } = ts.parseJsonConfigFileContent( this.typescriptConfig, parseConfigHost, this.options.projectInfo.projectRoot, ); - ret.push(...parsed.fileNames); + for (const file of fileNames) { + ret.add(file); + } } - return ret; + // Bonus: ensure all dependencies' entry points are included in the compiler + // input path. This guarantees we have symbols for all types, from the + // module root, which is necessary in order to properly detect submodules. + for (const assm of this.options.projectInfo.dependencyClosure) { + const { resolvedModule } = ts.resolveModuleName( + assm.name, + path.join( + this.options.projectInfo.projectRoot, + this.options.projectInfo.types, + ), + this.typescriptConfig?.compilerOptions ?? {}, + ts.sys, + ); + if (!resolvedModule) { + continue; + } + ret.add(resolvedModule.resolvedFileName); + } + + return Array.from(ret); } /** diff --git a/packages/jsii/lib/node-bindings.ts b/packages/jsii/lib/node-bindings.ts index a92984b2f7..ae7721577f 100644 --- a/packages/jsii/lib/node-bindings.ts +++ b/packages/jsii/lib/node-bindings.ts @@ -99,6 +99,15 @@ export const getParameterRelatedNode: ( | ts.PropertySignature | undefined = getRelatedNode; +export const getPropertyRelatedNode: ( + object: spec.Parameter, +) => + | ts.AccessorDeclaration + | ts.ParameterPropertyDeclaration + | ts.PropertyDeclaration + | ts.PropertySignature + | undefined = getRelatedNode; + export const getTypeRelatedNode: ( object: spec.Type, ) => diff --git a/packages/jsii/lib/transforms/deprecation-warnings.ts b/packages/jsii/lib/transforms/deprecation-warnings.ts index 07c0e01ee0..253419d433 100644 --- a/packages/jsii/lib/transforms/deprecation-warnings.ts +++ b/packages/jsii/lib/transforms/deprecation-warnings.ts @@ -74,97 +74,17 @@ export class DeprecationWarningsInjector { } } } else if (spec.isInterfaceType(type) && type.datatype) { - for (const prop of Object.values(type.properties ?? {})) { - if (spec.isDeprecated(prop) || spec.isDeprecated(type)) { - // If the property individually is deprecated, or the entire type is deprecated - const deprecatedDocs = - prop.docs?.deprecated ?? type.docs?.deprecated; - statements.push( - createWarningFunctionCall( - `${type.fqn}#${prop.name}`, - deprecatedDocs, - ts.createIdentifier(`"${prop.name}" in ${PARAMETER_NAME}`), - ), - ); - isEmpty = false; - } - - if ( - spec.isNamedTypeReference(prop.type) && - Object.keys(types).includes(prop.type.fqn) - ) { - const functionName = importedFunctionName( - prop.type.fqn, - assembly, - projectInfo, - ); - if (functionName) { - statements.push( - createTypeHandlerCall( - functionName, - `${PARAMETER_NAME}.${prop.name}`, - ), - ); - isEmpty = false; - } - } else if ( - spec.isCollectionTypeReference(prop.type) && - spec.isNamedTypeReference(prop.type.collection.elementtype) - ) { - const functionName = importedFunctionName( - prop.type.collection.elementtype.fqn, - assembly, - projectInfo, - ); - if (functionName) { - statements.push( - createTypeHandlerCall( - functionName, - `${PARAMETER_NAME}.${prop.name}`, - ), - ); - isEmpty = false; - } - } else if ( - spec.isUnionTypeReference(prop.type) && - spec.isNamedTypeReference(prop.type.union.types[0]) && - Object.keys(types).includes(prop.type.union.types[0].fqn) - ) { - const functionName = importedFunctionName( - prop.type.union.types[0].fqn, - assembly, - projectInfo, - ); - if (functionName) { - statements.push( - createTypeHandlerCall( - functionName, - `${PARAMETER_NAME}.${prop.name}`, - ), - ); - isEmpty = false; - } - } + const { statementsByProp, excludedProps } = processInterfaceType( + type, + types, + assembly, + projectInfo, + ); - // We also generate calls to all the supertypes - for (const iface of type.interfaces ?? []) { - const functionName = importedFunctionName( - iface, - assembly, - projectInfo, - ); - if (functionName) { - statements.push( - ts.createExpressionStatement( - ts.createCall( - ts.createIdentifier(functionName), - [], - [ts.createIdentifier(PARAMETER_NAME)], - ), - ), - ); - isEmpty = false; - } + for (const [name, statement] of statementsByProp.entries()) { + if (!excludedProps.has(name)) { + statements.push(statement); + isEmpty = false; } } } @@ -232,6 +152,102 @@ export class DeprecationWarningsInjector { } } +function processInterfaceType( + type: spec.InterfaceType, + types: { [p: string]: spec.Type }, + assembly: Assembly, + projectInfo: ProjectInfo, + statementsByProp: Map = new Map(), + excludedProps: Set = new Set(), +) { + for (const prop of Object.values(type.properties ?? {})) { + const fqn = `${type.fqn}#${prop.name}`; + if (spec.isDeprecated(prop) || spec.isDeprecated(type)) { + // If the property individually is deprecated, or the entire type is deprecated + const deprecatedDocs = prop.docs?.deprecated ?? type.docs?.deprecated; + const statement = createWarningFunctionCall( + fqn, + deprecatedDocs, + ts.createIdentifier(`"${prop.name}" in ${PARAMETER_NAME}`), + ); + statementsByProp.set(prop.name, statement); + } else { + /* If a prop is not deprecated, we don't want to generate a warning for it, + even if another property with the same name is deprecated in another + super-interface. */ + excludedProps.add(prop.name); + } + + if ( + spec.isNamedTypeReference(prop.type) && + Object.keys(types).includes(prop.type.fqn) + ) { + const functionName = importedFunctionName( + prop.type.fqn, + assembly, + projectInfo, + ); + if (functionName) { + const statement = createTypeHandlerCall( + functionName, + `${PARAMETER_NAME}.${prop.name}`, + ); + statementsByProp.set(`${prop.name}_`, statement); + } + } else if ( + spec.isCollectionTypeReference(prop.type) && + spec.isNamedTypeReference(prop.type.collection.elementtype) + ) { + const functionName = importedFunctionName( + prop.type.collection.elementtype.fqn, + assembly, + projectInfo, + ); + if (functionName) { + const statement = createTypeHandlerCall( + functionName, + `${PARAMETER_NAME}.${prop.name}`, + ); + statementsByProp.set(`${prop.name}_`, statement); + } + } else if ( + spec.isUnionTypeReference(prop.type) && + spec.isNamedTypeReference(prop.type.union.types[0]) && + Object.keys(types).includes(prop.type.union.types[0].fqn) + ) { + const functionName = importedFunctionName( + prop.type.union.types[0].fqn, + assembly, + projectInfo, + ); + if (functionName) { + const statement = createTypeHandlerCall( + functionName, + `${PARAMETER_NAME}.${prop.name}`, + ); + statementsByProp.set(`${prop.name}_`, statement); + } + } + } + + // We also generate calls to all the supertypes + for (const interfaceName of type.interfaces ?? []) { + const assemblies = projectInfo.dependencyClosure.concat(assembly); + const superType = findType(interfaceName, assemblies); + if (superType.type) { + processInterfaceType( + superType.type as spec.InterfaceType, + types, + assembly, + projectInfo, + statementsByProp, + excludedProps, + ); + } + } + return { statementsByProp, excludedProps }; +} + function fnName(fqn: string): string { return fqn.replace(/[^\w\d]/g, '_'); } diff --git a/packages/jsii/lib/validator.ts b/packages/jsii/lib/validator.ts index 998c6b8fb7..3442e0793a 100644 --- a/packages/jsii/lib/validator.ts +++ b/packages/jsii/lib/validator.ts @@ -7,6 +7,7 @@ import * as ts from 'typescript'; import { Emitter } from './emitter'; import { JsiiDiagnostic } from './jsii-diagnostic'; import { getRelatedNode } from './node-bindings'; +import * as bindings from './node-bindings'; import { ProjectInfo } from './project-info'; export class Validator implements Emitter { @@ -187,7 +188,8 @@ function _defaultValidations(): ValidationFunction[] { if (assembly.name === assm) { if (!(typeRef.fqn in (assembly.types ?? {}))) { diagnostic( - JsiiDiagnostic.JSII_3000_EXPORTED_API_USES_HIDDEN_TYPE.createDetached( + JsiiDiagnostic.JSII_3000_EXPORTED_API_USES_HIDDEN_TYPE.create( + typeRef.node!, // Pretend there is always a value typeRef.fqn, ), ); @@ -607,39 +609,85 @@ function _allMembers( return [..._allMethods(assm), ..._allProperties(assm)]; } -function _allTypeReferences(assm: spec.Assembly): spec.NamedTypeReference[] { - const typeReferences = new Array(); +interface AnnotatedTypeReference extends spec.NamedTypeReference { + readonly node: ts.Node | undefined; +} + +function _allTypeReferences( + assm: spec.Assembly, +): readonly AnnotatedTypeReference[] { + const typeReferences = new Array(); for (const type of _allTypes(assm)) { if (!spec.isClassOrInterfaceType(type)) { continue; } - if (spec.isClassType(type) && type.base) { - typeReferences.push({ fqn: type.base }); + if (spec.isClassType(type)) { + const node = bindings.getClassRelatedNode(type); + if (type.base) { + typeReferences.push({ + fqn: type.base, + node: node?.heritageClauses?.find( + (hc) => hc.token === ts.SyntaxKind.ExtendsKeyword, + )?.types[0], + }); + } + if (type.initializer?.parameters) { + for (const param of type.initializer.parameters) { + _collectTypeReferences( + param.type, + bindings.getParameterRelatedNode(param)?.type, + ); + } + } } if (type.interfaces) { - type.interfaces.forEach((iface) => typeReferences.push({ fqn: iface })); + const node = bindings.getClassOrInterfaceRelatedNode(type); + type.interfaces.forEach((iface) => + typeReferences.push({ + fqn: iface, + node: node?.heritageClauses?.find( + (hc) => + hc.token === + (spec.isInterfaceType(type) + ? ts.SyntaxKind.ImplementsKeyword + : ts.SyntaxKind.ExtendsKeyword), + ), + }), + ); } } for (const { member: prop } of _allProperties(assm)) { - _collectTypeReferences(prop.type); + _collectTypeReferences( + prop.type, + bindings.getPropertyRelatedNode(prop)?.type, + ); } for (const { member: meth } of _allMethods(assm)) { if (meth.returns) { - _collectTypeReferences(meth.returns.type); + _collectTypeReferences( + meth.returns.type, + bindings.getMethodRelatedNode(meth)?.type, + ); } for (const param of meth.parameters ?? []) { - _collectTypeReferences(param.type); + _collectTypeReferences( + param.type, + bindings.getParameterRelatedNode(param)?.type, + ); } } return typeReferences; - function _collectTypeReferences(type: spec.TypeReference): void { + function _collectTypeReferences( + type: spec.TypeReference, + node: ts.Node | undefined, + ): void { if (spec.isNamedTypeReference(type)) { - typeReferences.push(type); + typeReferences.push({ ...type, node }); } else if (spec.isCollectionTypeReference(type)) { - _collectTypeReferences(type.collection.elementtype); + _collectTypeReferences(type.collection.elementtype, node); } else if (spec.isUnionTypeReference(type)) { - type.union.types.forEach(_collectTypeReferences); + type.union.types.forEach((type) => _collectTypeReferences(type, node)); } } } diff --git a/packages/jsii/test/__snapshots__/negatives.test.ts.snap b/packages/jsii/test/__snapshots__/negatives.test.ts.snap index 3ed8b6469c..9eaa50f870 100644 --- a/packages/jsii/test/__snapshots__/negatives.test.ts.snap +++ b/packages/jsii/test/__snapshots__/negatives.test.ts.snap @@ -107,10 +107,23 @@ error JSII8000: Type names must be CamelCased. Rename "myEnum" to "MyEnum" exports[`enum-name.2 1`] = ` error JSII8000: Type names must be CamelCased. Rename "My_Enum" to "MyEnum" +`; + +exports[`expose-unexported-type-constructor-param 1`] = ` +neg.expose-unexported-type-constructor-param.ts:6:29 - error JSII3000: Exported APIs cannot use un-exported type "jsii.UnexportedProps" + +6 public constructor(props: UnexportedProps) { + ~~~~~~~~~~~~~~~ + + `; exports[`expose-unexported-type-external 1`] = ` -error JSII3000: Exported APIs cannot use un-exported type "jsii.UnexportedType" +neg.expose-unexported-type-external.ts:7:14 - error JSII3000: Exported APIs cannot use un-exported type "jsii.UnexportedType" + +7 public p?: UnexportedType; + ~~~~~~~~~~~~~~ + `; @@ -641,6 +654,11 @@ error JSII8002: Method and property (unless they are static readonly) names must `; exports[`stripped-deprecated 1`] = ` +neg.stripped-deprecated.ts:11:25 - error JSII3000: Exported APIs cannot use un-exported type "jsii.DeprecatedInterface" + +11 public bad(parameter: DeprecatedInterface): DeprecatedInterface { + ~~~~~~~~~~~~~~~~~~~ + neg.stripped-deprecated.ts:11:25 - error JSII3999: Parameter has @deprecated type jsii.DeprecatedInterface, and it is erased by --strip-deprecated. 11 public bad(parameter: DeprecatedInterface): DeprecatedInterface { @@ -650,6 +668,11 @@ neg.stripped-deprecated.ts:11:25 - error JSII3999: Parameter has @deprecated typ 4 export interface DeprecatedInterface {} ~~~~~~~~~~~~~~~~~~~ The @deprecated type is declared here +neg.stripped-deprecated.ts:11:47 - error JSII3000: Exported APIs cannot use un-exported type "jsii.DeprecatedInterface" + +11 public bad(parameter: DeprecatedInterface): DeprecatedInterface { + ~~~~~~~~~~~~~~~~~~~ + neg.stripped-deprecated.ts:11:47 - error JSII3999: Method has @deprecated type jsii.DeprecatedInterface, and it is erased by --strip-deprecated. 11 public bad(parameter: DeprecatedInterface): DeprecatedInterface { @@ -659,6 +682,11 @@ neg.stripped-deprecated.ts:11:47 - error JSII3999: Method has @deprecated type j 4 export interface DeprecatedInterface {} ~~~~~~~~~~~~~~~~~~~ The @deprecated type is declared here +neg.stripped-deprecated.ts:7:17 - error JSII3000: Exported APIs cannot use un-exported type "jsii.DeprecatedInterface" + +7 public ouch?: DeprecatedInterface; + ~~~~~~~~~~~~~~~~~~~ + neg.stripped-deprecated.ts:7:17 - error JSII3999: Property has @deprecated type jsii.DeprecatedInterface, and it is erased by --strip-deprecated. 7 public ouch?: DeprecatedInterface; @@ -668,6 +696,11 @@ neg.stripped-deprecated.ts:7:17 - error JSII3999: Property has @deprecated type 4 export interface DeprecatedInterface {} ~~~~~~~~~~~~~~~~~~~ The @deprecated type is declared here +neg.stripped-deprecated.ts:9:42 - error JSII3000: Exported APIs cannot use un-exported type "jsii.DeprecatedInterface" + +9 public constructor(public readonly no: DeprecatedInterface) {} + ~~~~~~~~~~~~~~~~~~~ + neg.stripped-deprecated.ts:9:42 - error JSII3999: Parameter has @deprecated type jsii.DeprecatedInterface, and it is erased by --strip-deprecated. 9 public constructor(public readonly no: DeprecatedInterface) {} @@ -686,7 +719,6 @@ neg.stripped-deprecated.ts:9:42 - error JSII3999: Property has @deprecated type 4 export interface DeprecatedInterface {} ~~~~~~~~~~~~~~~~~~~ The @deprecated type is declared here -error JSII3000: Exported APIs cannot use un-exported type "jsii.DeprecatedInterface" `; diff --git a/packages/jsii/test/deprecation-warnings.test.ts b/packages/jsii/test/deprecation-warnings.test.ts index 537e134860..ded6bfc61b 100644 --- a/packages/jsii/test/deprecation-warnings.test.ts +++ b/packages/jsii/test/deprecation-warnings.test.ts @@ -195,28 +195,79 @@ function testpkg_Baz(p) { `); }); - test('generates calls for supertypes', async () => { + test('generates calls for deprecated inherited properties', async () => { const result = await compileJsiiForTest( ` - export interface Foo {} - export interface Bar {readonly foo: Foo;} - export interface Baz extends Bar {readonly x: string;} + export interface Baz { + /** @deprecated message from Baz */ + readonly x: string; + } + export interface Bar { + /** @deprecated message from Bar */ + readonly x: string; + } + export interface Foo extends Bar, Baz { + } `, undefined /* callback */, { addDeprecationWarnings: true }, ); - expect(jsFile(result, '.warnings.jsii')).toMatch(`function testpkg_Baz(p) { + const warningsFileContent = jsFile(result, '.warnings.jsii'); + + // For each supertype, its corresponding function should be generated, as usual + expect(warningsFileContent).toMatch(`function testpkg_Baz(p) { if (p == null) return; visitedObjects.add(p); - testpkg_Bar(p); + if ("x" in p) + print("testpkg.Baz#x", "message from Baz"); visitedObjects.delete(p); -} -`); +}`); + expect(warningsFileContent).toMatch(`function testpkg_Bar(p) { + if (p == null) + return; + visitedObjects.add(p); + if ("x" in p) + print("testpkg.Bar#x", "message from Bar"); + visitedObjects.delete(p); +}`); + + // But a call for one of the instances of the property should also be generated in the base function + expect(warningsFileContent).toMatch(`function testpkg_Foo(p) { + if (p == null) + return; + visitedObjects.add(p); + if ("x" in p) + print("testpkg.Baz#x", "message from Baz"); + visitedObjects.delete(p); +}`); + }); + + test('skips properties that are deprecated in one supertype but not the other', async () => { + const result = await compileJsiiForTest( + ` + export interface Baz { + readonly x: string; + } + export interface Bar { + /** @deprecated message from Bar */ + readonly x: string; + } + export interface Foo extends Bar, Baz { + } + `, + undefined /* callback */, + { addDeprecationWarnings: true }, + ); + + const warningsFileContent = jsFile(result, '.warnings.jsii'); + + expect(warningsFileContent).toMatch(`function testpkg_Foo(p) { +}`); }); - test('generates calls for tyes with deprecated properties', async () => { + test('generates calls for types with deprecated properties', async () => { const result = await compileJsiiForTest( ` export interface Bar { @@ -274,9 +325,13 @@ function testpkg_Baz(p) { }); test('generates calls for types in other assemblies', async () => { + const calcBaseOfBaseRoot = resolveModuleDir( + '@scope/jsii-calc-base-of-base', + ); const calcBaseRoot = resolveModuleDir('@scope/jsii-calc-base'); const calcLibRoot = resolveModuleDir('@scope/jsii-calc-lib'); + await compile(calcBaseOfBaseRoot, false); await compile(calcBaseRoot, true); await compile(calcLibRoot, true); const warningsFile = loadWarningsFile(calcBaseRoot); @@ -290,11 +345,11 @@ function testpkg_Baz(p) { // Recompiling without deprecation warning to leave the packages in a clean state await compile(calcBaseRoot, false); await compile(calcLibRoot, false); - }, 25000); + }, 30000); }); describe('Call injections', () => { - test('does not add warnings, by default', async () => { + test('does not add warnings by default', async () => { const result = await compileJsiiForTest( ` export class Foo { diff --git a/packages/jsii/test/negatives/_unexported.ts b/packages/jsii/test/negatives/_unexported.ts new file mode 100644 index 0000000000..94a7c28bde --- /dev/null +++ b/packages/jsii/test/negatives/_unexported.ts @@ -0,0 +1,6 @@ +/** + * This should never be exported by the modules that import it. + */ +export interface UnexportedProps { + readonly name: string; +} diff --git a/packages/jsii/test/negatives/neg.expose-unexported-type-constructor-param.ts b/packages/jsii/test/negatives/neg.expose-unexported-type-constructor-param.ts new file mode 100644 index 0000000000..3d2350ead1 --- /dev/null +++ b/packages/jsii/test/negatives/neg.expose-unexported-type-constructor-param.ts @@ -0,0 +1,9 @@ +import { UnexportedProps } from './_unexported'; + +export class ExportedClass { + public readonly name: string; + + public constructor(props: UnexportedProps) { + this.name = props.name; + } +} diff --git a/regression-tests/@barrelimports/consumer/.gitignore b/regression-tests/@barrelimports/consumer/.gitignore new file mode 100644 index 0000000000..0c4e0081d6 --- /dev/null +++ b/regression-tests/@barrelimports/consumer/.gitignore @@ -0,0 +1,4 @@ +/.jsii +/tsconfig.json +*.js +*.d.ts diff --git a/regression-tests/@barrelimports/consumer/README.md b/regression-tests/@barrelimports/consumer/README.md new file mode 100644 index 0000000000..eaf22f65b1 --- /dev/null +++ b/regression-tests/@barrelimports/consumer/README.md @@ -0,0 +1,6 @@ +# @barrelimport/consumer + +This library re-exports a type imported from a barrel location within +`@barrelimport/provider`, without actually importing `@barrelimport/provider` +itself, so we validate the jsii compiler correctly identifies the submodule +declarations. diff --git a/regression-tests/@barrelimports/consumer/lib/index.ts b/regression-tests/@barrelimports/consumer/lib/index.ts new file mode 100644 index 0000000000..d5ced1d6bf --- /dev/null +++ b/regression-tests/@barrelimports/consumer/lib/index.ts @@ -0,0 +1,6 @@ +// Directly importing NamespacedStruct, NEVER having imported @barrelimports/provider +import { NamespacedStruct } from '@barrelimports/provider/lib/namespaced'; + +export class UsingBarrelImport { + public constructor(public readonly props: NamespacedStruct) { } +} diff --git a/regression-tests/@barrelimports/consumer/package.json b/regression-tests/@barrelimports/consumer/package.json new file mode 100644 index 0000000000..716fbdfd2d --- /dev/null +++ b/regression-tests/@barrelimports/consumer/package.json @@ -0,0 +1,30 @@ +{ + "name": "@barrelimports/consumer", + "version": "0.0.0", + "private": true, + "license": "Apache-2.0", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/jsii.git", + "directory": "regression-tests/@barrelimports/provider" + }, + "scripts": { + "build": "jsii" + }, + "peerDependencies": { + "@barrelimports/provider": "0.0.0" + }, + "devDependencies": { + "@barrelimports/provider": "0.0.0", + "jsii": "^0.0.0" + }, + "jsii": { + "targets": {} + } +} diff --git a/regression-tests/@barrelimports/provider/.gitignore b/regression-tests/@barrelimports/provider/.gitignore new file mode 100644 index 0000000000..0c4e0081d6 --- /dev/null +++ b/regression-tests/@barrelimports/provider/.gitignore @@ -0,0 +1,4 @@ +/.jsii +/tsconfig.json +*.js +*.d.ts diff --git a/regression-tests/@barrelimports/provider/README.md b/regression-tests/@barrelimports/provider/README.md new file mode 100644 index 0000000000..32226a5f72 --- /dev/null +++ b/regression-tests/@barrelimports/provider/README.md @@ -0,0 +1,5 @@ +# @barrelimport/provider + +This library provides a single namespaced export struct, so that we can validate +the jsii compiler is correctly able to identify submodule declarations when the +package entry point is never imported by the consuming code. diff --git a/regression-tests/@barrelimports/provider/lib/index.ts b/regression-tests/@barrelimports/provider/lib/index.ts new file mode 100644 index 0000000000..be34190b86 --- /dev/null +++ b/regression-tests/@barrelimports/provider/lib/index.ts @@ -0,0 +1 @@ +export * as namespaced from './namespaced'; diff --git a/regression-tests/@barrelimports/provider/lib/namespaced.ts b/regression-tests/@barrelimports/provider/lib/namespaced.ts new file mode 100644 index 0000000000..b64a2a52d0 --- /dev/null +++ b/regression-tests/@barrelimports/provider/lib/namespaced.ts @@ -0,0 +1,3 @@ +export interface NamespacedStruct { + readonly name: string; +} diff --git a/regression-tests/@barrelimports/provider/package.json b/regression-tests/@barrelimports/provider/package.json new file mode 100644 index 0000000000..58733bc50a --- /dev/null +++ b/regression-tests/@barrelimports/provider/package.json @@ -0,0 +1,26 @@ +{ + "name": "@barrelimports/provider", + "version": "0.0.0", + "private": true, + "license": "Apache-2.0", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/jsii.git", + "directory": "regression-tests/@barrelimports/provider" + }, + "scripts": { + "build": "jsii" + }, + "devDependencies": { + "jsii": "^0.0.0" + }, + "jsii": { + "targets": {} + } +} diff --git a/regression-tests/README.md b/regression-tests/README.md new file mode 100644 index 0000000000..8dd92a9763 --- /dev/null +++ b/regression-tests/README.md @@ -0,0 +1,10 @@ +# Regression Tests + +This directory contains packages that are supposed to cleanly compile using +`jsii`. This validates the compiler is able to correctly interpret the source. + +When adding new tests, be sure to follow these guidelines: + +- Create a new namespace for each regression scenario +- All packages should have `private: true` in their `package.json` +- Provide a README.md with an explanation of what the package(s) validate