diff --git a/.github/workflows/npm-build-test.yml b/.github/workflows/npm-build-test.yml
new file mode 100644
index 0000000000..a65c009705
--- /dev/null
+++ b/.github/workflows/npm-build-test.yml
@@ -0,0 +1,37 @@
+name: shesha-reactjs-build
+description: Attempt to build the shesha-reactjs project to ensure the branch is not broken
+
+on:
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ pull-requests: write
+ contents: read
+
+jobs:
+ build-attempt:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ./shesha-reactjs
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '20'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build
+ id: build
+ run: npm run build
+
\ No newline at end of file
diff --git a/ChangeLog.md b/ChangeLog.md
index 223724d9a6..c1a1f80052 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,29 +1,3 @@
# Release Notes
## Enhancements
-- **Ehanced Form Settings**: Introduced configurable form lifecycle management, providing more flexibility in form handling.
- - **Appearance**: Contains all settings related to form view (layout, size etc).
- - **Data**: Contains settings related to data processing and form lifecylce.
- - **Security**: Security related settings.
-- **Enhanced App Settings Page**: Expanded the App Settings page to manage front-end specific settings in addition to general settings, including Default URL, Theme, and Main Menu configurations.
- - **Default URL**: This is the url the user should be redirected to if the user is not authenticated and does not specify a specific page.
- - **Main Menu Settings**: Here you can configure the sidebar menu items by adjusting their settings and ordering.
- - **Theme Settings**: Here you customise the theme color of the application.
-- **Enhanced Button Component**: Added additional styling properties to the Button Component for improved customization.
-- **Exposed getAnonymousForms Endpoint**: Made the getAnonymousForms endpoint accessible for easier integration.
-- **Improved JavaScript Settings Component**: Updated the JS settings component for better performance and user experience.
-- **Configurable User Profile**: Allowed additional configurations to be configured below the user logged information.
-- Added `addDelayedUpdateData` variable which is required for files when using a script method.
-- **Style Section Hidden in Table**: The style section is now hidden for Textfield and Autocomplete components when rendered within a table.
-- **Font Weight on Table Column Names**: Increased the font weight to 600 for table column names to enhance visibility and readability.
-- **Reset Wizard State Action**: Exposed an action on Wizard actions that allows resetting the wizard state.
-
-## Bug Fixes
-- **Component Label Issue**: Fixed an issue where components (Address, Entity Reference, Subform, ChildEntitiesTag Group) did not append the label by default when a property name was selected.
-- **Base64 Image Rendering**: Resolved a problem with Base64 images not rendering in the Image component and container background property.
-- **CRUD Operations Column Expansion**: Corrected the unexpected expansion of CRUD operations columns when using the toogle columns selector option.
-- **Table View Component Issue**: Fixed the "add item" modal in the newly created Table view component, which was not closeable by default.
-- **Permission Configurations Import**: Addressed a bug causing the application to break when importing permission configurations with ConfigMigrations.
-- **setFormData Initialization**: Resolved an issue where setFormData used on Initialization did not append values to the specified field in forms.
-- **Backend Endpoint Management**: Fixed the issue where the backend did not properly remove or reinstate endpoints when disabled or enabled.
-- **Duplicate Records from Button Clicks**: Fixed a bug causing duplicate records due to multiple clicks on the default, custom buttons and datalist during network delays.
-- **Notes Component Overflow Issue**: Fixed an issue where clicking 'More' on long notes caused them to overlap outside the line section on the Notes component.
+- Component property updates
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 0000000000..2bd90f40f8
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,68 @@
+variables:
+ - name: 'BuildParameters.configuration'
+ value: release
+
+# trigger:
+# - main
+
+pool:
+ name: Azure Pipelines
+stages:
+ - stage: build
+ jobs:
+ - job: UnitTests_1
+ displayName: 'Unit Tests'
+ pool:
+ name: Azure Pipelines
+ vmImage: ubuntu-22.04
+ steps:
+ - checkout: self
+ - task: NuGetToolInstaller@1
+ inputs:
+ versionSpec: '6.x'
+ checkLatest: true
+ - task: NuGetCommand@2
+ condition: ne(variables.CACHE_RESTORED, true)
+ displayName: Nuget Restore
+ inputs:
+ command: 'restore'
+ feedsToUse: 'config'
+ restoreSolution: 'shesha-core/Shesha.sln'
+ nugetConfigPath: 'shesha-core/.nuget/NuGet.Azure.Config'
+ - task: UseDotNet@2
+ displayName: Use .NET Core sdk 8.x
+ retryCountOnTaskFailure: 3
+ inputs:
+ version: 8.x
+ - task: DotNetCoreCLI@2
+ displayName: dotnet build
+ inputs:
+ projects: shesha-core/Shesha.sln
+ arguments: --configuration $(BuildParameters.configuration)
+ - task: DockerInstaller@0
+ inputs:
+ dockerVersion: '20.10.11'
+ - script: |
+ docker --version
+ sudo systemctl start docker
+ displayName: 'Verify Docker'
+ - task: Docker@2
+ inputs:
+ containerRegistry: 'docker-images'
+ command: 'login'
+ - script: dotnet test Shesha.Tests.csproj --configuration $(buildConfiguration) --no-build --logger "trx;LogFileName=testresults.trx"
+ workingDirectory: 'shesha-core/test/Shesha.Tests'
+ displayName: 'Run tests with Testcontainers'
+ env:
+ DOCKER_HOST: 'unix:///var/run/docker.sock'
+ TESTCONTAINERS_RYUK_DISABLED: 'true'
+ - task: PublishTestResults@2
+ displayName: 'Publish test results'
+ inputs:
+ testResultsFormat: 'VSTest'
+ testResultsFiles: '**/*.trx'
+ failTaskOnFailedTests: true
+ failTaskOnFailureToPublishResults: true
+ failTaskOnMissingResultsFile: true
+ testRunTitle: 'Unit Tests'
+ condition: succeededOrFailed()
\ No newline at end of file
diff --git a/shesha-core/.nuget/NuGet.Azure.Config b/shesha-core/.nuget/NuGet.Azure.Config
new file mode 100644
index 0000000000..e6bf919ab9
--- /dev/null
+++ b/shesha-core/.nuget/NuGet.Azure.Config
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shesha-core/.nuget/NuGet.Config b/shesha-core/.nuget/NuGet.Config
index b192b019bc..e56dc7d6ca 100644
--- a/shesha-core/.nuget/NuGet.Config
+++ b/shesha-core/.nuget/NuGet.Config
@@ -5,10 +5,9 @@
+
-
-
diff --git a/shesha-core/README.md b/shesha-core/README.md
index f01e544764..5c9386551e 100644
--- a/shesha-core/README.md
+++ b/shesha-core/README.md
@@ -6,7 +6,7 @@ shesha-core
## License
-Shesha and the various shesha community components and services are available under the [GPL-3.0 license](https://opensource.org/licenses/GPL-3.0). Shesha also includes external libraries that are available under a variety of licenses. See [LICENSE](https://github.com/shesha-io/shesha-framework/blob/main/shesha-reactjs/LICENCE.md) for the full license text
+Shesha and the various shesha community components and services are available under the [Apache License 2.0](../LICENSE.md). Shesha also includes external libraries that are available under a variety of licenses. See [LICENSE.md](../LICENSE.md) for the full license text.
## Running locally from CLI:
diff --git a/shesha-core/Shesha.sln b/shesha-core/Shesha.sln
index 9f98b1a654..0931ecbab5 100644
--- a/shesha-core/Shesha.sln
+++ b/shesha-core/Shesha.sln
@@ -50,6 +50,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shesha.NHibernate.PostGis",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shesha.Common", "src\Shesha.Common\Shesha.Common.csproj", "{97D1FF0C-72EF-4C45-93B3-C169BCD654FA}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "analyzers", "analyzers", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SheshaCodeAnalyzers", "analyzers\SheshaCodeAnalyzers\SheshaCodeAnalyzers.csproj", "{588EA4DF-22E2-64C6-2DD1-6E8ADEDCBF1B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SheshaCodeAnalyzers.CodeFixes", "analyzers\SheshaCodeAnalyzers.CodeFixes\SheshaCodeAnalyzers.CodeFixes.csproj", "{05DC5A74-CCC2-3A28-008A-F69B34CF66E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SheshaCodeAnalyzers.Package", "analyzers\SheshaCodeAnalyzers.Package\SheshaCodeAnalyzers.Package.csproj", "{18145AAA-0E16-6212-F535-4A82F5069A17}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SheshaCodeAnalyzers.Test", "analyzers\SheshaCodeAnalyzers.Test\SheshaCodeAnalyzers.Test.csproj", "{C2196593-1C13-50DC-5C68-2C3B3193BB38}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -128,6 +138,22 @@ Global
{97D1FF0C-72EF-4C45-93B3-C169BCD654FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97D1FF0C-72EF-4C45-93B3-C169BCD654FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97D1FF0C-72EF-4C45-93B3-C169BCD654FA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {588EA4DF-22E2-64C6-2DD1-6E8ADEDCBF1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {588EA4DF-22E2-64C6-2DD1-6E8ADEDCBF1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {588EA4DF-22E2-64C6-2DD1-6E8ADEDCBF1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {588EA4DF-22E2-64C6-2DD1-6E8ADEDCBF1B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {05DC5A74-CCC2-3A28-008A-F69B34CF66E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {05DC5A74-CCC2-3A28-008A-F69B34CF66E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {05DC5A74-CCC2-3A28-008A-F69B34CF66E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {05DC5A74-CCC2-3A28-008A-F69B34CF66E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {18145AAA-0E16-6212-F535-4A82F5069A17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {18145AAA-0E16-6212-F535-4A82F5069A17}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {18145AAA-0E16-6212-F535-4A82F5069A17}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {18145AAA-0E16-6212-F535-4A82F5069A17}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2196593-1C13-50DC-5C68-2C3B3193BB38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2196593-1C13-50DC-5C68-2C3B3193BB38}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2196593-1C13-50DC-5C68-2C3B3193BB38}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C2196593-1C13-50DC-5C68-2C3B3193BB38}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -152,6 +178,10 @@ Global
{2A550F70-7843-4188-BD57-C994E0D27DA2} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{ADC60E62-AAD0-44A0-87DC-126170557958} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{97D1FF0C-72EF-4C45-93B3-C169BCD654FA} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
+ {588EA4DF-22E2-64C6-2DD1-6E8ADEDCBF1B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {05DC5A74-CCC2-3A28-008A-F69B34CF66E5} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {18145AAA-0E16-6212-F535-4A82F5069A17} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {C2196593-1C13-50DC-5C68-2C3B3193BB38} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {95ED23F3-8DEA-456E-A44B-87A161CB696A}
diff --git a/shesha-core/analyzers/Directory.Build.props b/shesha-core/analyzers/Directory.Build.props
new file mode 100644
index 0000000000..65b8ccf793
--- /dev/null
+++ b/shesha-core/analyzers/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+ true
+ $(NoWarn);CS1591;612;618;809;AsyncFixer01;8618;
+
+
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/CodeFixResources.Designer.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/CodeFixResources.Designer.cs
new file mode 100644
index 0000000000..b3b4b96051
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/CodeFixResources.Designer.cs
@@ -0,0 +1,83 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+namespace SheshaCodeAnalyzers
+{
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class CodeFixResources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CodeFixResources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (object.ReferenceEquals(resourceMan, null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SheshaCodeAnalyzers.CodeFixResources", typeof(CodeFixResources).GetTypeInfo().Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Make uppercase.
+ ///
+ internal static string CodeFixTitle
+ {
+ get
+ {
+ return ResourceManager.GetString("CodeFixTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/CodeFixResources.resx b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/CodeFixResources.resx
new file mode 100644
index 0000000000..97abe68945
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/CodeFixResources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Make uppercase
+ The title of the code fix.
+
+
\ No newline at end of file
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/RestrictedStaticPropertyCodeFixProvider.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/RestrictedStaticPropertyCodeFixProvider.cs
new file mode 100644
index 0000000000..51a7c33320
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/RestrictedStaticPropertyCodeFixProvider.cs
@@ -0,0 +1,98 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(RestrictedStaticPropertyCodeFixProvider)), Shared]
+ public class RestrictedStaticPropertyCodeFixProvider : CodeFixProvider
+ {
+ public sealed override ImmutableArray FixableDiagnosticIds =>
+ ImmutableArray.Create(RestrictedStaticPropertyAnalyzer.DiagnosticId);
+
+ public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+ var diagnostic = context.Diagnostics[0];
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+
+ var memberAccess = root.FindNode(diagnosticSpan) as MemberAccessExpressionSyntax;
+ if (memberAccess == null)
+ return;
+
+ context.RegisterCodeFix(
+ new MyCodeAction(
+ "Replace with StaticContext usage",
+ c => RemoveRestrictedPropertyAccessAsync(context.Document, memberAccess, c)),
+ diagnostic);
+ }
+
+ private async Task RemoveRestrictedPropertyAccessAsync(
+ Document document,
+ MemberAccessExpressionSyntax memberAccess,
+ CancellationToken cancellationToken)
+ {
+ var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+
+ // Replace the entire expression
+ var newExpression = SyntaxFactory.ParseExpression("StaticContext.IocManager");
+ var newRoot = root.ReplaceNode(memberAccess, newExpression);
+
+ // Add both namespaces if needed
+ newRoot = AddUsingIfMissing(newRoot, "Shesha.Services");
+
+ return document.WithSyntaxRoot(newRoot);
+ }
+
+ private SyntaxNode AddUsingIfMissing(SyntaxNode root, string namespaceToAdd)
+ {
+ if (root is CompilationUnitSyntax compilationUnit)
+ {
+ if (!compilationUnit.Usings.Any(u => u.Name.ToString() == namespaceToAdd))
+ {
+ var newUsing = SyntaxFactory.UsingDirective(
+ SyntaxFactory.ParseName(namespaceToAdd));
+
+ // Add to existing usings, keeping them sorted
+ var newUsings = compilationUnit.Usings.Add(newUsing)
+ .OrderBy(u => u.Name.ToString())
+ .ToList();
+
+ return compilationUnit.WithUsings(SyntaxFactory.List(newUsings));
+ }
+ }
+ return root;
+ }
+
+ private class MyCodeAction : CodeAction
+ {
+ private readonly Func> _createChangedDocument;
+
+ public MyCodeAction(string title, Func> createChangedDocument)
+ {
+ Title = title;
+ _createChangedDocument = createChangedDocument;
+ }
+
+ public override string Title { get; }
+
+ public override string EquivalenceKey => Title;
+
+ protected override Task GetChangedDocumentAsync(CancellationToken cancellationToken)
+ {
+ return _createChangedDocument(cancellationToken);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/SheshaCodeAnalyzers.CodeFixes.csproj b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/SheshaCodeAnalyzers.CodeFixes.csproj
new file mode 100644
index 0000000000..d1d348e8b9
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.CodeFixes/SheshaCodeAnalyzers.CodeFixes.csproj
@@ -0,0 +1,22 @@
+
+
+
+ netstandard2.0
+ false
+ SheshaCodeAnalyzers
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Package/SheshaCodeAnalyzers.Package.csproj b/shesha-core/analyzers/SheshaCodeAnalyzers.Package/SheshaCodeAnalyzers.Package.csproj
new file mode 100644
index 0000000000..b623f0915a
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Package/SheshaCodeAnalyzers.Package.csproj
@@ -0,0 +1,45 @@
+
+
+
+ netstandard2.0
+ false
+ true
+ true
+
+
+
+ SheshaCodeAnalyzers
+ 1.0.0.0
+ ivan
+ http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE
+ http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE
+ http://ICON_URL_HERE_OR_DELETE_THIS_LINE
+ http://REPOSITORY_URL_HERE_OR_DELETE_THIS_LINE
+ false
+ SheshaCodeAnalyzers
+ Summary of changes made in this release of the package.
+ Copyright
+ SheshaCodeAnalyzers, analyzers
+ true
+ true
+
+ $(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Package/tools/install.ps1 b/shesha-core/analyzers/SheshaCodeAnalyzers.Package/tools/install.ps1
new file mode 100644
index 0000000000..53136a238f
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Package/tools/install.ps1
@@ -0,0 +1,275 @@
+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)
+ }
+ }
+ }
+}
+# SIG # Begin signature block
+# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA/i+qRUHsWzI0s
+# FVk99zLgt/HOEQ33uvkFsWtHTHZgf6CCDXYwggX0MIID3KADAgECAhMzAAADTrU8
+# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
+# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
+# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
+# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
+# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
+# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
+# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
+# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
+# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
+# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
+# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
+# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
+# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
+# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
+# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
+# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
+# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
+# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
+# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
+# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
+# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
+# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
+# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
+# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
+# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
+# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
+# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
+# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
+# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
+# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
+# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
+# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
+# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
+# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
+# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
+# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
+# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
+# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
+# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
+# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
+# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
+# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
+# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
+# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
+# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
+# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
+# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
+# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
+# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
+# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
+# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
+# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
+# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
+# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
+# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
+# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
+# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
+# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
+# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
+# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
+# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
+# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
+# /Xmfwb1tbWrJUnMTDXpQzTGCGgowghoGAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
+# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
+# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
+# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
+# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
+# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIEY4Ow3COroWH11sAEOoStJj
+# 1u4sq9rcx0dAx0gyZLHCMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
+# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
+# BQAEggEAFlSLlk17KQp2AwLbr5e4T5zyE44MGZOdNejIip+Mg8co8qho16qdNSvg
+# AhvoJYxPJJr70DSCU9BIUoWY7hXoi9S4P08YlAid7BUT5OciIgHlrb8I900LaE+S
+# 83rSvfVU1CZCjiSwcgng5DD2VPRo0Lu4G9p2Ky14dyOPwtPvrpsib5s9kewZLdiy
+# /KxEDLKX8P+cHat1xH7RaZLDNxweRS6GSomjE2vjOlQHNSW879XR8bSoAt/m4uR1
+# WyrAxTGZb4miEYX+I5HsrWvbZLw9NSCJ/crbbap3LIobfQtK5binjY7v4MQp/5Oq
+# y4S/4FAfwhWDXfaQfq6YTeOjHRVQbKGCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC
+# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
+# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
+# AwQCAQUABCCV3irbWIoYz2Llfx9YQhUNtcP6GOrL7+YTUXQ4y5qzWAIGZNTJrsAW
+# GBMyMDIzMDgzMTAwMTI1OC45ODNaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
+# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
+# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
+# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTIwMC0w
+# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
+# ghHqMIIHIDCCBQigAwIBAgITMwAAAc9SNr5xS81IygABAAABzzANBgkqhkiG9w0B
+# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
+# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
+# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzA1MjUxOTEy
+# MTFaFw0yNDAyMDExOTEyMTFaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
+# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
+# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
+# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTIwMC0wNUUwLUQ5NDcxJTAjBgNV
+# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
+# AQUAA4ICDwAwggIKAoICAQC4Pct+15TYyrUje553lzBQodgmd5Bz7WuH8SdHpAoW
+# z+01TrHExBSuaMKnxvVMsyYtas5h6aopUGAS5WKVLZAvUtH62TKmAE0JK+i1hafi
+# CSXLZPcRexxeRkOqeZefLBzXp0nudMOXUUab333Ss8LkoK4l3LYxm1Ebsr3b2OTo
+# 2ebsAoNJ4kSxmVuPM7C+RDhGtVKR/EmHsQ9GcwGmluu54bqiVFd0oAFBbw4txTU1
+# mruIGWP/i+sgiNqvdV/wah/QcrKiGlpWiOr9a5aGrJaPSQD2xgEDdPbrSflYxsRM
+# dZCJI8vzvOv6BluPcPPGGVLEaU7OszdYjK5f4Z5Su/lPK1eST5PC4RFsVcOiS4L0
+# sI4IFZywIdDJHoKgdqWRp6Q5vEDk8kvZz6HWFnYLOlHuqMEYvQLr6OgooYU9z0A5
+# cMLHEIHYV1xiaBzx2ERiRY9MUPWohh+TpZWEUZlUm/q9anXVRN0ujejm6OsUVFDs
+# sIMszRNCqEotJGwtHHm5xrCKuJkFr8GfwNelFl+XDoHXrQYL9zY7Np+frsTXQpKR
+# NnmI1ashcn5EC+wxUt/EZIskWzewEft0/+/0g3+8YtMkUdaQE5+8e7C8UMiXOHkM
+# K25jNNQqLCedlJwFIf9ir9SpMc72NR+1j6Uebiz/ZPV74do3jdVvq7DiPFlTb92U
+# KwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFDaeKPtp0eTSVdG+gZc5BDkabTg4MB8G
+# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
+# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
+# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
+# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
+# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
+# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
+# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBQgm4pnA0xkd/9uKXJMzdMYyxUfUm/ZusU
+# Ba32MEZXQuMGp20pSuX2VW9/tpTMo5bkaJdBVoUyd2DbDsNb1kjr/36ntT0jvL3A
+# oWStAFhZBypmpPbx+BPK49ZlejlM4d5epX668tRRGfFip9Til9yKRfXBrXnM/q64
+# IinN7zXEQ3FFQhdJMzt8ibXClO7eFA+1HiwZPWysYWPb/ZOFobPEMvXie+GmEbTK
+# bhE5tze6RrA9aejjP+v1ouFoD5bMj5Qg+wfZXqe+hfYKpMd8QOnQyez+Nlj1ityn
+# OZWfwHVR7dVwV0yLSlPT+yHIO8g+3fWiAwpoO17bDcntSZ7YOBljXrIgad4W4gX+
+# 4tp1eBsc6XWIITPBNzxQDZZRxD4rXzOB6XRlEVJdYZQ8gbXOirg/dNvS2GxcR50Q
+# dOXDAumdEHaGNHb6y2InJadCPp2iT5QLC4MnzR+YZno1b8mWpCdOdRs9g21QbbrI
+# 06iLk9KD61nx7K5ReSucuS5Z9nbkIBaLUxDesFhr1wmd1ynf0HQ51Swryh7YI7TX
+# T0jr81mbvvI9xtoqjFvIhNBsICdCfTR91ylJTH8WtUlpDhEgSqWt3gzNLPTSvXAx
+# XTpIM583sZdd+/2YGADMeWmt8PuMce6GsIcLCOF2NiYZ10SXHZS5HRrLrChuzedD
+# RisWpIu5uTCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
+# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
+# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
+# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
+# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
+# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
+# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
+# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
+# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
+# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
+# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
+# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
+# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
+# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
+# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
+# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
+# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
+# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
+# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
+# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
+# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
+# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
+# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
+# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
+# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
+# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
+# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
+# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
+# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
+# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
+# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
+# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
+# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
+# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
+# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
+# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
+# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
+# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNN
+# MIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
+# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
+# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
+# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjkyMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
+# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDq
+# 8xzVXwLguauAQj1rrJ4/TyEMm6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
+# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6JpNsjAiGA8yMDIzMDgzMDIzMjIy
+# NloYDzIwMjMwODMxMjMyMjI2WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDomk2y
+# AgEAMAcCAQACAi7oMAcCAQACAhLnMAoCBQDom58yAgEAMDYGCisGAQQBhFkKBAIx
+# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI
+# hvcNAQELBQADggEBADE16CHIs3WeXYKQG9djja+StAB7gsNJxV9p+CETL3847UL3
+# +DIeoj6p5g0FkS8PJK2xc+UbcNx6XJO+WUXEbU9GL4mrOCQjYOM+i3r8FEU+l3Gh
+# 6ZG/9ygsIYRXEfDKK4lsbrrUkFQs9nDISHT3f8JZEJJXSsGmwcHWlNC0LC8bv0Jp
+# e2Bw2+SNc6SlGD8Vv45r4WFPHhfSioCz4HSsF1He3/2Wku7OH85FKvugBlsca7+F
+# bpGsDSL4LO9bv60DxuD+8xBZuyTB8s64ifCGlOXCNpK5VaHND48PhoJbuD0COwlM
+# Rn5NlT6T4hhtkPOqNscMlzYHmTOKc5NhWK8PyrIxggQNMIIECQIBATCBkzB8MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
+# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAc9SNr5xS81IygABAAABzzAN
+# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
+# CSqGSIb3DQEJBDEiBCAjGiC3/PscCMBvPZjpZqbYcL2WRZ+Ecf74oiIPQKkjSzCB
+# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EILPpsLqeNS4NuYXE2VJlMuvQeWVA
+# 80ZDFhpOPjSzhPa/MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
+# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
+# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
+# MTACEzMAAAHPUja+cUvNSMoAAQAAAc8wIgQgWdbLA3Co0zf3nE5086HU0tdn0vK7
+# yXyU9aAFpszvWFIwDQYJKoZIhvcNAQELBQAEggIANrHN06oaP0N1lUSxxoJteJgI
+# fQjN82xV5VSE0cwNCBy05fg1VydPERF59+MIwIlJHhikSo3YOj5tt3AohC78U46P
+# 2IdrLHKlA3rjiLUGwQvGUKJUSsEH4uueA1mmh9jwUBJhY3NjTcMQaQqp/oxZTaya
+# l7NqbubBIZvsDD126SUr8jtVWtZZzw8pnWCFb4Rijii4fY1UiQzfQLFwqQuid6tE
+# I0AaY3IoTlp7U9K2wfAPWcP1G7n3qv+990GEiQlGJlCfIJSSJQodzL2QZF5HCn/K
+# SfgkRPn3y/Aax8683mWCT8zricYzO3MZ9j0T7tAcqOiWb7PFCsk5Va44lq4Gv0u+
+# +60FYCAA/Qn6eMuNkqIpBeIK0+NYUcMSwPdY/riKXdgkVLwChEJC5WWznD/Iqsil
+# Jj9XYailhXzYx7Pa2MLays62LPwCnUxRQBTD9/rL3XQMj69iA4lisb51dKAtrqAU
+# 53aRXFn+twYYFTAUQ/oNK14nZEQE5H53xAfhphMokJOu+CnQQKeCMeYlex6Q4zfw
+# TQxP/xXZ+QW2cSZTwh1d5iE0XMhKCZxhxIOF/rRA+75L5GUz60reRZPeH/7USYZL
+# VPc0+kxIdSbNFJAhAp0u59wSMQdBofor3+HfDfmxmoSjfCSH4TvOkNIulX1PPJPX
+# UB7H4n7XHWJPkUU0cUw=
+# SIG # End signature block
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Package/tools/uninstall.ps1 b/shesha-core/analyzers/SheshaCodeAnalyzers.Package/tools/uninstall.ps1
new file mode 100644
index 0000000000..1f6b6d4f0e
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Package/tools/uninstall.ps1
@@ -0,0 +1,282 @@
+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
+ {
+
+ }
+ }
+ }
+ }
+}
+# SIG # Begin signature block
+# MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDC68wb97fg0QGL
+# yXrxJhYfmibzcOh8caqC0uZprfczDaCCDXYwggX0MIID3KADAgECAhMzAAADTrU8
+# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
+# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
+# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
+# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
+# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
+# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
+# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
+# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
+# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
+# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
+# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
+# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
+# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
+# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
+# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
+# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
+# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
+# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
+# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
+# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
+# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
+# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
+# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
+# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
+# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
+# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
+# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
+# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
+# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
+# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
+# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
+# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
+# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
+# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
+# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
+# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
+# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
+# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
+# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
+# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
+# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
+# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
+# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
+# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
+# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
+# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
+# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
+# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
+# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
+# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
+# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
+# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
+# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
+# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
+# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
+# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
+# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
+# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
+# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
+# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
+# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
+# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
+# /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
+# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
+# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
+# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
+# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
+# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIBdcqRcs5QL71hlQnl3M636V
+# 5iTZvb6co3MHeMuIr36qMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
+# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
+# BQAEggEARbhO/zqm6SWBf6DSJ3P1r82VjSyMGXaLtMfTOq/bqHOXPOqC25R1v5uO
+# zu4ri+UOS8dU6EfW6C9Xf/Z1Ue/oxrvxn5j8mPvsmcs5OyDO0hW0Wv6pYEy5Z5up
+# mfcqvfUfl3+ir29lgPuz0f1mLpz0XxqhjqElEi5RfZD1k1YVg65f0qHroP2txql5
+# TfC77DXJ8verzVm1wqXBHTAERQD94TJobahYTCmyaudMjLUVFakv2lTMv0YTnrQR
+# So006ZQg3i1jcVCJt/bRDGKh3xUo1IHgoh3NjMEkxT3iWt8rnX8Us6T6Zg8B2OxC
+# 0EnuIu/eYYUlYTLQxO9eks7w1kVcUqGCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC
+# F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
+# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
+# AwQCAQUABCBQ1HvJFFsT0ICl6oEZlSNN8DlUeQobBHt/oTUGN6iKBgIGZNTKS0Bc
+# GBMyMDIzMDgzMTAwMTI1OC4zODVaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
+# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
+# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
+# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0YwMC0w
+# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
+# ghHtMIIHIDCCBQigAwIBAgITMwAAAdWpAs/Fp8npWgABAAAB1TANBgkqhkiG9w0B
+# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
+# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
+# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzA1MjUxOTEy
+# MzBaFw0yNDAyMDExOTEyMzBaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
+# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
+# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
+# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0YwMC0wNUUwLUQ5NDcxJTAjBgNV
+# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
+# AQUAA4ICDwAwggIKAoICAQDFfak57Oph9vuxtloABiLc6enT+yKH619b+OhGdkyh
+# gNzkX80KUGI/jEqOVMV4Sqt/UPFFidx2t7v2SETj2tAzuVKtDfq2HBpu80vZ0vyQ
+# DydVt4MDL4tJSKqgYofCxDIBrWzJJjgBolKdOJx1ut2TyOc+UOm7e92tVPHpjdg+
+# Omf31TLUf/oouyAOJ/Inn2ih3ASP0QYm+AFQjhYDNDu8uzMdwHF5QdwsscNa9PVS
+# GedLdDLo9jL6DoPF4NYo06lvvEQuSJ9ImwZfBGLy/8hpE7RD4ewvJKmM1+t6eQuE
+# sTXjrGM2WjkW18SgUZ8n+VpL2uk6AhDkCa355I531p0Jkqpoon7dHuLUdZSQO40q
+# mVIQ6qQCanvImTqmNgE/rPJ0rgr0hMPI/uR1T/iaL0mEq4bqak+3sa8I+FAYOI/P
+# C7V+zEek+sdyWtaX+ndbGlv/RJb5mQaGn8NunbkfvHD1Qt5D0rmtMOekYMq7QjYq
+# E3FEP/wAY4TDuJxstjsa2HXi2yUDEg4MJL6/JvsQXToOZ+IxR6KT5t5fB5FpZYBp
+# VLMma3pm5z6VXvkXrYs33NXJqVWLwiswa7NUFV87Es2sou9Idw3yAZmHIYWgOQ+D
+# IY1nY3aG5DODiwN1rJyEb+mbWDagrdVxcncr6UKKO49eoNTXEW+scUf6GwXG0KEy
+# mQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFK/QXKNO35bBMOz3R5giX7Ala2OaMB8G
+# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
+# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
+# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
+# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
+# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
+# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
+# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBmRddqvQuyjRpx0HGxvOqffFrbgFAg0j82
+# v0v7R+/8a70S2V4t7yKYKSsQGI6pvt1A8JGmuZyjmIXmw23AkI5bZkxvSgws8rrB
+# tJw9vakEckcWFQb7JG6b618x0s9Q3DL0dRq46QZRnm7U6234lecvjstAow30dP0T
+# nIacPWKpPc3QgB+WDnglN2fdT1ruQ6WIVBenmpjpG9ypRANKUx5NRcpdJAQW2FqE
+# HTS3Ntb+0tCqIkNHJ5aFsF6ehRovWZp0MYIz9bpJHix0VrjdLVMOpe7wv62t90E3
+# UrE2KmVwpQ5wsMD6YUscoCsSRQZrA5AbwTOCZJpeG2z3vDo/huvPK8TeTJ2Ltu/I
+# tXgxIlIOQp/tbHAiN8Xptw/JmIZg9edQ/FiDaIIwG5YHsfm2u7TwOFyd6OqLw18Z
+# 5j/IvDPzlkwWJxk6RHJF5dS4s3fnyLw3DHBe5Dav6KYB4n8x/cEmD/R44/8gS5Pf
+# uG1srjLdyyGtyh0KiRDSmjw+fa7i1VPoemidDWNZ7ksNadMad4ZoDvgkqOV4A6a+
+# N8HIc/P6g0irrezLWUgbKXSN8iH9RP+WJFx5fBHE4AFxrbAUQ2Zn5jDmHAI3wYcQ
+# DnnEYP51A75WFwPsvBrfrb1+6a1fuTEH1AYdOOMy8fX8xKo0E0Ys+7bxIvFPsUpS
+# zfFjBolmhzCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
+# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
+# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
+# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
+# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
+# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
+# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
+# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
+# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
+# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
+# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
+# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
+# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
+# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
+# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
+# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
+# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
+# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
+# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
+# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
+# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
+# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
+# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
+# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
+# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
+# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
+# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
+# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
+# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
+# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
+# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
+# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
+# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
+# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
+# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
+# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
+# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
+# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ
+# MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
+# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
+# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
+# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdGMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
+# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQBO
+# Ei+S/ZVFe6w1Id31m6Kge26lNKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
+# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6JpN3jAiGA8yMDIzMDgzMDIzMjMx
+# MFoYDzIwMjMwODMxMjMyMzEwWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDomk3e
+# AgEAMAoCAQACAiLLAgH/MAcCAQACAhLTMAoCBQDom59eAgEAMDYGCisGAQQBhFkK
+# BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ
+# KoZIhvcNAQELBQADggEBAC/zAZ9IEqD3nHBUWwxFTfnDSRErnCJ6XGxH5jOVtR0t
+# 9pi7yCpApLpA2D12g1lcv4ugnwGpsbwmFjrcF4WlHemRa77qv409xNhNKrnh3H+U
+# X2hvy9Utp9LiJiqS7lOW5VN1Uv+LbnA+FWt//4J+YLv44D/dliUGjYX623X7KiEX
+# dbdXPR/Sn+W2YVQ19O8liKaFDnDnIAz+WLCfL6EaoGu4Te/Mr65Khy3YWTwQfXxr
+# gR/JMDzLzWossnGszYCN8S8d9X6mfzWuYv4JHLEiThW++WbMLeT2hhKPomcbvqU4
+# wPb/ylDrTrWuAr/fVndECXVjCIzYJiFwOWn/ZfN9FpQxggQNMIIECQIBATCBkzB8
+# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
+# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
+# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAdWpAs/Fp8npWgABAAAB
+# 1TANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
+# MC8GCSqGSIb3DQEJBDEiBCAHS+EjBkJ/YPugQQv1D7eXVQOI4DWPIYpUxpssheDN
+# lTCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EINm/I4YM166JMM7EKIcYvlcb
+# r2CHjKC0LUOmpZIbBsH/MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
+# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
+# IDIwMTACEzMAAAHVqQLPxafJ6VoAAQAAAdUwIgQgBVj4mNvMkXn0xEeEe3i6urr/
+# L5Eh2p4uPk3zOcR/jHIwDQYJKoZIhvcNAQELBQAEggIAiKbnM5VQAwi5gWDevpEJ
+# oHiZRrb0HApEUkca54Oye2+5tyRfWo3ruZvLZueHWsbEzYXclOscHVPjyR1t6s+p
+# W13utx4mDab1BaJCBq1q9IH1HDfCf/kSMb0H02UDNBumrt1s5/oaiiY75S3kigpt
+# XHCKV/AKbi+4vORYdBwJhWvy4kug+zZHWAp7+K4rVeAaMbWOitriFPQaSdZlOkNT
+# VKMbYUtX6VEnhyfr5O390TxPJCdkDznT6rAf5FlQEkim7wb2gb/Osi73KF0dtnRd
+# 0ePNT4GxulYTrAhHsZmyuinh/FIyqJDtW3C+2eVt/lx6GJfAtDA/gVCe9mAL4bYv
+# 7vjocHeLvWJ8bc0PYMCRZXMsU2zkJqVJ7pZWq+z5hGQAHemrQj9hUZBXCEFVZ8dd
+# jEZbIsg2nwZOFakhvdAvvGlTXPbRMOCHblToXAKA8ksRbLob8CDL6Cstoy5VL3al
+# fOAWLj3FYITlvGvAYCtJzHrHdqyphL805Co1syR6YDopR8tDrxgWzJKAby5fIolP
+# 7SfunXsCa0n3xx80aaxR0apljIXZWBSMGZdJmVzASQFxlexNsU1PmaLmmpn0fih/
+# 567e+kyzFG1wiw5btwttSW9hKgCX+yze1B4IK4yquTQSfPikrCpbBaFZ0OlWmOnL
+# r0eKAKY3WDyxYgNyeg6KeCc=
+# SIG # End signature block
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/SheshaCodeAnalyzers.Test.csproj b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/SheshaCodeAnalyzers.Test.csproj
new file mode 100644
index 0000000000..f0c15f7fd4
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/SheshaCodeAnalyzers.Test.csproj
@@ -0,0 +1,28 @@
+
+
+
+ netcoreapp3.1
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/SheshaCodeAnalyzersUnitTests.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/SheshaCodeAnalyzersUnitTests.cs
new file mode 100644
index 0000000000..ea8bcdebc8
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/SheshaCodeAnalyzersUnitTests.cs
@@ -0,0 +1,187 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Linq;
+using System.Threading.Tasks;
+using VerifyCS = SheshaCodeAnalyzers.Test.CSharpCodeFixVerifier<
+ SheshaCodeAnalyzers.RestrictedStaticPropertyAnalyzer,
+ SheshaCodeAnalyzers.RestrictedStaticPropertyCodeFixProvider>;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ [TestClass]
+ public class SheshaCodeAnalyzersUnitTest
+ {
+ //No diagnostics expected to show up
+ [TestMethod]
+ public async Task TestMethod1()
+ {
+ var test = @"";
+
+ await VerifyCS.VerifyAnalyzerAsync(test);
+ }
+
+ //Diagnostic and CodeFix both triggered and checked for
+ [TestMethod]
+ public async Task TestMethod2()
+ {
+ const string testCode = @"
+using System;
+using Abp.Dependency;
+
+class TestClass
+{
+ void TestMethod()
+ {
+ var repository = {|#0:IocManager.Instance|}.Resolve();
+ var time = {|#1:DateTime.Now|};
+ }
+}";
+ var expectedValidation = VerifyCS.Diagnostic(RestrictedStaticPropertyAnalyzer.DiagnosticId)
+ .WithLocation(0)
+ .WithArguments("Abp.Dependency.IocManager", "Instance");
+ await VerifyCS.VerifyAnalyzerAsync(testCode, expectedValidation);
+
+
+ var test = @"
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+ using System.Diagnostics;
+
+ namespace ConsoleApplication1
+ {
+ class {|#0:TypeName|}
+ {
+ }
+ }";
+
+ var fixtest = @"
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+ using System.Diagnostics;
+
+ namespace ConsoleApplication1
+ {
+ class TYPENAME
+ {
+ }
+ }";
+
+ var expected = VerifyCS.Diagnostic(RestrictedStaticPropertyAnalyzer.DiagnosticId).WithLocation(0).WithArguments("TypeName");
+
+ await VerifyCS.VerifyCodeFixAsync(test, expected, fixtest);
+ }
+
+ [TestMethod]
+ public async Task TestAnalyzer()
+ {
+ const string testCode = @"
+using System;
+using Abp.Dependency;
+
+public interface IRepository
+{
+}
+
+class TestClass
+{
+ void TestMethod()
+ {
+ var repository = {|#0:IocManager.Instance|}.Resolve();
+ }
+}";
+
+ const string fixedCode = @"using Abp.Dependency;
+using Shesha.Services;
+using System;
+
+public interface IRepository
+{
+}
+
+class TestClass
+{
+ void TestMethod()
+ {
+ var repository = StaticContext.IocManager.Resolve();
+ }
+}";
+
+ const string abpCode = @"
+using System;
+
+namespace Abp.Dependency {
+ public class IocManager {
+ public static IocManager Instance;
+ public T Resolve()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
+";
+ const string shaCode = @"
+using System;
+using Abp.Dependency;
+
+namespace Shesha.Services {
+ public static class StaticContext {
+ public static IocManager IocManager;
+ }
+}
+";
+
+ var expected = VerifyCS.Diagnostic(RestrictedStaticPropertyAnalyzer.DiagnosticId).WithLocation(0).WithArguments("Abp.Dependency.IocManager", "Instance");
+
+ var testAnalyze = new VerifyCS.Test
+ {
+ TestState = {
+ Sources = { testCode, abpCode, shaCode },
+ },
+ FixedState = {
+ Sources = { fixedCode, abpCode, shaCode }
+ },
+ // Disable automatic verification
+ TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck | TestBehaviors.SkipSuppressionCheck,
+ CodeFixTestBehaviors = CodeFixTestBehaviors.SkipFixAllCheck
+
+ };
+ testAnalyze.TestState.ExpectedDiagnostics.Add(expected);
+
+ // Need to store the solution outside the event handler
+ Solution fixedSolution = null;
+
+ // Register a callback for when fixes are computed
+ testAnalyze.SolutionTransforms.Add((solution, projectId) =>
+ {
+ fixedSolution = solution;
+ return solution; // Return unchanged
+ });
+
+ try
+ {
+ await testAnalyze.RunAsync();
+ }
+ catch
+ {
+ throw;
+ }
+
+ // Assert
+ Assert.IsNotNull(fixedSolution);
+
+ var doc = testAnalyze.TestState.Sources.First();
+ var fixedDocument = fixedSolution.GetDocumentIdsWithFilePath(doc.filename);
+
+ var docId = fixedDocument.First();
+ var fixedDoc = fixedSolution.GetDocument(docId);
+ var fixedText = await fixedDoc.GetTextAsync();
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs
new file mode 100644
index 0000000000..672fd9b293
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs
@@ -0,0 +1,26 @@
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class CSharpAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ public class Test : CSharpAnalyzerTest
+ {
+ public Test()
+ {
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ return solution;
+ });
+ }
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpAnalyzerVerifier`1.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpAnalyzerVerifier`1.cs
new file mode 100644
index 0000000000..a0117591cc
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpAnalyzerVerifier`1.cs
@@ -0,0 +1,38 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class CSharpAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => CSharpAnalyzerVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => CSharpAnalyzerVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => CSharpAnalyzerVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs
new file mode 100644
index 0000000000..b8205edde2
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs
@@ -0,0 +1,28 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class CSharpCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ public class Test : CSharpCodeFixTest
+ {
+ public Test()
+ {
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ return solution;
+ });
+ }
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeFixVerifier`2.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeFixVerifier`2.cs
new file mode 100644
index 0000000000..5753001fd4
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeFixVerifier`2.cs
@@ -0,0 +1,61 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class CSharpCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => CSharpCodeFixVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => CSharpCodeFixVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => CSharpCodeFixVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource)
+ => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
+ => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs
new file mode 100644
index 0000000000..2be88732be
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs
@@ -0,0 +1,26 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class CSharpCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ public class Test : CSharpCodeRefactoringTest
+ {
+ public Test()
+ {
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ return solution;
+ });
+ }
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs
new file mode 100644
index 0000000000..2be77a9ffd
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs
@@ -0,0 +1,36 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class CSharpCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ ///
+ public static async Task VerifyRefactoringAsync(string source, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, new[] { expected }, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpVerifierHelper.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpVerifierHelper.cs
new file mode 100644
index 0000000000..5afe9f7328
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/CSharpVerifierHelper.cs
@@ -0,0 +1,33 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using System;
+using System.Collections.Immutable;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ internal static class CSharpVerifierHelper
+ {
+ ///
+ /// By default, the compiler reports diagnostics for nullable reference types at
+ /// , and the analyzer test framework defaults to only validating
+ /// diagnostics at . This map contains all compiler diagnostic IDs
+ /// related to nullability mapped to , which is then used to enable all
+ /// of these warnings for default validation during analyzer and code fix tests.
+ ///
+ internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler();
+
+ private static ImmutableDictionary GetNullableWarningsFromCompiler()
+ {
+ string[] args = { "/warnaserror:nullable" };
+ var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory);
+ var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
+
+ // Workaround for https://github.com/dotnet/roslyn/issues/41610
+ nullableWarnings = nullableWarnings
+ .SetItem("CS8632", ReportDiagnostic.Error)
+ .SetItem("CS8669", ReportDiagnostic.Error);
+
+ return nullableWarnings;
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs
new file mode 100644
index 0000000000..d7106ecc97
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs
@@ -0,0 +1,17 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class VisualBasicAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ public class Test : VisualBasicAnalyzerTest
+ {
+ public Test()
+ {
+ }
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs
new file mode 100644
index 0000000000..74f5a83984
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs
@@ -0,0 +1,38 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class VisualBasicAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => VisualBasicAnalyzerVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => VisualBasicAnalyzerVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => VisualBasicAnalyzerVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs
new file mode 100644
index 0000000000..6909947892
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs
@@ -0,0 +1,16 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class VisualBasicCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ public class Test : VisualBasicCodeFixTest
+ {
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs
new file mode 100644
index 0000000000..8691e3d070
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs
@@ -0,0 +1,61 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class VisualBasicCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => VisualBasicCodeFixVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => VisualBasicCodeFixVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => VisualBasicCodeFixVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource)
+ => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
+ => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs
new file mode 100644
index 0000000000..114864f01a
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs
@@ -0,0 +1,14 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class VisualBasicCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ public class Test : VisualBasicCodeRefactoringTest
+ {
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs
new file mode 100644
index 0000000000..f78362f926
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs
@@ -0,0 +1,36 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SheshaCodeAnalyzers.Test
+{
+ public static partial class VisualBasicCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ ///
+ public static async Task VerifyRefactoringAsync(string source, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, new[] { expected }, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Vsix/SheshaCodeAnalyzers.Vsix.csproj b/shesha-core/analyzers/SheshaCodeAnalyzers.Vsix/SheshaCodeAnalyzers.Vsix.csproj
new file mode 100644
index 0000000000..3a25f14d5d
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Vsix/SheshaCodeAnalyzers.Vsix.csproj
@@ -0,0 +1,48 @@
+
+
+
+
+
+ net472
+ SheshaCodeAnalyzers.Vsix
+ SheshaCodeAnalyzers.Vsix
+
+
+
+ false
+ false
+ false
+ false
+ false
+ false
+ Roslyn
+
+
+
+
+
+
+
+ Program
+ $(DevEnvDir)devenv.exe
+ /rootsuffix $(VSSDKTargetPlatformRegRootSuffix)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers.Vsix/source.extension.vsixmanifest b/shesha-core/analyzers/SheshaCodeAnalyzers.Vsix/source.extension.vsixmanifest
new file mode 100644
index 0000000000..3e357977b2
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers.Vsix/source.extension.vsixmanifest
@@ -0,0 +1,24 @@
+
+
+
+
+ SheshaCodeAnalyzers
+ This is a sample diagnostic extension for the .NET Compiler Platform ("Roslyn").
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers/Resources.Designer.cs b/shesha-core/analyzers/SheshaCodeAnalyzers/Resources.Designer.cs
new file mode 100644
index 0000000000..d7f04b38d3
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers/Resources.Designer.cs
@@ -0,0 +1,105 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+namespace SheshaCodeAnalyzers
+{
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (object.ReferenceEquals(resourceMan, null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SheshaCodeAnalyzers.Resources", typeof(Resources).GetTypeInfo().Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type names should be all uppercase..
+ ///
+ internal static string AnalyzerDescription
+ {
+ get
+ {
+ return ResourceManager.GetString("AnalyzerDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type name '{0}' contains lowercase letters.
+ ///
+ internal static string AnalyzerMessageFormat
+ {
+ get
+ {
+ return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type name contains lowercase letters.
+ ///
+ internal static string AnalyzerTitle
+ {
+ get
+ {
+ return ResourceManager.GetString("AnalyzerTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers/Resources.resx b/shesha-core/analyzers/SheshaCodeAnalyzers/Resources.resx
new file mode 100644
index 0000000000..410edccd7c
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers/Resources.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Type names should be all uppercase.
+ An optional longer localizable description of the diagnostic.
+
+
+ Type name '{0}' contains lowercase letters
+ The format-able message the diagnostic displays.
+
+
+ Type name contains lowercase letters
+ The title of the diagnostic.
+
+
\ No newline at end of file
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers/RestrictedStaticPropertyAnalyzer.cs b/shesha-core/analyzers/SheshaCodeAnalyzers/RestrictedStaticPropertyAnalyzer.cs
new file mode 100644
index 0000000000..4103acf6fe
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers/RestrictedStaticPropertyAnalyzer.cs
@@ -0,0 +1,75 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace SheshaCodeAnalyzers
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class RestrictedStaticPropertyAnalyzer : DiagnosticAnalyzer
+ {
+ private static readonly ImmutableDictionary RestrictedProperties =
+ ImmutableDictionary.CreateRange(new[]
+ {
+ new KeyValuePair("Abp.Dependency.IocManager", new[] { "Instance" }),
+ //new KeyValuePair("System.Environment", new[] { "CurrentDirectory", "ExitCode" }),
+ //new KeyValuePair("System.DateTime", new[] { "Now", "UtcNow" })
+ });
+
+ public const string DiagnosticId = "SHA001";
+ private const string Category = "Usage";
+
+ private static readonly LocalizableString Title = "Restricted static property access";
+ private static readonly LocalizableString MessageFormat = "Usage of property '{1}' from static class '{0}' is not allowed";
+ private static readonly LocalizableString Description = "Certain static properties are restricted from usage in this codebase.";
+
+ 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.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterSyntaxNodeAction(AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression);
+ }
+
+ private static void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
+ {
+ var memberAccess = (MemberAccessExpressionSyntax)context.Node;
+
+ if (!(memberAccess.Name is IdentifierNameSyntax propertyNameSyntax))
+ return;
+
+ var propertyName = propertyNameSyntax.Identifier.Text;
+ var expression = memberAccess.Expression;
+ var typeInfo = context.SemanticModel.GetTypeInfo(expression);
+
+ if (typeInfo.Type == null)
+ return;
+
+ var fullTypeName = typeInfo.Type.ToDisplayString();
+
+ if (!RestrictedProperties.TryGetValue(fullTypeName, out var restrictedProps))
+ return;
+
+ if (!restrictedProps.Contains(propertyName))
+ return;
+
+ var diagnostic = Diagnostic.Create(
+ Rule,
+ memberAccess.GetLocation(),
+ fullTypeName,
+ propertyName);
+
+ context.ReportDiagnostic(diagnostic);
+ }
+ }
+}
diff --git a/shesha-core/analyzers/SheshaCodeAnalyzers/SheshaCodeAnalyzers.csproj b/shesha-core/analyzers/SheshaCodeAnalyzers/SheshaCodeAnalyzers.csproj
new file mode 100644
index 0000000000..7176c81d7f
--- /dev/null
+++ b/shesha-core/analyzers/SheshaCodeAnalyzers/SheshaCodeAnalyzers.csproj
@@ -0,0 +1,21 @@
+
+
+
+ netstandard2.0
+ false
+
+
+ *$(MSBuildProjectFile)*
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shesha-core/local-packages/SheshaCodeAnalyzers.1.0.0.nupkg b/shesha-core/local-packages/SheshaCodeAnalyzers.1.0.0.nupkg
new file mode 100644
index 0000000000..1fd9e4794f
Binary files /dev/null and b/shesha-core/local-packages/SheshaCodeAnalyzers.1.0.0.nupkg differ
diff --git a/shesha-core/Directory.Build.props b/shesha-core/src/Directory.Build.props
similarity index 50%
rename from shesha-core/Directory.Build.props
rename to shesha-core/src/Directory.Build.props
index aa7ca60e8b..1ad5c39ca8 100644
--- a/shesha-core/Directory.Build.props
+++ b/shesha-core/src/Directory.Build.props
@@ -1,8 +1,9 @@
-
- true
- $(NoWarn);CS1591;612;618;809
-
+
+ enable
+ true
+ $(NoWarn);CS1591;612;618;809;AsyncFixer01;8618;
+
True
@@ -10,4 +11,10 @@
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/shesha-core/src/Shesha.Application/AbpAsyncCrudAppService.cs b/shesha-core/src/Shesha.Application/AbpAsyncCrudAppService.cs
index 85751527c2..be088a3d6e 100644
--- a/shesha-core/src/Shesha.Application/AbpAsyncCrudAppService.cs
+++ b/shesha-core/src/Shesha.Application/AbpAsyncCrudAppService.cs
@@ -2,11 +2,9 @@
using Abp.Application.Services.Dto;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
-using Abp.Linq;
-using System;
-using System.Collections.Generic;
+using Abp.Linq.Extensions;
+using Shesha.Application.Services.Dto;
using System.Linq;
-using System.Text;
using System.Threading.Tasks;
namespace Shesha
@@ -29,7 +27,7 @@ protected AbpAsyncCrudAppService(IRepository repository)
}
public abstract class AbpAsyncCrudAppService
- : AbpAsyncCrudAppService
+ : AbpAsyncCrudAppService
where TEntity : class, IEntity
where TEntityDto : IEntityDto
{
@@ -169,6 +167,22 @@ protected virtual Task GetEntityByIdAsync(TPrimaryKey id)
{
return Repository.GetAsync(id);
}
- }
+ protected override IQueryable ApplyPaging(IQueryable query, TGetAllInput input)
+ {
+ if (input is IPagedResultRequest pagedInput)
+ {
+ if (pagedInput.SkipCount > 0)
+ query = query.Skip(pagedInput.SkipCount);
+ }
+
+ if (input is ILimitedResultRequest limitedInput)
+ {
+ if (limitedInput.MaxResultCount > 0 && limitedInput.MaxResultCount < int.MaxValue)
+ query = query.Take(limitedInput.MaxResultCount);
+ }
+
+ return query;
+ }
+ }
}
diff --git a/shesha-core/src/Shesha.Application/AbpCrudAppService.cs b/shesha-core/src/Shesha.Application/AbpCrudAppService.cs
index 0ce0b11814..d797494bec 100644
--- a/shesha-core/src/Shesha.Application/AbpCrudAppService.cs
+++ b/shesha-core/src/Shesha.Application/AbpCrudAppService.cs
@@ -22,15 +22,15 @@ public abstract class AbpCrudAppService Repository;
- protected virtual string GetPermissionName { get; set; }
+ protected virtual string? GetPermissionName { get; set; }
- protected virtual string GetAllPermissionName { get; set; }
+ protected virtual string? GetAllPermissionName { get; set; }
- protected virtual string CreatePermissionName { get; set; }
+ protected virtual string? CreatePermissionName { get; set; }
- protected virtual string UpdatePermissionName { get; set; }
+ protected virtual string? UpdatePermissionName { get; set; }
- protected virtual string DeletePermissionName { get; set; }
+ protected virtual string? DeletePermissionName { get; set; }
protected AbpCrudAppService(IRepository repository)
{
@@ -131,7 +131,7 @@ protected virtual void MapToEntity(TUpdateInput updateInput, TEntity entity)
ObjectMapper.Map(updateInput, entity);
}
- protected virtual void CheckPermission(string permissionName)
+ protected virtual void CheckPermission(string? permissionName)
{
if (!string.IsNullOrEmpty(permissionName))
{
diff --git a/shesha-core/src/Shesha.Application/Api/ApiAppService.cs b/shesha-core/src/Shesha.Application/Api/ApiAppService.cs
index c9a773756a..d5478c2925 100644
--- a/shesha-core/src/Shesha.Application/Api/ApiAppService.cs
+++ b/shesha-core/src/Shesha.Application/Api/ApiAppService.cs
@@ -16,7 +16,7 @@ namespace Shesha.Api
///
/// API application service
///
- public class ApiAppService: SheshaAppServiceBase//, IApiAppService
+ public class ApiAppService : SheshaAppServiceBase//, IApiAppService
{
private readonly IApiDescriptionGroupCollectionProvider _apiDescriptionsProvider;
private readonly IPermissionedObjectManager _permissionedObjectManager;
@@ -31,7 +31,7 @@ IPermissionedObjectManager permissionedObjectManager
}
[HttpGet]
- public async Task> EndpointsAsync(string term, string verb, int maxResultCount = 10)
+ public async Task> EndpointsAsync(string? term, string? verb, int maxResultCount = 10)
{
var actionDescriptors = _apiDescriptionsProvider.ApiDescriptionGroups.Items.SelectMany(g => g.Items.Select(gi => gi.ActionDescriptor)).ToList();
@@ -42,19 +42,20 @@ public async Task> EndpointsAsync(string term, string
if (await _permissionedObjectManager.IsActionDescriptorEnabledAsync(actionDescriptor))
permissioned.Add(actionDescriptor);
- var allEndpoints = permissioned.SelectMany(desc => {
+ var allEndpoints = permissioned.SelectMany(desc =>
+ {
var verbs = desc.ActionConstraints?.OfType().SelectMany(c => c.HttpMethods).Distinct().ToList() ?? new List { "" };
- var actionDescriptor = desc as ControllerActionDescriptor;
+ return desc is ControllerActionDescriptor actionDescriptor
+ ? verbs.Select(v => new ApiEndpointInfo
+ {
+ HttpVerb = v.ToLower(),
+ Url = "/" + desc.AttributeRouteInfo?.Template?.TrimStart('/'),
- return verbs.Select(v => new ApiEndpointInfo
- {
- HttpVerb = v.ToLower(),
- Url = "/" + desc.AttributeRouteInfo?.Template.TrimStart('/'),
-
- ActionName = actionDescriptor?.ActionName,
- ControllerName = actionDescriptor?.ControllerName,
- });
+ ActionName = actionDescriptor.ActionName,
+ ControllerName = actionDescriptor.ControllerName,
+ })
+ : new List();
})
.Where(i => !string.IsNullOrWhiteSpace(i.Url))
.ToList();
diff --git a/shesha-core/src/Shesha.Application/Api/ApiQuery.cs b/shesha-core/src/Shesha.Application/Api/ApiQuery.cs
deleted file mode 100644
index cfaad8ee8c..0000000000
--- a/shesha-core/src/Shesha.Application/Api/ApiQuery.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using Abp.Application.Services.Dto;
-using Abp.Dependency;
-using GraphQL;
-using GraphQL.Types;
-using Microsoft.AspNetCore.Mvc.ActionConstraints;
-using Microsoft.AspNetCore.Mvc.ApiExplorer;
-using Microsoft.AspNetCore.Mvc.Controllers;
-using Microsoft.Extensions.DependencyInjection;
-using Newtonsoft.Json.Linq;
-using Shesha.Api.Dto;
-using Shesha.Application.Services.Dto;
-using Shesha.GraphQL.Provider.GraphTypes;
-using Shesha.JsonLogic;
-using Shesha.QuickSearch;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace Shesha.Api
-{
- public class ApiQuery: ObjectGraphType, ITransientDependency
- {
- private readonly IJsonLogic2LinqConverter _jsonLogicConverter;
-
- public ApiQuery(IServiceProvider serviceProvider)
- {
- _jsonLogicConverter = serviceProvider.GetRequiredService();
-
- FieldAsync>(
- "endpoints",
- arguments: new QueryArguments(
- new QueryArgument> { Name = "input", DefaultValue = new FilteredPagedAndSortedResultRequestDto() }
- ),
- resolve: context => {
- var input = context.GetArgument("input");
-
- var apiDescriptionsProvider = serviceProvider.GetService();
- var quickSearcher = serviceProvider.GetRequiredService();
-
- var actionDescriptors = apiDescriptionsProvider.ApiDescriptionGroups.Items.SelectMany(g => g.Items.Select(gi => gi.ActionDescriptor)).ToList();
-
- var allEndpoints = actionDescriptors.SelectMany(desc => {
- var verbs = desc.ActionConstraints.OfType().SelectMany(c => c.HttpMethods).Distinct().ToList();
-
- var actionDescriptor = desc as ControllerActionDescriptor;
-
- /*
- if (actionDescriptor != null && actionDescriptor.ActionName.Contains("Query"))
- {
- XmlCommentsNodeNameHelper.GetMemberNameForType();
- }
- */
-
- return verbs.Select(v => new ApiEndpointInfo
- {
- HttpVerb = v,
- Url = desc.AttributeRouteInfo?.Template,
-
- ActionName = actionDescriptor?.ActionName,
- ControllerName = actionDescriptor?.ControllerName,
- });
- })
- .Where(i => !string.IsNullOrWhiteSpace(i.Url))
- .AsQueryable();
-
- var endpoints = AddFilter(allEndpoints, input.Filter);
-
- // add quick search
- if (!string.IsNullOrWhiteSpace(input.QuickSearch))
- endpoints = endpoints.Where(ep => ep.Url.Contains(input.QuickSearch, StringComparison.InvariantCultureIgnoreCase) || (ep.Description ?? "").Contains(input.QuickSearch, StringComparison.InvariantCultureIgnoreCase));
-
- // apply paging
- var pageQuery = endpoints.Skip(input.SkipCount);
- if (input.MaxResultCount > 0)
- pageQuery = pageQuery.Take(input.MaxResultCount);
-
- var result = new PagedResultDto
- {
- Items = pageQuery.ToList(),
- TotalCount = allEndpoints.Count()
- };
-
- return Task.FromResult