diff --git a/packages/jsii-dotnet-analyzers/.gitignore b/packages/jsii-dotnet-analyzers/.gitignore new file mode 100644 index 0000000000..65d6c8ce34 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/.gitignore @@ -0,0 +1,17 @@ +# generated by generate.sh +src/Amazon.JSII.Generator/JsiiVersion.cs +src/Directory.Build.props +src/NuGet.Metadata.props + +*.js +*.d.ts +node_modules/ +.nyc_output/ +coverage/ + + +*.nupkg +bin/ +cli/ +obj/ +*.DotSettings.user diff --git a/packages/jsii-dotnet-analyzers/Directory.Build.props.t.js b/packages/jsii-dotnet-analyzers/Directory.Build.props.t.js new file mode 100644 index 0000000000..77bca5d03c --- /dev/null +++ b/packages/jsii-dotnet-analyzers/Directory.Build.props.t.js @@ -0,0 +1,9 @@ +const version = require('./package.json').version.replace(/\+.+$/, ''); // omit "+build" suffix + +process.stdout.write(` + + ${version} + netstandard2.0 + + +`); diff --git a/packages/jsii-dotnet-analyzers/LICENSE b/packages/jsii-dotnet-analyzers/LICENSE new file mode 100644 index 0000000000..add725cd48 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/jsii-dotnet-analyzers/NuGet.Metadata.props.t.js b/packages/jsii-dotnet-analyzers/NuGet.Metadata.props.t.js new file mode 100644 index 0000000000..e0c50b6ad4 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/NuGet.Metadata.props.t.js @@ -0,0 +1,19 @@ +const package = require('./package.json'); + +process.stdout.write(` + + True + True + True + ..\\..\\bin\\$(Configuration)\\NuGet\\ + $(JsiiVersion) + ${package.description} + ${package.homepage} + https://spdx.org/licenses/${package.license}.html + ${package.author.name} + ${package.author.name} + key.snk + True + + +`); diff --git a/packages/jsii-dotnet-analyzers/build.sh b/packages/jsii-dotnet-analyzers/build.sh new file mode 100644 index 0000000000..93d1136aa6 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail + +dotnet build --force -c Release ./src/Amazon.JSII.Analyzers + +cp -f ./bin/Release/NuGet/*.nupkg . diff --git a/packages/jsii-dotnet-analyzers/generate.sh b/packages/jsii-dotnet-analyzers/generate.sh new file mode 100644 index 0000000000..5a5764b0d9 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/generate.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail +src="./src" + +# Generate metadata files based on package.json. +/usr/bin/env node ./Directory.Build.props.t.js > ${src}/Directory.Build.props +/usr/bin/env node ./NuGet.Metadata.props.t.js > ${src}/NuGet.Metadata.props diff --git a/packages/jsii-dotnet-analyzers/lib/index.ts b/packages/jsii-dotnet-analyzers/lib/index.ts new file mode 100644 index 0000000000..838fecdac4 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/lib/index.ts @@ -0,0 +1,3 @@ +import path = require('path'); + +export const repository = path.resolve(__dirname, path.join('..', 'bin', 'Release', 'NuGet')); diff --git a/packages/jsii-dotnet-analyzers/package-lock.json b/packages/jsii-dotnet-analyzers/package-lock.json new file mode 100644 index 0000000000..6b6d4d37f6 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/package-lock.json @@ -0,0 +1,15 @@ +{ + "name": "jsii-dotnet-analyzers", + "version": "0.15.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "jsii-build-tools": { + "version": "file:../jsii-build-tools", + "dev": true + }, + "jsii-dotnet-runtime": { + "version": "file:../jsii-dotnet-runtime" + } + } +} diff --git a/packages/jsii-dotnet-analyzers/package.json b/packages/jsii-dotnet-analyzers/package.json new file mode 100644 index 0000000000..df169759bc --- /dev/null +++ b/packages/jsii-dotnet-analyzers/package.json @@ -0,0 +1,32 @@ +{ + "name": "jsii-dotnet-analyzers", + "version": "0.15.0", + "description": ".NET Roslyn Analyzers for Jsii", + "main": "lib/index.js", + "private": true, + "types": "lib/index.d.ts", + "scripts": { + "gen": "/bin/bash ./generate.sh", + "build": "npm run gen && tsc --build && /bin/bash ./build.sh", + "test": "/bin/bash ./test.sh", + "package": "package-dotnet" + }, + "devDependencies": { + "jsii-build-tools": "file:../jsii-build-tools" + }, + "dependencies": { + "jsii-dotnet-runtime": "file:../jsii-dotnet-runtime" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "email": "aws-jsii@amazon.com" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/aws/jsii.git", + "directory": "packages/jsii-dotnet-analyzers" + }, + "homepage": "https://github.com/aws/jsii" +} diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Amazon.JSII.Analyzers.UnitTests.csproj b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Amazon.JSII.Analyzers.UnitTests.csproj new file mode 100755 index 0000000000..7a61bc6c1a --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Amazon.JSII.Analyzers.UnitTests.csproj @@ -0,0 +1,25 @@ + + + + netcoreapp2.0 + false + Amazon.JSII.Analyzers.UnitTests + + + + + + + + + + + + + + + + + + + diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Helpers/DiagnosticResult.cs b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Helpers/DiagnosticResult.cs new file mode 100755 index 0000000000..dde80c43f9 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Helpers/DiagnosticResult.cs @@ -0,0 +1,87 @@ +using Microsoft.CodeAnalysis; +using System; + +namespace TestHelper +{ + /// + /// Location where the diagnostic appears, as determined by path, line number, and column number. + /// + public struct DiagnosticResultLocation + { + public DiagnosticResultLocation(string path, int line, int column) + { + if (line < -1) + { + throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); + } + + if (column < -1) + { + throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); + } + + this.Path = path; + this.Line = line; + this.Column = column; + } + + public string Path { get; } + public int Line { get; } + public int Column { get; } + } + + /// + /// Struct that stores information about a Diagnostic appearing in a source + /// + public struct DiagnosticResult + { + private DiagnosticResultLocation[] locations; + + public DiagnosticResultLocation[] Locations + { + get + { + if (this.locations == null) + { + this.locations = new DiagnosticResultLocation[] { }; + } + return this.locations; + } + + set + { + this.locations = value; + } + } + + public DiagnosticSeverity Severity { get; set; } + + public string Id { get; set; } + + public string Message { get; set; } + + public string Path + { + get + { + return this.Locations.Length > 0 ? this.Locations[0].Path : ""; + } + } + + public int Line + { + get + { + return this.Locations.Length > 0 ? this.Locations[0].Line : -1; + } + } + + public int Column + { + get + { + return this.Locations.Length > 0 ? this.Locations[0].Column : -1; + } + } + } +} diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Helpers/DiagnosticVerifier.Helper.cs b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Helpers/DiagnosticVerifier.Helper.cs new file mode 100755 index 0000000000..de72e54f8d --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Helpers/DiagnosticVerifier.Helper.cs @@ -0,0 +1,170 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace TestHelper +{ + /// + /// Class for turning strings into documents and getting the diagnostics on them + /// All methods are static + /// + public abstract partial class DiagnosticVerifier + { + private static readonly MetadataReference CorlibReference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); + private static readonly MetadataReference SystemCoreReference = MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location); + private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location); + private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); + + internal static string DefaultFilePathPrefix = "Test"; + internal static string CSharpDefaultFileExt = "cs"; + internal static string VisualBasicDefaultExt = "vb"; + internal static string TestProjectName = "TestProject"; + + #region Get Diagnostics + + /// + /// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. + /// + /// Classes in the form of strings + /// The language the source classes are in + /// The analyzer to be run on the sources + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location + private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) + { + return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); + } + + /// + /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. + /// The returned diagnostics are then ordered by location in the source document. + /// + /// The analyzer to run on the documents + /// The Documents that the analyzer will be run on + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location + protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) + { + var projects = new HashSet(); + foreach (var document in documents) + { + projects.Add(document.Project); + } + + var diagnostics = new List(); + foreach (var project in projects) + { + var compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer)); + var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; + foreach (var diag in diags) + { + if (diag.Location == Location.None || diag.Location.IsInMetadata) + { + diagnostics.Add(diag); + } + else + { + for (int i = 0; i < documents.Length; i++) + { + var document = documents[i]; + var tree = document.GetSyntaxTreeAsync().Result; + if (tree == diag.Location.SourceTree) + { + diagnostics.Add(diag); + } + } + } + } + } + + var results = SortDiagnostics(diagnostics); + diagnostics.Clear(); + return results; + } + + /// + /// Sort diagnostics by location in source document + /// + /// The list of Diagnostics to be sorted + /// An IEnumerable containing the Diagnostics in order of Location + private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) + { + return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); + } + + #endregion + + #region Set up compilation and documents + /// + /// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it. + /// + /// Classes in the form of strings + /// The language the source code is in + /// A Tuple containing the Documents produced from the sources and their TextSpans if relevant + private static Document[] GetDocuments(string[] sources, string language) + { + if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic) + { + throw new ArgumentException("Unsupported Language"); + } + + var project = CreateProject(sources, language); + var documents = project.Documents.ToArray(); + + if (sources.Length != documents.Length) + { + throw new InvalidOperationException("Amount of sources did not match amount of Documents created"); + } + + return documents; + } + + /// + /// Create a Document from a string through creating a project that contains it. + /// + /// Classes in the form of a string + /// The language the source code is in + /// A Document created from the source string + protected static Document CreateDocument(string source, string language = LanguageNames.CSharp) + { + return CreateProject(new[] { source }, language).Documents.First(); + } + + /// + /// Create a project using the inputted strings as sources. + /// + /// Classes in the form of strings + /// The language the source code is in + /// A Project created out of the Documents created from the source strings + private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp) + { + string fileNamePrefix = DefaultFilePathPrefix; + string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt; + + var projectId = ProjectId.CreateNewId(debugName: TestProjectName); + + var solution = new AdhocWorkspace() + .CurrentSolution + .AddProject(projectId, TestProjectName, TestProjectName, language) + .AddMetadataReference(projectId, CorlibReference) + .AddMetadataReference(projectId, SystemCoreReference) + .AddMetadataReference(projectId, CSharpSymbolsReference) + .AddMetadataReference(projectId, CodeAnalysisReference); + + int count = 0; + foreach (var source in sources) + { + var newFileName = fileNamePrefix + count + "." + fileExt; + var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); + solution = solution.AddDocument(documentId, newFileName, SourceText.From(source)); + count++; + } + return solution.GetProject(projectId); + } + #endregion + } +} + diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/JsiiOptionalAnalyzerTests.cs b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/JsiiOptionalAnalyzerTests.cs new file mode 100755 index 0000000000..18a1de12bf --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/JsiiOptionalAnalyzerTests.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Xunit; +using TestHelper; + +namespace Amazon.JSII.Analyzers.UnitTests +{ + public class JsiiOptionalAnalyzerTests : DiagnosticVerifier + { + [Fact] + public void TestGivenSomeEmptyCodeThenRoslynDoesNotComplain() + { + var test = @""; + + VerifyCSharpDiagnostic(test); + } + + [Fact] + public void TestGivenSomeCodeWithAMissingRequiredPropertyThenRoslynComplains() + { + var test = @" + using System; + namespace Amazon.JSII.Analyzers.UnitTests + { + public class JsiiByValueAttribute : Attribute + { + } + + public class JsiiClassAttribute : Attribute + { + } + + public class JsiiOptionalAttribute : Attribute + { + } + + [JsiiByValue] + public class SampleProps + { + [JsiiOptional] + public string OptionalProperty1 { get; set; } + + [JsiiOptional] + public string OptionalProperty2 { get; set; } + + public string RequiredProperty1 { get; set; } + + public string RequiredProperty2 { get; set; } + } + + [JsiiClass] + public class SampleClass + { + public SampleClass(SampleProps props) + { + props = null; + } + } + + class Test + { + // This should fail because there is missing required properties and it is a nested instruction + var result1 = new SampleClass(new SampleProps()); + + // This should fail because RequiredProperty1 is passed as null + var result2 = new SampleClass(new SampleProps() + { + RequiredProperty1 = null, + OptionalProperty2 = ""test"", + RequiredProperty2 = ""test"" + }); + + // This is OK, the properties might be passed later, we don't want to enforce it + var result3 = new SampleProps(); + + // This is not OK, if you start passing properties, you should pass all of the required ones + var result4 = new SampleProps() + { + RequiredProperty1 = null, + OptionalProperty2 = ""test"" + }; + + // This is not OK, RequiredProperty1 is null + var result5 = new SampleProps() + { + RequiredProperty1 = null, + OptionalProperty2 = ""test"", + RequiredProperty2 = ""test"" + }; + + // This is OK, all required properties are passed and not null. + var result6 = new SampleProps() + { + RequiredProperty1 = ""test"", + OptionalProperty2 = ""test"", + RequiredProperty2 = ""test"" + }; + } + }"; + var expected = new List() + { + new DiagnosticResult() + { + Id = "JSII001", + Message = "The property RequiredProperty1 is required and cannot be null", + Severity = DiagnosticSeverity.Error, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 43, 51) + } + }, + new DiagnosticResult() + { + Id = "JSII001", + Message = "The property RequiredProperty2 is required and cannot be null", + Severity = DiagnosticSeverity.Error, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 43, 51) + } + }, + new DiagnosticResult() + { + Id = "JSII001", + Message = "The property RequiredProperty1 is required and cannot be null", + Severity = DiagnosticSeverity.Error, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 46, 51) + } + }, + new DiagnosticResult() + { + Id = "JSII001", + Message = "The property RequiredProperty1 is required and cannot be null", + Severity = DiagnosticSeverity.Error, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 57, 35) + } + }, + new DiagnosticResult() + { + Id = "JSII001", + Message = "The property RequiredProperty2 is required and cannot be null", + Severity = DiagnosticSeverity.Error, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 57, 35) + } + }, + new DiagnosticResult() + { + Id = "JSII001", + Message = "The property RequiredProperty1 is required and cannot be null", + Severity = DiagnosticSeverity.Error, + Locations = + new[] { + new DiagnosticResultLocation("Test0.cs", 64, 35) + } + } + }; + + VerifyCSharpDiagnostic(test, expected.ToArray()); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new JsiiOptionalAnalyzer(); + } + } +} diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Verifiers/DiagnosticVerifier.cs b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Verifiers/DiagnosticVerifier.cs new file mode 100755 index 0000000000..8a66157221 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.UnitTests/Verifiers/DiagnosticVerifier.cs @@ -0,0 +1,269 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Xunit; + +namespace TestHelper +{ + /// + /// Superclass of all Unit Tests for DiagnosticAnalyzers + /// + public abstract partial class DiagnosticVerifier + { + #region To be implemented by Test classes + /// + /// Get the CSharp analyzer being tested - to be implemented in non-abstract class + /// + protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return null; + } + + /// + /// Get the Visual Basic analyzer being tested (C#) - to be implemented in non-abstract class + /// + protected virtual DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() + { + return null; + } + #endregion + + #region Verifier wrappers + + /// + /// Called to test a C# DiagnosticAnalyzer when applied on the single inputted string as a source + /// Note: input a DiagnosticResult for each Diagnostic expected + /// + /// A class in the form of a string to run the analyzer on + /// DiagnosticResults that should appear after the analyzer is run on the source + protected void VerifyCSharpDiagnostic(string source, params DiagnosticResult[] expected) + { + VerifyDiagnostics(new[] { source }, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); + } + + /// + /// Called to test a VB DiagnosticAnalyzer when applied on the single inputted string as a source + /// Note: input a DiagnosticResult for each Diagnostic expected + /// + /// A class in the form of a string to run the analyzer on + /// DiagnosticResults that should appear after the analyzer is run on the source + protected void VerifyBasicDiagnostic(string source, params DiagnosticResult[] expected) + { + VerifyDiagnostics(new[] { source }, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); + } + + /// + /// Called to test a C# DiagnosticAnalyzer when applied on the inputted strings as a source + /// Note: input a DiagnosticResult for each Diagnostic expected + /// + /// An array of strings to create source documents from to run the analyzers on + /// DiagnosticResults that should appear after the analyzer is run on the sources + protected void VerifyCSharpDiagnostic(string[] sources, params DiagnosticResult[] expected) + { + VerifyDiagnostics(sources, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); + } + + /// + /// Called to test a VB DiagnosticAnalyzer when applied on the inputted strings as a source + /// Note: input a DiagnosticResult for each Diagnostic expected + /// + /// An array of strings to create source documents from to run the analyzers on + /// DiagnosticResults that should appear after the analyzer is run on the sources + protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[] expected) + { + VerifyDiagnostics(sources, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); + } + + /// + /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, + /// then verifies each of them. + /// + /// An array of strings to create source documents from to run the analyzers on + /// The language of the classes represented by the source strings + /// The analyzer to be run on the source code + /// DiagnosticResults that should appear after the analyzer is run on the sources + private void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) + { + var diagnostics = GetSortedDiagnostics(sources, language, analyzer); + VerifyDiagnosticResults(diagnostics, analyzer, expected); + } + + #endregion + + #region Actual comparisons and verifications + /// + /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. + /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. + /// + /// The Diagnostics found by the compiler after running the analyzer on the source code + /// The analyzer that was being run on the sources + /// Diagnostic Results that should have appeared in the code + private static void VerifyDiagnosticResults(IEnumerable actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) + { + int expectedCount = expectedResults.Count(); + int actualCount = actualResults.Count(); + + if (expectedCount != actualCount) + { + string diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzer, actualResults.ToArray()) : " NONE."; + + Assert.True(false, + string.Format("Mismatch between number of diagnostics returned, expected \"{0}\" actual \"{1}\"\r\n\r\nDiagnostics:\r\n{2}\r\n", expectedCount, actualCount, diagnosticsOutput)); + } + + for (int i = 0; i < expectedResults.Length; i++) + { + var actual = actualResults.ElementAt(i); + var expected = expectedResults[i]; + + if (expected.Line == -1 && expected.Column == -1) + { + if (actual.Location != Location.None) + { + Assert.True(false, + string.Format("Expected:\nA project diagnostic with No location\nActual:\n{0}", + FormatDiagnostics(analyzer, actual))); + } + } + else + { + VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First()); + var additionalLocations = actual.AdditionalLocations.ToArray(); + + if (additionalLocations.Length != expected.Locations.Length - 1) + { + Assert.True(false, + string.Format("Expected {0} additional locations but got {1} for Diagnostic:\r\n {2}\r\n", + expected.Locations.Length - 1, additionalLocations.Length, + FormatDiagnostics(analyzer, actual))); + } + + for (int j = 0; j < additionalLocations.Length; ++j) + { + VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); + } + } + + if (actual.Id != expected.Id) + { + Assert.True(false, + string.Format("Expected diagnostic id to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", + expected.Id, actual.Id, FormatDiagnostics(analyzer, actual))); + } + + if (actual.Severity != expected.Severity) + { + Assert.True(false, + string.Format("Expected diagnostic severity to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", + expected.Severity, actual.Severity, FormatDiagnostics(analyzer, actual))); + } + + if (actual.GetMessage() != expected.Message) + { + Assert.True(false, + string.Format("Expected diagnostic message to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", + expected.Message, actual.GetMessage(), FormatDiagnostics(analyzer, actual))); + } + } + } + + /// + /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. + /// + /// The analyzer that was being run on the sources + /// The diagnostic that was found in the code + /// The Location of the Diagnostic found in the code + /// The DiagnosticResultLocation that should have been found + private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) + { + var actualSpan = actual.GetLineSpan(); + + Assert.True(actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")), + string.Format("Expected diagnostic to be in file \"{0}\" was actually in file \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", + expected.Path, actualSpan.Path, FormatDiagnostics(analyzer, diagnostic))); + + var actualLinePosition = actualSpan.StartLinePosition; + + // Only check line position if there is an actual line in the real diagnostic + if (actualLinePosition.Line > 0) + { + if (actualLinePosition.Line + 1 != expected.Line) + { + Assert.True(false, + string.Format("Expected diagnostic to be on line \"{0}\" was actually on line \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", + expected.Line, actualLinePosition.Line + 1, FormatDiagnostics(analyzer, diagnostic))); + } + } + + // Only check column position if there is an actual column position in the real diagnostic + if (actualLinePosition.Character > 0) + { + if (actualLinePosition.Character + 1 != expected.Column) + { + Assert.True(false, + string.Format("Expected diagnostic to start at column \"{0}\" was actually at column \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", + expected.Column, actualLinePosition.Character + 1, FormatDiagnostics(analyzer, diagnostic))); + } + } + } + #endregion + + #region Formatting Diagnostics + /// + /// Helper method to format a Diagnostic into an easily readable string + /// + /// The analyzer that this verifier tests + /// The Diagnostics to be formatted + /// The Diagnostics formatted as a string + private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diagnostic[] diagnostics) + { + var builder = new StringBuilder(); + for (int i = 0; i < diagnostics.Length; ++i) + { + builder.AppendLine("// " + diagnostics[i].ToString()); + + var analyzerType = analyzer.GetType(); + var rules = analyzer.SupportedDiagnostics; + + foreach (var rule in rules) + { + if (rule != null && rule.Id == diagnostics[i].Id) + { + var location = diagnostics[i].Location; + if (location == Location.None) + { + builder.AppendFormat("GetGlobalResult({0}.{1})", analyzerType.Name, rule.Id); + } + else + { + Assert.True(location.IsInSource, + $"Test base does not currently handle diagnostics in metadata locations. Diagnostic in metadata: {diagnostics[i]}\r\n"); + + string resultMethodName = diagnostics[i].Location.SourceTree.FilePath.EndsWith(".cs") ? "GetCSharpResultAt" : "GetBasicResultAt"; + var linePosition = diagnostics[i].Location.GetLineSpan().StartLinePosition; + + builder.AppendFormat("{0}({1}, {2}, {3}.{4})", + resultMethodName, + linePosition.Line + 1, + linePosition.Character + 1, + analyzerType.Name, + rule.Id); + } + + if (i != diagnostics.Length - 1) + { + builder.Append(','); + } + + builder.AppendLine(); + break; + } + } + } + return builder.ToString(); + } + #endregion + } +} diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.sln b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.sln new file mode 100644 index 0000000000..a905ad7c35 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2026 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Amazon.JSII.Analyzers", "Amazon.JSII.Analyzers\Amazon.JSII.Analyzers.csproj", "{E7BFF0E9-D8BF-4996-98B7-58334EA276D1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{B88CEA39-359B-45A0-86D6-0BC1FD284BBE}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Amazon.JSII.Analyzers.UnitTests", "Amazon.JSII.Analyzers.UnitTests\Amazon.JSII.Analyzers.UnitTests.csproj", "{96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E7BFF0E9-D8BF-4996-98B7-58334EA276D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7BFF0E9-D8BF-4996-98B7-58334EA276D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7BFF0E9-D8BF-4996-98B7-58334EA276D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7BFF0E9-D8BF-4996-98B7-58334EA276D1}.Release|Any CPU.Build.0 = Release|Any CPU + {96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Release|Any CPU.Build.0 = Release|Any CPU + {7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {96CC0C0B-1D90-448F-9BFC-07CE93D2CE29} = {1F4EEFB5-9E4C-4464-9C3B-6729ABB0511E} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C5094D14-EAB4-4A0A-80A2-14748C28C057} + EndGlobalSection +EndGlobal diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/Amazon.JSII.Analyzers.csproj b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/Amazon.JSII.Analyzers.csproj new file mode 100644 index 0000000000..8e4ff80347 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/Amazon.JSII.Analyzers.csproj @@ -0,0 +1,21 @@ + + + + + Amazon.JSII.Analyzers + .NET Roslyn Analyzers for JSII + netstandard2.0 + true + + + + + + + + + + + + + diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/JsiiOptionalAnalyzer.cs b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/JsiiOptionalAnalyzer.cs new file mode 100644 index 0000000000..957a093d44 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/JsiiOptionalAnalyzer.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Amazon.JSII.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class JsiiOptionalAnalyzer : DiagnosticAnalyzer + { + private const string DiagnosticId = "JSII001"; + private const string Title = "A required property is missing or null"; + private const string MessageFormat = "The property is required and cannot be null"; + private const string MessageFormatWithPropertyName = "The property {0} is required and cannot be null"; + private const string Description = "The property is required and cannot be null"; + private const string DescriptionWitPropertyName = "The property {0} is required and cannot be null"; + private const string Category = "Jsii.Usage"; + + private static readonly DiagnosticDescriptor Rule = + new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ObjectCreationExpression); + } + + private static void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + var objectCreation = (ObjectCreationExpressionSyntax)context.Node; + var typeInfo = context.SemanticModel.GetTypeInfo(objectCreation); + if (IsJsiiDatatype(typeInfo)) + { + // If the newly created instance is a Jsii datatype [JsiiByValue] + // Get all the properties passed + var passedProperties = new HashSet(); + foreach (var child in objectCreation.ChildNodes()) + { + if (child.Kind() == SyntaxKind.ObjectInitializerExpression) + { + // This is an inline initialization + // Saving all the properties that are passed when initializing the props object + foreach (var passedProperty in child.ChildNodes().Where(n => n.Kind() == SyntaxKind.SimpleAssignmentExpression)) + { + var props = passedProperty.ChildNodes().ToArray(); + if (props.Length >= 2) + { + // Property = value + if (props[1].ToString() != "null") // value != null ? + { + var propName = props[0].ToString(); + passedProperties.Add(propName); + } + } + } + } + } + + // Parent.Parent.Parent = new Construct() instruction. + // #1 Parent = Argument + // #2 Parent = ArgumentList + // #3 Parent = ObjectCreationExpressionSyntax (if it exists). + var parentType = context.SemanticModel.GetTypeInfo(objectCreation.Parent.Parent.Parent); + + // If the object initialization was an empty newProps() outside of a JsiiClass - We don't fail + if (passedProperties.Count == 0 && (parentType.Type == null || !IsJsiiClass(parentType))) + return; + + // Get all the required properties on the prop object + var requiredProperties = typeInfo.Type.GetMembers() + .Where(m => m.Kind == SymbolKind.Property + && !IsJsiiOptionalProperty(m)); + foreach (var requiredProperty in requiredProperties) + { + // The property in the props class IS NOT optional, check if it is passed as an argument. + if (!passedProperties.Contains(requiredProperty.Name)) + { + // This property IS REQUIRED and was not passed in the arguments. Raising an error + var rule = new DiagnosticDescriptor(DiagnosticId, + Title, + string.Format(MessageFormatWithPropertyName, requiredProperty.Name), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: string.Format(DescriptionWitPropertyName, requiredProperty.Name)); + context.ReportDiagnostic(Diagnostic.Create(rule, context.Node.GetLocation())); + } + } + } + } + + /// + /// Checks if the TypeInfo is related to a Jsii class + /// + /// + /// This is done by checking for the [JsiiClass] attribute + /// + /// The TypeInfo object to check for + /// true if the TypeInfo is related to a Jsii class, false otherwise + private static bool IsJsiiClass(TypeInfo typeInfo) + { + var typeAttributes = typeInfo.Type.GetAttributes().ToArray(); + return typeAttributes.Any(a => a.AttributeClass.Name == "JsiiClassAttribute"); + } + + /// + /// Checks if the TypeInfo is related to a Jsii datatype + /// + /// + /// This is done by checking for the [JsiiByValueAttribute] attribute + /// + /// The TypeInfo object to check for + /// true if the TypeInfo is related to a Jsii datatype, false otherwise + private static bool IsJsiiDatatype(TypeInfo typeInfo) + { + var typeAttributes = typeInfo.Type.GetAttributes().ToArray(); + return typeAttributes.Any(a => a.AttributeClass.Name == "JsiiByValueAttribute"); + } + + /// + /// Checks if the property is optional for jsii + /// + /// + /// This is done by checking for the [JsiiOptionalAttribute] attribute + /// + /// The property to check for + /// true if the property is optional, false otherwise + private static bool IsJsiiOptionalProperty(ISymbol property) + { + return property.GetAttributes().Any(a => a.AttributeClass.Name == "JsiiOptionalAttribute"); + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/tools/install.ps1 b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/tools/install.ps1 new file mode 100644 index 0000000000..c1c3d88223 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/tools/install.ps1 @@ -0,0 +1,58 @@ +param($installPath, $toolsPath, $package, $project) + +if($project.Object.SupportsPackageDependencyResolution) +{ + if($project.Object.SupportsPackageDependencyResolution()) + { + # Do not install analyzers via install.ps1, instead let the project system handle it. + return + } +} + +$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve + +foreach($analyzersPath in $analyzersPaths) +{ + if (Test-Path $analyzersPath) + { + # Install the language agnostic analyzers. + foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) + } + } + } +} + +# $project.Type gives the language name like (C# or VB.NET) +$languageFolder = "" +if($project.Type -eq "C#") +{ + $languageFolder = "cs" +} +if($project.Type -eq "VB.NET") +{ + $languageFolder = "vb" +} +if($languageFolder -eq "") +{ + return +} + +foreach($analyzersPath in $analyzersPaths) +{ + # Install language specific analyzers. + $languageAnalyzersPath = join-path $analyzersPath $languageFolder + if (Test-Path $languageAnalyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) + } + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/tools/uninstall.ps1 b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/tools/uninstall.ps1 new file mode 100644 index 0000000000..829d26efa9 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/src/Amazon.JSII.Analyzers/tools/uninstall.ps1 @@ -0,0 +1,65 @@ +param($installPath, $toolsPath, $package, $project) + +if($project.Object.SupportsPackageDependencyResolution) +{ + if($project.Object.SupportsPackageDependencyResolution()) + { + # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. + return + } +} + +$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve + +foreach($analyzersPath in $analyzersPaths) +{ + # Uninstall the language agnostic analyzers. + if (Test-Path $analyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) + } + } + } +} + +# $project.Type gives the language name like (C# or VB.NET) +$languageFolder = "" +if($project.Type -eq "C#") +{ + $languageFolder = "cs" +} +if($project.Type -eq "VB.NET") +{ + $languageFolder = "vb" +} +if($languageFolder -eq ""), +{ + return +} + +foreach($analyzersPath in $analyzersPaths) +{ + # Uninstall language specific analyzers. + $languageAnalyzersPath = join-path $analyzersPath $languageFolder + if (Test-Path $languageAnalyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + try + { + $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) + } + catch + { + + } + } + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-analyzers/test.sh b/packages/jsii-dotnet-analyzers/test.sh new file mode 100644 index 0000000000..5338fc26dc --- /dev/null +++ b/packages/jsii-dotnet-analyzers/test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail + +# Run unit tests +echo "Running library unit tests" +dotnet test -c Release ./src/Amazon.JSII.Analyzers.UnitTests diff --git a/packages/jsii-dotnet-analyzers/tsconfig.json b/packages/jsii-dotnet-analyzers/tsconfig.json new file mode 100644 index 0000000000..6f8f29cf64 --- /dev/null +++ b/packages/jsii-dotnet-analyzers/tsconfig.json @@ -0,0 +1,54 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "lib": ["es2016", "es2017.object", "es2017.string"], /* Specify library files to be included in the compilation: */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* Enable strict null checks. */ + "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + "strictPropertyInitialization": false, /* DO NOT Raise error on class attribute not initialized by constructor. */ + + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": false, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": false, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Amazon.JSII.Runtime.csproj b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Amazon.JSII.Runtime.csproj index a157ba16b6..761a89bc56 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Amazon.JSII.Runtime.csproj +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Amazon.JSII.Runtime.csproj @@ -14,10 +14,9 @@ - + - diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Deputy/JsiiOptionalAttribute.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Deputy/JsiiOptionalAttribute.cs new file mode 100644 index 0000000000..1102879073 --- /dev/null +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Deputy/JsiiOptionalAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Amazon.JSII.Runtime.Deputy +{ + /// + /// Flags a property as optional. + /// This is used by the jsii-dotnet-analyzers package to emit errors + /// on required properties that are missing. + /// + [AttributeUsage(AttributeTargets.Property)] + public class JsiiOptionalAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/lib/targets/dotnet/dotnetgenerator.ts b/packages/jsii-pacmak/lib/targets/dotnet/dotnetgenerator.ts index e3e6061256..ff4a2ff95a 100644 --- a/packages/jsii-pacmak/lib/targets/dotnet/dotnetgenerator.ts +++ b/packages/jsii-pacmak/lib/targets/dotnet/dotnetgenerator.ts @@ -644,6 +644,9 @@ export class DotNetGenerator extends Generator { const propName = this.nameutils.convertPropertyName(prop.name); this.dotnetDocGenerator.emitDocs(prop); + if (prop.optional) { + this.code.line('[JsiiOptional]'); + } this.dotnetRuntimeGenerator.emitAttributesForProperty(prop, datatype); let isOverrideKeyWord = ''; diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStruct.cs index c36847573d..2c2b7cdecb 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStruct.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStruct.cs @@ -36,6 +36,7 @@ public string Astring /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "firstOptional", typeJson: "{\"collection\":{\"elementtype\":{\"primitive\":\"string\"},\"kind\":\"array\"}}", isOptional: true, isOverride: true)] [System.Obsolete()] public string[] FirstOptional diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStructProxy.cs index 8c15dae980..f0ac0931da 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStructProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/MyFirstStructProxy.cs @@ -39,6 +39,7 @@ public string Astring /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "firstOptional", typeJson: "{\"collection\":{\"elementtype\":{\"primitive\":\"string\"},\"kind\":\"array\"}}", isOptional: true)] [System.Obsolete()] public string[] FirstOptional diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionals.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionals.cs index d82c4b4553..2635cc9ab5 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionals.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionals.cs @@ -13,6 +13,7 @@ public class StructWithOnlyOptionals : Amazon.JSII.Tests.CalculatorNamespace.Lib /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "optional1", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] [System.Obsolete()] public string Optional1 @@ -24,6 +25,7 @@ public string Optional1 /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "optional2", typeJson: "{\"primitive\":\"number\"}", isOptional: true, isOverride: true)] [System.Obsolete()] public double? Optional2 @@ -35,6 +37,7 @@ public double? Optional2 /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "optional3", typeJson: "{\"primitive\":\"boolean\"}", isOptional: true, isOverride: true)] [System.Obsolete()] public bool? Optional3 diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionalsProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionalsProxy.cs index 2034bc7b4c..3074e21fbe 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionalsProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/StructWithOnlyOptionalsProxy.cs @@ -18,6 +18,7 @@ private StructWithOnlyOptionalsProxy(ByRefValue reference): base(reference) /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "optional1", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] [System.Obsolete()] public string Optional1 @@ -28,6 +29,7 @@ public string Optional1 /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "optional2", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] [System.Obsolete()] public double? Optional2 @@ -38,6 +40,7 @@ public double? Optional2 /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "optional3", typeJson: "{\"primitive\":\"boolean\"}", isOptional: true)] [System.Obsolete()] public bool? Optional3 diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs index b5b70f1476..3fa26cb700 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs @@ -232,6 +232,7 @@ public virtual object UnknownProperty /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optionalEnumValue", typeJson: "{\"fqn\":\"jsii-calc.StringEnum\"}", isOptional: true)] public virtual Amazon.JSII.Tests.CalculatorNamespace.StringEnum? OptionalEnumValue { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Calculator.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Calculator.cs index 3b38368237..27f02c06ab 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Calculator.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Calculator.cs @@ -121,6 +121,7 @@ public virtual Amazon.JSII.Tests.CalculatorNamespace.LibNamespace.Value_ Curr /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "maxValue", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public virtual double? MaxValue { @@ -132,6 +133,7 @@ public virtual double? MaxValue /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "unionProperty", typeJson: "{\"union\":{\"types\":[{\"fqn\":\"jsii-calc.Add\"},{\"fqn\":\"jsii-calc.Multiply\"},{\"fqn\":\"jsii-calc.Power\"}]}}", isOptional: true)] public virtual object UnionProperty { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorProps.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorProps.cs index e6fe4c9cab..d9ee88181e 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorProps.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorProps.cs @@ -12,6 +12,7 @@ public class CalculatorProps : Amazon.JSII.Tests.CalculatorNamespace.ICalculator /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "initialValue", typeJson: "{\"primitive\":\"number\"}", isOptional: true, isOverride: true)] public double? InitialValue { @@ -22,6 +23,7 @@ public double? InitialValue /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "maximumValue", typeJson: "{\"primitive\":\"number\"}", isOptional: true, isOverride: true)] public double? MaximumValue { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorPropsProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorPropsProxy.cs index 9582baa158..f6d967c1e1 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorPropsProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/CalculatorPropsProxy.cs @@ -16,6 +16,7 @@ private CalculatorPropsProxy(ByRefValue reference): base(reference) /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "initialValue", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public double? InitialValue { @@ -25,6 +26,7 @@ public double? InitialValue /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "maximumValue", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public double? MaximumValue { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DefaultedConstructorArgument.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DefaultedConstructorArgument.cs index 15798beccd..929d118bf4 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DefaultedConstructorArgument.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DefaultedConstructorArgument.cs @@ -44,6 +44,7 @@ public virtual System.DateTime Arg3 /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "arg2", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public virtual string Arg2 { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DeprecatedClass.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DeprecatedClass.cs index eb025e0de6..b9c7382590 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DeprecatedClass.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DeprecatedClass.cs @@ -50,6 +50,7 @@ public virtual string ReadonlyProperty /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "mutableProperty", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] [System.Obsolete("shouldn't have been mutable")] public virtual double? MutableProperty diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStruct.cs index 5d82d1ad0a..2b4a1ada28 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStruct.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStruct.cs @@ -44,6 +44,7 @@ public Amazon.JSII.Tests.CalculatorNamespace.DoubleTrouble NonPrimitive /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "anotherOptional", typeJson: "{\"collection\":{\"elementtype\":{\"fqn\":\"@scope/jsii-calc-lib.Value\"},\"kind\":\"map\"}}", isOptional: true, isOverride: true)] public System.Collections.Generic.IDictionary AnotherOptional { @@ -54,6 +55,7 @@ public Amazon.JSII.Tests.CalculatorNamespace.DoubleTrouble NonPrimitive /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optionalAny", typeJson: "{\"primitive\":\"any\"}", isOptional: true, isOverride: true)] public object OptionalAny { @@ -64,6 +66,7 @@ public object OptionalAny /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optionalArray", typeJson: "{\"collection\":{\"elementtype\":{\"primitive\":\"string\"},\"kind\":\"array\"}}", isOptional: true, isOverride: true)] public string[] OptionalArray { @@ -98,6 +101,7 @@ public string Astring /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "firstOptional", typeJson: "{\"collection\":{\"elementtype\":{\"primitive\":\"string\"},\"kind\":\"array\"}}", isOptional: true, isOverride: true)] [System.Obsolete()] public string[] FirstOptional diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStructProxy.cs index da0836ab8f..0b16f241bd 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStructProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DerivedStructProxy.cs @@ -45,6 +45,7 @@ public Amazon.JSII.Tests.CalculatorNamespace.DoubleTrouble NonPrimitive /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "anotherOptional", typeJson: "{\"collection\":{\"elementtype\":{\"fqn\":\"@scope/jsii-calc-lib.Value\"},\"kind\":\"map\"}}", isOptional: true)] public System.Collections.Generic.IDictionary AnotherOptional { @@ -54,6 +55,7 @@ public Amazon.JSII.Tests.CalculatorNamespace.DoubleTrouble NonPrimitive /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optionalAny", typeJson: "{\"primitive\":\"any\"}", isOptional: true)] public object OptionalAny { @@ -63,6 +65,7 @@ public object OptionalAny /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optionalArray", typeJson: "{\"collection\":{\"elementtype\":{\"primitive\":\"string\"},\"kind\":\"array\"}}", isOptional: true)] public string[] OptionalArray { @@ -94,6 +97,7 @@ public string Astring /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "firstOptional", typeJson: "{\"collection\":{\"elementtype\":{\"primitive\":\"string\"},\"kind\":\"array\"}}", isOptional: true)] [System.Obsolete()] public string[] FirstOptional diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptions.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptions.cs index 4ed1aa61a3..fbbd4264a9 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptions.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptions.cs @@ -11,6 +11,7 @@ public class EraseUndefinedHashValuesOptions : Amazon.JSII.Tests.CalculatorNames /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "option1", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Option1 { @@ -21,6 +22,7 @@ public string Option1 /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "option2", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Option2 { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptionsProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptionsProxy.cs index 84dc19301f..9faeb33e5d 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptionsProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EraseUndefinedHashValuesOptionsProxy.cs @@ -15,6 +15,7 @@ private EraseUndefinedHashValuesOptionsProxy(ByRefValue reference): base(referen /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "option1", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Option1 { @@ -24,6 +25,7 @@ public string Option1 /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "option2", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Option2 { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ExperimentalClass.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ExperimentalClass.cs index 47db920320..9a87527611 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ExperimentalClass.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ExperimentalClass.cs @@ -44,6 +44,7 @@ public virtual string ReadonlyProperty /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "mutableProperty", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public virtual double? MutableProperty { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Greetee.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Greetee.cs index ccd8effa38..19d064df54 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Greetee.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/Greetee.cs @@ -15,6 +15,7 @@ public class Greetee : Amazon.JSII.Tests.CalculatorNamespace.IGreetee /// world /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "name", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Name { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/GreeteeProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/GreeteeProxy.cs index bf9232f9ab..181ebd82c7 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/GreeteeProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/GreeteeProxy.cs @@ -19,6 +19,7 @@ private GreeteeProxy(ByRefValue reference): base(reference) /// world /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "name", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Name { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IDeprecatedInterfaceProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IDeprecatedInterfaceProxy.cs index cca4d9bd98..f1d60e948c 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IDeprecatedInterfaceProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IDeprecatedInterfaceProxy.cs @@ -16,6 +16,7 @@ private IDeprecatedInterfaceProxy(ByRefValue reference): base(reference) /// /// stability: Deprecated /// + [JsiiOptional] [JsiiProperty(name: "mutableProperty", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] [System.Obsolete("could be better")] public double? MutableProperty diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IExperimentalInterfaceProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IExperimentalInterfaceProxy.cs index 5480a314be..09b159632b 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IExperimentalInterfaceProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IExperimentalInterfaceProxy.cs @@ -15,6 +15,7 @@ private IExperimentalInterfaceProxy(ByRefValue reference): base(reference) /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "mutableProperty", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public double? MutableProperty { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IStableInterfaceProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IStableInterfaceProxy.cs index d951e4593f..5b7b4f6f98 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IStableInterfaceProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IStableInterfaceProxy.cs @@ -15,6 +15,7 @@ private IStableInterfaceProxy(ByRefValue reference): base(reference) /// /// stability: Stable /// + [JsiiOptional] [JsiiProperty(name: "mutableProperty", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public double? MutableProperty { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/InterfaceInNamespaceIncludesClasses/Foo.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/InterfaceInNamespaceIncludesClasses/Foo.cs index 4f9fab38a5..50e5611192 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/InterfaceInNamespaceIncludesClasses/Foo.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/InterfaceInNamespaceIncludesClasses/Foo.cs @@ -23,6 +23,7 @@ protected Foo(DeputyProps props): base(props) /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "bar", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public virtual string Bar { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JsiiAgent_.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JsiiAgent_.cs index 2759a17388..9208e398f1 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JsiiAgent_.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JsiiAgent_.cs @@ -25,6 +25,7 @@ protected JsiiAgent_(DeputyProps props): base(props) /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "jsiiAgent", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public static string JsiiAgent { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServiceProps.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServiceProps.cs index 25c3f9f42f..3f4ad3c875 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServiceProps.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServiceProps.cs @@ -16,6 +16,7 @@ public class LoadBalancedFargateServiceProps : Amazon.JSII.Tests.CalculatorNames /// 80 /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "containerPort", typeJson: "{\"primitive\":\"number\"}", isOptional: true, isOverride: true)] public double? ContainerPort { @@ -30,6 +31,7 @@ public double? ContainerPort /// 256 /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "cpu", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Cpu { @@ -57,6 +59,7 @@ public string Cpu /// 512 /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "memoryMiB", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string MemoryMiB { @@ -70,6 +73,7 @@ public string MemoryMiB /// true /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "publicLoadBalancer", typeJson: "{\"primitive\":\"boolean\"}", isOptional: true, isOverride: true)] public bool? PublicLoadBalancer { @@ -83,6 +87,7 @@ public bool? PublicLoadBalancer /// false /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "publicTasks", typeJson: "{\"primitive\":\"boolean\"}", isOptional: true, isOverride: true)] public bool? PublicTasks { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServicePropsProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServicePropsProxy.cs index 56607197f6..c68b635314 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServicePropsProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/LoadBalancedFargateServicePropsProxy.cs @@ -20,6 +20,7 @@ private LoadBalancedFargateServicePropsProxy(ByRefValue reference): base(referen /// 80 /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "containerPort", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public double? ContainerPort { @@ -33,6 +34,7 @@ public double? ContainerPort /// 256 /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "cpu", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Cpu { @@ -59,6 +61,7 @@ public string Cpu /// 512 /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "memoryMiB", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string MemoryMiB { @@ -71,6 +74,7 @@ public string MemoryMiB /// true /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "publicLoadBalancer", typeJson: "{\"primitive\":\"boolean\"}", isOptional: true)] public bool? PublicLoadBalancer { @@ -83,6 +87,7 @@ public bool? PublicLoadBalancer /// false /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "publicTasks", typeJson: "{\"primitive\":\"boolean\"}", isOptional: true)] public bool? PublicTasks { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefined.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefined.cs index 897d15eda1..4b3cd58211 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefined.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefined.cs @@ -54,6 +54,7 @@ public virtual void VerifyPropertyIsUndefined() /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "changeMeToUndefined", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public virtual string ChangeMeToUndefined { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedData.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedData.cs index 9bf866fef9..a88fd52f43 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedData.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedData.cs @@ -21,6 +21,7 @@ public object[] ArrayWithThreeElementsAndUndefinedAsSecondArgument /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "thisShouldBeUndefined", typeJson: "{\"primitive\":\"any\"}", isOptional: true, isOverride: true)] public object ThisShouldBeUndefined { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedDataProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedDataProxy.cs index f409bb3aac..591bd0cf89 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedDataProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NullShouldBeTreatedAsUndefinedDataProxy.cs @@ -24,6 +24,7 @@ public object[] ArrayWithThreeElementsAndUndefinedAsSecondArgument /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "thisShouldBeUndefined", typeJson: "{\"primitive\":\"any\"}", isOptional: true)] public object ThisShouldBeUndefined { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalConstructorArgument.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalConstructorArgument.cs index 3cbbc1ac03..8a36aa1250 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalConstructorArgument.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalConstructorArgument.cs @@ -44,6 +44,7 @@ public virtual string Arg2 /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "arg3", typeJson: "{\"primitive\":\"date\"}", isOptional: true)] public virtual System.DateTime? Arg3 { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStruct.cs index 685ed0bc75..0e55a0c4af 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStruct.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStruct.cs @@ -11,6 +11,7 @@ public class OptionalStruct : Amazon.JSII.Tests.CalculatorNamespace.IOptionalStr /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "field", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Field { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructConsumer.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructConsumer.cs index 7dac995a47..c473601635 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructConsumer.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructConsumer.cs @@ -35,6 +35,7 @@ public virtual bool ParameterWasUndefined /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "fieldValue", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public virtual string FieldValue { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructProxy.cs index d831d90c68..9f26565881 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/OptionalStructProxy.cs @@ -15,6 +15,7 @@ private OptionalStructProxy(ByRefValue reference): base(reference) /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "field", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Field { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ReferenceEnumFromScopedPackage.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ReferenceEnumFromScopedPackage.cs index d0822350e9..f9aa6e4946 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ReferenceEnumFromScopedPackage.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/ReferenceEnumFromScopedPackage.cs @@ -42,6 +42,7 @@ public virtual void SaveFoo(Amazon.JSII.Tests.CalculatorNamespace.LibNamespace.E /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "foo", typeJson: "{\"fqn\":\"@scope/jsii-calc-lib.EnumFromScopedModule\"}", isOptional: true)] public virtual Amazon.JSII.Tests.CalculatorNamespace.LibNamespace.EnumFromScopedModule? Foo { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStruct.cs index 3dbc4c062b..7c40a353be 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStruct.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStruct.cs @@ -23,6 +23,7 @@ public string DeeperRequiredProp /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "deeperOptionalProp", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string DeeperOptionalProp { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStructProxy.cs index fa23095a8f..79d73c80f6 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStructProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/SecondLevelStructProxy.cs @@ -26,6 +26,7 @@ public string DeeperRequiredProp /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "deeperOptionalProp", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string DeeperOptionalProp { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StableClass.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StableClass.cs index eea996a83f..606e61050a 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StableClass.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StableClass.cs @@ -44,6 +44,7 @@ public virtual string ReadonlyProperty /// /// stability: Stable /// + [JsiiOptional] [JsiiProperty(name: "mutableProperty", typeJson: "{\"primitive\":\"number\"}", isOptional: true)] public virtual double? MutableProperty { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWords.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWords.cs index 3067e8e87e..438bb39094 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWords.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWords.cs @@ -21,6 +21,7 @@ public string Default /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "assert", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Assert { @@ -31,6 +32,7 @@ public string Assert /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "result", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Result { @@ -41,6 +43,7 @@ public string Result /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "that", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string That { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWordsProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWordsProxy.cs index 4ea4f6fa23..b705625b0d 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWordsProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/StructWithJavaReservedWordsProxy.cs @@ -24,6 +24,7 @@ public string Default /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "assert", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Assert { @@ -33,6 +34,7 @@ public string Assert /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "result", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Result { @@ -42,6 +44,7 @@ public string Result /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "that", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string That { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStruct.cs index 107d1c91e6..41725b0da4 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStruct.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStruct.cs @@ -34,6 +34,7 @@ public object SecondLevel /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optional", typeJson: "{\"primitive\":\"string\"}", isOptional: true, isOverride: true)] public string Optional { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStructProxy.cs index 274ccb3ce9..7d683eb598 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStructProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/TopLevelStructProxy.cs @@ -36,6 +36,7 @@ public object SecondLevel /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "optional", typeJson: "{\"primitive\":\"string\"}", isOptional: true)] public string Optional { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionProperties.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionProperties.cs index 71b5875699..606c4ac6b5 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionProperties.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionProperties.cs @@ -21,6 +21,7 @@ public object Bar /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "foo", typeJson: "{\"union\":{\"types\":[{\"primitive\":\"string\"},{\"primitive\":\"number\"}]}}", isOptional: true, isOverride: true)] public object Foo { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionPropertiesProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionPropertiesProxy.cs index 41c79d7eea..cb853c0301 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionPropertiesProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnionPropertiesProxy.cs @@ -24,6 +24,7 @@ public object Bar /// /// stability: Experimental /// + [JsiiOptional] [JsiiProperty(name: "foo", typeJson: "{\"union\":{\"types\":[{\"primitive\":\"string\"},{\"primitive\":\"number\"}]}}", isOptional: true)] public object Foo {