├── .all-contributorsrc ├── .config └── dotnet-tools.json ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── dependabot.yml ├── labeler.yml ├── release.yml └── workflows │ ├── build-test-pack.yml │ ├── codeql-analysis.yml │ ├── label-pull-requests.yml │ └── release.yml ├── .gitignore ├── .globalconfig ├── CHANGELOG.md ├── Common.props ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── LICENSE ├── NuGet-README.md ├── NuGet.config ├── PolyKit.sln ├── PolyKit.sln.DotSettings ├── README.md ├── THIRD-PARTY-NOTICES ├── build.cake ├── build ├── BuildData.cake ├── Changelog.cake ├── DocFx.cake ├── THIRD-PARTY-NOTICES ├── dotnet.cake ├── environment.cake ├── fail.cake ├── filesystem.cake ├── git.cake ├── github.cake ├── json.cake ├── nbgv.cake ├── options.cake ├── process.cake ├── public-api.cake ├── setup-teardown.cake ├── utilities.cake ├── versioning.cake └── workspace.cake ├── global.json ├── graphics ├── PackageIcon.png ├── README.md ├── Readme.png ├── Readme.svg ├── SocialCard.png ├── SocialCard.svg ├── SquareLogo.svg └── docs │ ├── favicon.ico │ └── logo.svg ├── src ├── PolyKit.Embedded │ ├── PolyKit.Embedded.csproj │ └── build │ │ └── PolyKit.Embedded.targets ├── PolyKit.Generator │ ├── PolyKit.Generator.csproj │ └── PolyfillGenerator.cs ├── PolyKit.Polyfills │ ├── PolyKit.Polyfills.csproj │ ├── PolyKit │ │ └── Diagnostics │ │ │ └── CodeAnalysis │ │ │ └── ValidatedNotNullAttribute.cs │ └── System │ │ ├── DateOnly.cs │ │ ├── Diagnostics │ │ ├── CodeAnalysis │ │ │ ├── AllowNullAttribute.cs │ │ │ ├── ConstantExpectedAttribute.cs │ │ │ ├── DisallowNullAttribute.cs │ │ │ ├── DoesNotReturnAttribute.cs │ │ │ ├── DoesNotReturnIfAttribute.cs │ │ │ ├── DynamicDependencyAttribute.cs │ │ │ ├── DynamicallyAccessedMemberTypes.cs │ │ │ ├── DynamicallyAccessedMembersAttribute.cs │ │ │ ├── ExperimentalAttribute.cs │ │ │ ├── MaybeNullAttribute.cs │ │ │ ├── MaybeNullWhenAttribute.cs │ │ │ ├── MemberNotNullAttribute.cs │ │ │ ├── MemberNotNullWhenAttribute.cs │ │ │ ├── NotNullAttribute.cs │ │ │ ├── NotNullIfNotNullAttribute.cs │ │ │ ├── NotNullWhenAttribute.cs │ │ │ ├── RequiresAssemblyFilesAttribute.cs │ │ │ ├── RequiresDynamicCodeAttribute.cs │ │ │ ├── RequiresUnreferencedCodeAttribute.cs │ │ │ ├── SetsRequiredMembersAttribute.cs │ │ │ ├── StringSyntaxAttribute.cs │ │ │ ├── UnconditionalSuppressMessageAttribute.cs │ │ │ └── UnscopedRefAttribute.cs │ │ ├── PolyKitStackTraceExtensions.cs │ │ ├── StackTraceHiddenAttribute.cs │ │ └── TraceFormat.cs │ │ ├── HashCode.cs │ │ ├── ISpanFormattable.cs │ │ ├── Index.cs │ │ ├── Linq │ │ └── PolyKitEnumerable.cs │ │ ├── PolyKitExceptionExtensions.cs │ │ ├── Range.cs │ │ ├── Runtime │ │ ├── CompilerServices │ │ │ ├── AsyncMethodBuilderAttribute.cs │ │ │ ├── CallerArgumentExpressionAttribute.cs │ │ │ ├── CompilerFeatureRequiredAttribute.cs │ │ │ ├── InterpolatedStringHandlerArgumentAttribute.cs │ │ │ ├── InterpolatedStringHandlerAttribute.cs │ │ │ ├── IsExternalInit.cs │ │ │ ├── ModuleInitializerAttribute.cs │ │ │ ├── RequiredMemberAttribute.cs │ │ │ └── SkipLocalsInitAttribute.cs │ │ ├── InteropServices │ │ │ └── UnmanagedCallersOnlyAttribute.cs │ │ └── Versioning │ │ │ └── RequiresPreviewFeaturesAttribute.cs │ │ └── TimeOnly.cs └── PolyKit │ └── PolyKit.csproj ├── stylecop.json └── version.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "PolyKit", 3 | "projectOwner": "Tenacom", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "jshint", 12 | "contributorsPerLine": 7, 13 | "contributorsSortAlphabetically": true, 14 | "badgeTemplate": "[![All Contributors](https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square)](#contributors)", 15 | "contributorTemplate": "\">\" width=\"<%= options.imageSize %>px;\" alt=\"\"/>
<%= contributor.name %>
", 16 | "types": { 17 | "custom": {} 18 | }, 19 | "linkToUsage": true, 20 | "skipCi": true, 21 | "contributors": [ 22 | { 23 | "login": "rdeago", 24 | "name": "Riccardo De Agostini", 25 | "avatar_url": "https://avatars.githubusercontent.com/u/139223?v=4", 26 | "profile": "https://github.com/rdeago", 27 | "contributions": [ 28 | "doc", 29 | "code", 30 | "projectManagement", 31 | "ideas", 32 | "maintenance", 33 | "question", 34 | "review" 35 | ] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "4.0.0", 7 | "commands": [ 8 | "dotnet-cake" 9 | ] 10 | }, 11 | "nbgv": { 12 | "version": "3.6.133", 13 | "commands": [ 14 | "nbgv" 15 | ] 16 | }, 17 | "dotnet-reportgenerator-globaltool": { 18 | "version": "5.2.0", 19 | "commands": [ 20 | "reportgenerator" 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # IMPORTANT: Always keep EOL settings in sync with .editorconfig 2 | 3 | # Default settings 4 | * text=auto 5 | 6 | # Solution files 7 | *.sln text eol=crlf 8 | 9 | # Code files 10 | *.cake text eol=crlf diff=csharp 11 | *.cs text eol=crlf diff=csharp 12 | *.vb text eol=crlf 13 | 14 | # XML project files 15 | *.csproj text eol=lf 16 | *.vbproj text eol=lf 17 | *.vcxproj text eol=lf 18 | *.vcxproj.filters text eol=lf 19 | *.proj text eol=lf 20 | *.projitems text eol=lf 21 | *.shproj text eol=lf 22 | *.props text eol=lf 23 | *.targets text eol=lf 24 | 25 | # XML config files 26 | *.ruleset text eol=lf 27 | *.config text eol=lf 28 | *.nuspec text eol=lf 29 | *.resx text eol=lf 30 | *.vsixmanifest text eol=lf 31 | *.vsct text eol=lf 32 | *.runsettings text eol=lf 33 | 34 | # Other XML files 35 | *.xml text eol=lf 36 | *.svg text eol=lf 37 | 38 | # JSON files 39 | *.json text eol=lf 40 | 41 | # YAML files 42 | *.yml text eol=lf 43 | *.yaml text eol=lf 44 | 45 | # Shell scripts 46 | *.in text eol=lf diff=bash 47 | *.sh text eol=lf diff=bash 48 | 49 | # Windows batch files 50 | *.bat text eol=crlf 51 | *.BAT text eol=crlf 52 | *.cmd text eol=crlf 53 | *.CMD text eol=crlf 54 | 55 | # Markdown files 56 | *.md text eol=lf diff=markdown 57 | 58 | # InnoSetup files 59 | *.iss text eol=crlf 60 | 61 | # Image files 62 | *.jpg binary 63 | *.png binary 64 | *.gif binary 65 | 66 | # Document files 67 | *.pdf binary diff=astextplain 68 | *.PDF binary diff=astextplain 69 | *.rtf binary diff=astextplain 70 | *.RTF binary diff=astextplain 71 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file specifies users whose review is automatically requested when a PR modifies certain files. 2 | # For more ionformation see: 3 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 4 | 5 | # GitHub and apps configuration files 6 | /.github/ @rdeago 7 | /.all-contributorsrc @rdeago 8 | 9 | # Git configuration files 10 | /.git* @rdeago 11 | 12 | # Build scripts 13 | *.cake @rdeago 14 | 15 | # Licensing 16 | LICENSE @rdeago 17 | THIRD-PARTY-NOTICES @rdeago 18 | 19 | # Solution infrastructure files 20 | Directory.Build.* @rdeago 21 | .editorconfig @rdeago 22 | .globalconfig @rdeago 23 | stylecop.json @rdeago 24 | *.DotSettings @rdeago 25 | NuGet.config @rdeago 26 | version.json @rdeago 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: { interval: "daily" } 6 | labels: [ "area:deps", "area:ci" ] 7 | reviewers: [ "rdeago" ] 8 | - package-ecosystem: "nuget" 9 | directory: "/" 10 | schedule: { interval: "daily" } 11 | labels: [ "area:deps" ] 12 | reviewers: [ "rdeago" ] 13 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | 'area:code': 2 | - '*.sln' 3 | - 'src/**/*' 4 | 5 | 'area:style': 6 | - '**/.editorconfig' 7 | - '**/.globalconfig' 8 | - '**/stylecop.json' 9 | - '**/*.DotSettings' 10 | 11 | 'area:build': 12 | - '**/*.cake' 13 | - 'build/**/*' 14 | 15 | 'area:repo': 16 | - '.github/*.yml' 17 | - '.github/**/*.md' 18 | - CODEOWNERS 19 | - '.github/CODEOWNERS' 20 | 21 | 'area:ci': 22 | - '.github/workflows/**/*' 23 | - 'lgtm.yml' 24 | 25 | 'area:deps': 26 | - '**/Directory.Packages.props' 27 | - Directory.Build.props 28 | - Directory.Build.targets 29 | - global.json 30 | - .config/dotnet-tools.json 31 | 32 | 'area:docs': 33 | - 'docs/**/*' 34 | - '.all-contributorsrc' 35 | - '**/CHANGELOG.md' 36 | - '**/LICENSE' 37 | - '**/NuGet-README.md' 38 | - '**/README.md' 39 | - '**/THIRD-PARTY-NOTICES' 40 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore-for-release 5 | categories: 6 | - title: Breaking changes 7 | labels: 8 | - breaking 9 | - title: New features 10 | labels: 11 | - enhancement 12 | - title: Bugs fixed 13 | labels: 14 | - bug 15 | - title: Other changes 16 | labels: 17 | - "*" 18 | -------------------------------------------------------------------------------- /.github/workflows/build-test-pack.yml: -------------------------------------------------------------------------------- 1 | name: Build, test, and pack 2 | 3 | on: 4 | push: 5 | branches: [ main, 'v[0-9]+.[0-9]+' ] 6 | pull_request: 7 | branches: [ main, 'v[0-9]+.[0-9]+' ] 8 | 9 | jobs: 10 | build_test_pack: 11 | runs-on: windows-latest 12 | env: 13 | DOTNET_NOLOGO: 'true' 14 | DOTNET_CLI_TELEMETRY_OPTOUT: 'true' 15 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' 16 | DOTNET_CLI_UI_LANGUAGE: 'en-US' 17 | FEEDZ_IO_PRIVATE_TOKEN: ${{ secrets.FEEDZ_IO_PRIVATE_TOKEN }} 18 | steps: 19 | - name: Checkout repository with full history 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 # Checkout with full history so nbgv can compute Git height correctly. 23 | - name: Setup .NET SDK 24 | uses: actions/setup-dotnet@v3 25 | with: 26 | global-json-file: global.json 27 | - name: Restore .NET tools 28 | shell: cmd 29 | run: dotnet tool restore 30 | - name: Run build script 31 | shell: cmd 32 | run: | 33 | if [%CAKE_VERBOSITY%]==[] set CAKE_VERBOSITY=Normal 34 | if [%RUNNER_DEBUG%]==[1] set CAKE_VERBOSITY=Diagnostic 35 | dotnet cake --target Pack --verbosity %CAKE_VERBOSITY% 36 | - name: Upload coverage to Codecov 37 | uses: codecov/codecov-action@v3 38 | with: 39 | working-directory: ./TestResults/ 40 | files: Cobertura.xml 41 | verbose: true 42 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ main, 'v[0-9]+.[0-9]+' ] 6 | pull_request: 7 | branches: [ main, 'v[0-9]+.[0-9]+' ] 8 | schedule: 9 | - cron: '38 16 * * 6' # At 4:38PM, every Saturday 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | env: 16 | DOTNET_NOLOGO: 'true' 17 | DOTNET_CLI_TELEMETRY_OPTOUT: 'true' 18 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' 19 | DOTNET_CLI_UI_LANGUAGE: 'en-US' 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | language: [ 'csharp' ] # https://aka.ms/codeql-docs/language-support 28 | steps: 29 | - name: Checkout repository with full history 30 | uses: actions/checkout@v4 31 | with: 32 | fetch-depth: 0 # Checkout with full history so nbgv can compute Git height correctly. 33 | - name: Initialize CodeQL 34 | uses: github/codeql-action/init@v2 35 | with: 36 | languages: ${{ matrix.language }} 37 | queries: security-and-quality 38 | - name: Setup .NET SDK 39 | uses: actions/setup-dotnet@v3 40 | with: 41 | global-json-file: global.json 42 | - name: Restore .NET tools 43 | run: dotnet tool restore 44 | - name: Build solution 45 | run: | 46 | if test "$RUNNER_DEBUG" == "1"; then 47 | CAKE_VERBOSITY="Diagnostic" 48 | elif test -z "$CAKE_VERBOSITY"; then 49 | CAKE_VERBOSITY="Normal" 50 | fi 51 | dotnet cake --target Build --verbosity $CAKE_VERBOSITY 52 | - name: Perform CodeQL Analysis 53 | uses: github/codeql-action/analyze@v2 54 | with: 55 | category: "/language:${{matrix.language}}" 56 | -------------------------------------------------------------------------------- /.github/workflows/label-pull-requests.yml: -------------------------------------------------------------------------------- 1 | name: Set labels on PR 2 | on: 3 | pull_request_target: 4 | types: [ opened, synchronize, reopened ] 5 | 6 | jobs: 7 | 8 | set_labels: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: read 12 | pull-requests: write 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | - name: Assign labels to pull request 17 | uses: actions/labeler@v4 18 | with: 19 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 20 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish a release 2 | 3 | concurrency: 4 | group: release-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | inputs: 10 | versionSpecChange: 11 | description: 'Version spec change' 12 | required: true 13 | type: choice 14 | default: 'None' 15 | options: 16 | - None 17 | - Unstable 18 | - Stable 19 | - Minor 20 | - Major 21 | checkPublicApi: 22 | description: 'Check public API files' 23 | required: false 24 | default: true 25 | type: boolean 26 | forceUpdateChangelog: 27 | description: 'Update changelog on preview' 28 | required: false 29 | default: false 30 | type: boolean 31 | checkChangelog: 32 | description: 'Check changelog before update' 33 | required: false 34 | default: true 35 | type: boolean 36 | cakeVerbosity: 37 | description: 'Cake verbosity' 38 | required: true 39 | type: choice 40 | default: 'Normal' 41 | options: 42 | - Normal 43 | - Verbose 44 | - Diagnostic 45 | jobs: 46 | release: 47 | runs-on: windows-latest 48 | env: 49 | DOTNET_NOLOGO: 'true' 50 | DOTNET_CLI_TELEMETRY_OPTOUT: 'true' 51 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' 52 | DOTNET_CLI_UI_LANGUAGE: 'en-US' 53 | FEEDZ_IO_PRIVATE_TOKEN: ${{ secrets.FEEDZ_IO_PRIVATE_TOKEN }} 54 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 55 | 56 | # Deploy non-prerelease public packages on NuGet 57 | RELEASE_NUGET_SOURCE: 'https://api.nuget.org/v3/index.json' 58 | RELEASE_NUGET_KEY: ${{ secrets.NUGET_DEPLOYMENT_KEY }} 59 | # Deploy prerelease public packages on a public Feedz.io feed 60 | PRERELEASE_NUGET_SOURCE: 'https://f.feedz.io/tenacom/preview/nuget/index.json' 61 | PRERELEASE_NUGET_KEY: ${{ secrets.FEEDZ_IO_PRIVATE_TOKEN }} 62 | # Deploy all private packages on a private Feedz.io feed 63 | PRIVATE_NUGET_SOURCE: 'https://f.feedz.io/tenacom/private/nuget/index.json' 64 | PRIVATE_NUGET_KEY: ${{ secrets.FEEDZ_IO_PRIVATE_TOKEN }} 65 | 66 | VERSION_SPEC_CHANGE: ${{ inputs.versionSpecChange }} 67 | CHECK_PUBLIC_API: ${{ inputs.checkPublicApi }} 68 | FORCE_UPDATE_CHANGELOG: ${{ inputs.forceUpdateChangelog }} 69 | CHECK_CHANGELOG: ${{ inputs.checkChangelog }} 70 | CAKE_VERBOSITY: ${{ inputs.cakeVerbosity }} 71 | steps: 72 | - name: Log workflow inputs 73 | shell: cmd 74 | run: | 75 | echo Version spec change : %VERSION_SPEC_CHANGE% 76 | echo Check public API files : %CHECK_PUBLIC_API% 77 | echo Update changelog on preview : %FORCE_UPDATE_CHANGELOG% 78 | echo Check changelog before update : %CHECK_CHANGELOG% 79 | echo Cake verbosity : %CAKE_VERBOSITY% 80 | - name: Checkout repository with full history 81 | uses: actions/checkout@v4 82 | with: 83 | fetch-depth: 0 # Checkout with full history so nbgv can compute Git height correctly. 84 | token: ${{ secrets.RELEASE_TOKEN }} 85 | persist-credentials: true # We need auth set up in the Cake script 86 | - name: Setup .NET SDK 87 | uses: actions/setup-dotnet@v3 88 | with: 89 | global-json-file: global.json 90 | - name: Restore .NET tools 91 | shell: cmd 92 | run: dotnet tool restore 93 | - name: Run build script 94 | id: build 95 | shell: cmd 96 | run: | 97 | if [%CAKE_VERBOSITY%]==[] set CAKE_VERBOSITY=Normal 98 | if [%RUNNER_DEBUG%]==[1] set CAKE_VERBOSITY=Diagnostic 99 | dotnet cake --target Release --verbosity %CAKE_VERBOSITY% 100 | - name: Upload coverage to Codecov 101 | uses: codecov/codecov-action@v3 102 | with: 103 | working-directory: ./TestResults/ 104 | files: Cobertura.xml 105 | name: v${{ steps.build.outputs.version }} 106 | verbose: true 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build artifacts 2 | artifacts/ 3 | 4 | # Local build logs 5 | logs/ 6 | 7 | # Cake build 8 | tools/ 9 | 10 | # Testing 11 | TestResults/ 12 | 13 | # Visual Studio 14 | **/bin/ 15 | **/obj/ 16 | **/.vs/ 17 | *.csproj.user 18 | *.pubxml.user 19 | 20 | # ReSharper 21 | *.DotSettings.user 22 | _ReSharper.*/ 23 | 24 | # Windows thumbnails 25 | Thumbs.db 26 | 27 | # DocFx 28 | docs/globalMetadata.json 29 | docs/api/.manifest 30 | docs/api/*.yml 31 | docs/obj/ 32 | docs/_site/ 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to PolyKit will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## Unreleased changes 9 | 10 | ### New features 11 | 12 | ### Changes to existing features 13 | 14 | ### Bugs fixed in this release 15 | 16 | ### Known problems introduced by this release 17 | 18 | ## [3.0.9](https://github.com/Tenacom/PolyKit/releases/tag/3.0.9) (2023-11-26) 19 | 20 | This release updates some dependencies to their post-.NET 8.0 versions. No other modifications were made. 21 | 22 | ## [3.0.4](https://github.com/Tenacom/PolyKit/releases/tag/3.0.4) (2023-11-20) 23 | 24 | ### New features 25 | 26 | - .NET 8 was added as a target platform. 27 | - All polyfills were updated with modifications (if any) made to BCL types up to the release of .NET 8.0.0. 28 | - The polyfill for [`ExperimentalAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute) has been added; however, this attribute is only polyfilled by PolyKit.Embedded when compiling with .NET SDK 8.0. This avoids giving the user the false impression that the attribute is supported, when the compiler doesn't actually support it. 29 | - [`DateOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.dateonly) and [`TimeOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.timeonly) polyfills now support [`deconstruction`](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct). 30 | 31 | ### Changes to existing features 32 | 33 | - **BREAKING CHANGE:** Extension classes that were previously in `PolyKit.*` namespaces have been moved to `System.*` namespaces, in order for their members to be more easily discoverable (e.g. by Intellisense) and usable without additional `using` statements. 34 | This change may seem to go against best practices, as it places PolyKit types in namespaces usually reserved for the BCL; however, it makes sense if you consider that one of the purposes of polyfills is to minimize the amount of code changes necessary to backport code. 35 | Affected extension classes include: 36 | - `PolyKitEnumerable`, moved from `PolyKit.Linq` to `System.Linq`; 37 | - `PolyKitExceptionExtensions`, moved from `PolyKit.Diagnostics` to `System`; 38 | - `PolyKitStackTraceExtensions`, moved from `PolyKit.Diagnostics` to `System.Diagnostics`. 39 | 40 | ## [2.0.30](https://github.com/Tenacom/PolyKit/releases/tag/2.0.30) (2022-11-24) 41 | 42 | ### Bugs fixed in this release 43 | 44 | - The polyfill for [`DateOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.dateonly) could generate a `CS8602` warning (possible dereference of a null reference). 45 | - The polyfill for [`TimeOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.timeonly), when compiled without span support, generated two `CS1503` errors because of a missing preprocessor conditional. 46 | 47 | ## [2.0.26](https://github.com/Tenacom/PolyKit/releases/tag/2.0.26) (2022-11-24) 48 | 49 | ### Bugs fixed in this release 50 | 51 | - The polyfills for [`DateOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.dateonly) and [`TimeOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.timeonly) only worked when either the target platform supported spans, or the [`System.Memory`](https://www.nuget.org/packages/System.Memory) package was referenced. 52 | 53 | ## [2.0.24](https://github.com/Tenacom/PolyKit/releases/tag/2.0.24) (2022-11-23) 54 | 55 | ### New features 56 | 57 | - .NET 7 was added as a target platform. 58 | - Features that were introduced with .NET 7 are not polyfilled by PolyKit.Embedded when compiling with .NET SDK 6.0. This avoids giving the user the false impression that, for example, `UnscopedRefAttribute` is supported, when the compiler doesn't actually support it. 59 | - PolyKit now provides a quasi-polyfill for [`Enumerable.TryGetNonEnumeratedCount`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.trygetnonenumeratedcount). Since extending the `Enumerable` class is not possible, PolyKit adds (in the `PolyKit.Linq` namespace) a `TryGetCountWithoutEnumerating` extension method that calls `TryGetNonEnumeratedCount` on .NET6.0+ and polyfills as much functionality as possible on older frameworks. 60 | - Polyfills for the following features were added: 61 | - [required members](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members); 62 | - [`scoped` modifier](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/low-level-struct-improvements) (including the `UnscopedRef` attribute); 63 | - [`AsyncMethodBuilder` attribute](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#asyncmethodbuilder-attribute); 64 | - [`ModuleInitializer` attribute](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#moduleinitializer-attribute); 65 | - [trimming incompatibility attributes](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming#resolve-trim-warnings); 66 | - [`UnconditionalSuppressMessage` attribute](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming#unconditionalsuppressmessage); 67 | - [`CompilerFeatureRequired` attribute](https://github.com/dotnet/runtime/issues/66167); 68 | - [`RequiresPreviewFeatures` attribute](https://github.com/dotnet/designs/blob/main/accepted/2021/preview-features/preview-features.md); 69 | - [`UnmanagedCallersOnly` attribute](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers#systemruntimeinteropservicesunmanagedcallersonlyattribute); 70 | - [`ConstantExpected` attribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.constantexpectedattribute); 71 | - [`StringSyntax` attribute](https://github.com/dotnet/runtime/issues/62505); 72 | - [`ISpanFormattable` interface](https://learn.microsoft.com/en-us/dotnet/api/system.ispanformattable) (note that the polyfill does NOT add `ISpanFormattable` support to .NET Runtime types); 73 | - [`DateOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.dateonly) and [`TimeOnly`](https://learn.microsoft.com/en-us/dotnet/api/system.timeonly) structs (not that the polyfills do NOT implement [`IParsable`](https://learn.microsoft.com/en-us/dotnet/api/system.iparsable) and [`ISpanParsable`](https://learn.microsoft.com/en-us/dotnet/api/system.ispanparsable-1), although the methods are there and can be used as public methods of the individual types). 74 | 75 | ### Changes to existing features 76 | 77 | - **BREAKING CHANGE:** Following .NET's [Library support for older frameworks](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/7.0/old-framework-support) policy, support for .NET Core 3.1 has been removed. 78 | - All types provideed by PolyKit are now flagged with the necessary attributes to be ignored by code analyzers, debuggers, code coverage tools, code metrics, etc. See [this blog post](https://riccar.do/posts/2022/2022-05-30-well-behaved-guest-code.html) for more information about the attributes added to types and the rationale behind each of them. 79 | 80 | ## [1.0.16](https://github.com/Tenacom/PolyKit/releases/tag/1.0.16) (2022-11-01) 81 | 82 | Initial release. 83 | -------------------------------------------------------------------------------- /Common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PolyKit 6 | Tenacom and contributors 7 | Tenacom 8 | Tenacom 9 | Copyright (c) $(Authors) 10 | 11 | false 12 | https://github.com/Tenacom/PolyKit 13 | See $(PackageProjectUrl)/blob/main/CHANGELOG.md 14 | https://github.com/Tenacom/PolyKit 15 | true 16 | true 17 | true 18 | true 19 | false 20 | 21 | 22 | 23 | 24 | latest 25 | false 26 | true 27 | enable 28 | true 29 | true 30 | false 31 | true 32 | false 33 | true 34 | false 35 | 36 | 37 | 38 | 39 | false 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Tenacom and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NuGet-README.md: -------------------------------------------------------------------------------- 1 | # ![PolyKit - C# polyfills, your way](https://raw.githubusercontent.com/Tenacom/PolyKit/main/graphics/Readme.png) 2 | 3 | --- 4 | 5 | PolyKit is both a run-time library (provided via the [`PolyKit`](https://nuget.org/packages/PolyKit) NuGet package) and a set of ready-to-compile source files (provided via the [`PolyKit.Embedded`](https://nuget.org/packages/PolyKit.Embedded) NuGet package) that add support for latest C# features as well as recent additions to the .NET runtime library, even in projects targeting .NET Framework or .NET Standard 2.0. 6 | 7 | Want to know more? [Here's the complete README.](https://github.com/Tenacom/PolyKit#readme) 8 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /PolyKit.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32526.322 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "- Configuration", "- Configuration", "{ED7AE9DE-0190-495E-BAB8-91D7916DE79B}" 7 | ProjectSection(SolutionItems) = preProject 8 | .editorconfig = .editorconfig 9 | .globalconfig = .globalconfig 10 | Common.props = Common.props 11 | NuGet.config = NuGet.config 12 | stylecop.json = stylecop.json 13 | version.json = version.json 14 | EndProjectSection 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "- Documentation", "- Documentation", "{0661C764-ED18-47F2-8A94-8193D0652E8A}" 17 | ProjectSection(SolutionItems) = preProject 18 | CHANGELOG.md = CHANGELOG.md 19 | LICENSE = LICENSE 20 | NuGet-README.md = NuGet-README.md 21 | README.md = README.md 22 | THIRD-PARTY-NOTICES = THIRD-PARTY-NOTICES 23 | EndProjectSection 24 | EndProject 25 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04BEFF7A-9805-4109-983D-F1832FC44532}" 26 | EndProject 27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolyKit", "src\PolyKit\PolyKit.csproj", "{9A8C068C-0751-4E2B-ABEB-D3E3C9DD1FB4}" 28 | EndProject 29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolyKit.Embedded", "src\PolyKit.Embedded\PolyKit.Embedded.csproj", "{CAB8EAA2-8652-4993-ACA5-6693CE4D4A26}" 30 | EndProject 31 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolyKit.Polyfills", "src\PolyKit.Polyfills\PolyKit.Polyfills.csproj", "{A977FFFD-8B8C-4AAC-9176-8976960DE5C4}" 32 | EndProject 33 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolyKit.Generator", "src\PolyKit.Generator\PolyKit.Generator.csproj", "{9CE09A81-98CF-4CC2-B5FE-8159AA933F36}" 34 | EndProject 35 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "- Dependencies", "- Dependencies", "{8474FA20-638B-49BB-BF75-AAFC78B60750}" 36 | ProjectSection(SolutionItems) = preProject 37 | Directory.Packages.props = Directory.Packages.props 38 | .config\dotnet-tools.json = .config\dotnet-tools.json 39 | global.json = global.json 40 | EndProjectSection 41 | EndProject 42 | Global 43 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 44 | Debug|Any CPU = Debug|Any CPU 45 | Release|Any CPU = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 48 | {9A8C068C-0751-4E2B-ABEB-D3E3C9DD1FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {9A8C068C-0751-4E2B-ABEB-D3E3C9DD1FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {9A8C068C-0751-4E2B-ABEB-D3E3C9DD1FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {9A8C068C-0751-4E2B-ABEB-D3E3C9DD1FB4}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {CAB8EAA2-8652-4993-ACA5-6693CE4D4A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {CAB8EAA2-8652-4993-ACA5-6693CE4D4A26}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {CAB8EAA2-8652-4993-ACA5-6693CE4D4A26}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {CAB8EAA2-8652-4993-ACA5-6693CE4D4A26}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {A977FFFD-8B8C-4AAC-9176-8976960DE5C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {A977FFFD-8B8C-4AAC-9176-8976960DE5C4}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {A977FFFD-8B8C-4AAC-9176-8976960DE5C4}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {A977FFFD-8B8C-4AAC-9176-8976960DE5C4}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {9CE09A81-98CF-4CC2-B5FE-8159AA933F36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {9CE09A81-98CF-4CC2-B5FE-8159AA933F36}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {9CE09A81-98CF-4CC2-B5FE-8159AA933F36}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {9CE09A81-98CF-4CC2-B5FE-8159AA933F36}.Release|Any CPU.Build.0 = Release|Any CPU 64 | EndGlobalSection 65 | GlobalSection(SolutionProperties) = preSolution 66 | HideSolutionNode = FALSE 67 | EndGlobalSection 68 | GlobalSection(NestedProjects) = preSolution 69 | {9A8C068C-0751-4E2B-ABEB-D3E3C9DD1FB4} = {04BEFF7A-9805-4109-983D-F1832FC44532} 70 | {CAB8EAA2-8652-4993-ACA5-6693CE4D4A26} = {04BEFF7A-9805-4109-983D-F1832FC44532} 71 | {A977FFFD-8B8C-4AAC-9176-8976960DE5C4} = {04BEFF7A-9805-4109-983D-F1832FC44532} 72 | {9CE09A81-98CF-4CC2-B5FE-8159AA933F36} = {04BEFF7A-9805-4109-983D-F1832FC44532} 73 | EndGlobalSection 74 | GlobalSection(ExtensibilityGlobals) = postSolution 75 | SolutionGuid = {C9053E59-317D-43DC-A16B-6E45E036C77E} 76 | EndGlobalSection 77 | EndGlobal 78 | -------------------------------------------------------------------------------- /build/DocFx.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #tool nuget:?package=docfx.console&version=2.59.4 5 | 6 | #nullable enable 7 | 8 | // --------------------------------------------------------------------------------------------- 9 | // DocFx class 10 | // --------------------------------------------------------------------------------------------- 11 | 12 | using System; 13 | using System.Runtime.InteropServices; 14 | 15 | /* 16 | * Summary : Implements DocFx operations 17 | */ 18 | sealed class DocFx 19 | { 20 | private const string ToolExeName = "docfx.exe"; 21 | 22 | private readonly DirectoryPath _docsPath; 23 | private FilePath? _docFxPath; 24 | 25 | /* 26 | * Summary : Initializes a new instance of the DocFx class. 27 | * Params : context - The Cake context. 28 | * docsPath - The path to the folder where DocFX operates. 29 | */ 30 | public DocFx(ICakeContext context, BuildData buildData, DirectoryPath docsPath) 31 | { 32 | Context = context; 33 | BuildData = buildData; 34 | _docsPath = docsPath; 35 | } 36 | 37 | private ICakeContext Context { get; } 38 | 39 | private BuildData BuildData { get; } 40 | 41 | /* 42 | * Summary : Extracts language metadata according to docfx.json settings. 43 | */ 44 | public void Metadata() 45 | { 46 | var docFxJsonPath = _docsPath.CombineWithFilePath("docfx.json"); 47 | var json = LoadJsonObject(docFxJsonPath); 48 | if (!json.TryGetPropertyValue("metadata", out _)) 49 | { 50 | Context.Information("No metadata to generate."); 51 | return; 52 | } 53 | 54 | Context.Information("Running DocFx..."); 55 | Run("metadata"); 56 | } 57 | 58 | /* 59 | * Summary : Generates documentation according to docfx.json settings. 60 | */ 61 | public void Build() 62 | { 63 | Context.Information("Running DocFx..."); 64 | Run("build"); 65 | } 66 | 67 | /* 68 | * Summary : Hosts the built documentation web site. 69 | */ 70 | public void Serve() 71 | { 72 | if (BuildData.IsCI) 73 | { 74 | Context.Information("DocFX web server not suitable for cloud builds, skipping."); 75 | return; 76 | } 77 | 78 | Context.Information("Starting DocFX web server..."); 79 | var (_, process) = Start("serve _site"); 80 | Console.WriteLine("Press any key to stop serving..."); 81 | _ = WaitForKey(); 82 | Context.Information("Stopping DocFX web server..."); 83 | process.Kill(); 84 | process.WaitForExit(); 85 | } 86 | 87 | private static ConsoleKeyInfo WaitForKey() 88 | { 89 | while (Console.KeyAvailable) 90 | { 91 | _ = Console.ReadKey(true); 92 | } 93 | 94 | return Console.ReadKey(true); 95 | } 96 | 97 | private void Run(ProcessArgumentBuilder arguments) 98 | { 99 | var (commandName, process) = Start(arguments); 100 | process.WaitForExit(); 101 | var exitCode = process.GetExitCode(); 102 | Context.Ensure(exitCode == 0, $"{commandName} exited with code {exitCode}."); 103 | } 104 | 105 | private (string commandName, IProcess Process) Start(ProcessArgumentBuilder arguments) 106 | { 107 | _docFxPath ??= Context.Tools.Resolve(ToolExeName); 108 | Context.Ensure(_docFxPath != null, $"Cannot find {ToolExeName}"); 109 | FilePath command = _docFxPath; 110 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 111 | { 112 | command = "mono"; 113 | arguments = arguments.PrependQuoted(_docFxPath.FullPath); 114 | } 115 | 116 | var process = Context.StartAndReturnProcess(command, new ProcessSettings() 117 | { 118 | Arguments = arguments, 119 | WorkingDirectory = _docsPath, 120 | }); 121 | 122 | return (command.GetFilenameWithoutExtension().ToString(), process); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /build/THIRD-PARTY-NOTICES: -------------------------------------------------------------------------------- 1 | These scripts may use and/or incorporate third-party libraries or other resources 2 | that may be distributed under licenses different than this project. 3 | 4 | In the event that we accidentally failed to list a required notice, please 5 | bring it to our attention. Either post an issue, or email us: 6 | 7 | info@tenacom.it 8 | 9 | The attached notices are provided for information only. 10 | 11 | ================================================================================================ 12 | Humanizer - https://github.com/Humanizr/Humanizer 13 | ------------------------------------------------------------------------------------------------ 14 | The MIT License (MIT) 15 | 16 | Copyright (c) .NET Foundation and Contributors 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy 19 | of this software and associated documentation files (the "Software"), to deal 20 | in the Software without restriction, including without limitation the rights 21 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | copies of the Software, and to permit persons to whom the Software is 23 | furnished to do so, subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in 26 | all copies or substantial portions of the Software. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 31 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 33 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 34 | THE SOFTWARE. 35 | -------------------------------------------------------------------------------- /build/dotnet.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // .NET SDK helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.IO; 11 | using System.Linq; 12 | 13 | using SysDirectory = System.IO.Directory; 14 | using SysPath = System.IO.Path; 15 | 16 | /* 17 | * Summary : Restore all NuGet packages for the solution. 18 | * Params : context - The Cake context. 19 | * data - Build configuration data. 20 | */ 21 | static void RestoreSolution(this ICakeContext context, BuildData data) 22 | { 23 | context.Information("Restoring NuGet packages for solution..."); 24 | context.DotNetRestore(data.SolutionPath.FullPath, new() { 25 | MSBuildSettings = data.MSBuildSettings, 26 | DisableParallel = true, 27 | Interactive = false, 28 | }); 29 | } 30 | 31 | /* 32 | * Summary : Build all projects in the solution. 33 | * Params : context - The Cake context. 34 | * data - Build configuration data. 35 | * restore - true to restore NuGet packages before building, false otherwise. 36 | */ 37 | static void BuildSolution(this ICakeContext context, BuildData data, bool restore) 38 | { 39 | context.Information($"Building solution (restore = {restore})..."); 40 | context.DotNetBuild(data.SolutionPath.FullPath, new() { 41 | Configuration = data.Configuration, 42 | MSBuildSettings = data.MSBuildSettings, 43 | NoLogo = true, 44 | NoRestore = !restore, 45 | }); 46 | } 47 | 48 | /* 49 | * Summary : Run all unit tests for the solution. 50 | * Params : context - The Cake context. 51 | * data - Build configuration data. 52 | * restore - true to restore NuGet packages before testing, false otherwise. 53 | * build - true to build the solution before testing, false otherwise. 54 | * collect - true to collect coverage data with Coverlet 55 | * Remarks : If successful, this method will merge all coverage reports generated by VSTest 56 | * into a single file suitable for upload to Codecov. 57 | */ 58 | static void TestSolution(this ICakeContext context, BuildData data, bool restore, bool build, bool collect) 59 | { 60 | context.Information($"Running tests (restore = {restore}, build = {build}, collect = {collect})..."); 61 | context.DotNetTest(data.SolutionPath.FullPath, new() { 62 | Configuration = data.Configuration, 63 | MSBuildSettings = data.MSBuildSettings, 64 | NoBuild = !build, 65 | NoLogo = true, 66 | NoRestore = !restore, 67 | ArgumentCustomization = args => collect 68 | ? args.Append("--collect:\"XPlat Code Coverage\"") 69 | : args, 70 | }); 71 | 72 | // Merge coverage reports only if there are any 73 | if (collect) 74 | { 75 | if (!context.FileSystem.Exist(data.TestResultsPath) || !context.GetSubDirectories(data.TestResultsPath).Any()) 76 | { 77 | context.Information("No coverage reports were generated."); 78 | } 79 | else 80 | { 81 | context.Information("Merging coverage reports..."); 82 | const string CoverageDataFileName = "coverage.cobertura.xml"; 83 | var coverageDataGlob = SysPath.Combine(data.TestResultsPath.FullPath, "*", CoverageDataFileName); 84 | context.DotNetTool($"reportgenerator \"-reports:{coverageDataGlob}\" \"-targetDir:{data.TestResultsPath.FullPath}\" -reporttypes:Cobertura"); 85 | } 86 | } 87 | } 88 | 89 | /* 90 | * Summary : Run the Pack target on the solution. This usually produces NuGet packages, 91 | * but Buildvana SDK may hijack the target to produce, for example, setup executables. 92 | * Params : context - The Cake context. 93 | * data - Build configuration data. 94 | * restore - true to restore NuGet packages before packing, false otherwise. 95 | * build - true to build the solution before packing, false otherwise. 96 | */ 97 | static void PackSolution(this ICakeContext context, BuildData data, bool restore, bool build) 98 | { 99 | context.Information($"Packing solution (restore = {restore}, build = {build})..."); 100 | context.DotNetPack(data.SolutionPath.FullPath, new() { 101 | Configuration = data.Configuration, 102 | MSBuildSettings = data.MSBuildSettings, 103 | NoBuild = !build, 104 | NoLogo = true, 105 | NoRestore = !restore, 106 | }); 107 | } 108 | 109 | /* 110 | * Summary : Asynchronously pushes all produced NuGet packages to the appropriate NuGet server. 111 | * Params : context - The Cake context. 112 | * data - Build configuration data. 113 | * Remarks : - This method uses the following environment variables: 114 | * * PRERELEASE_NUGET_SOURCE - NuGet source URL where to push prerelease packages 115 | * * RELEASE_NUGET_SOURCE - NuGet source URL where to push non-prerelease packages 116 | * * PRERELEASE_NUGET_KEY - API key for PRERELEASE_NUGET_SOURCE 117 | * * RELEASE_NUGET_KEY - API key for RELEASE_NUGET_SOURCE 118 | * - If there are no .nupkg files in the designated artifacts directory, this method does nothing. 119 | */ 120 | static async Task NuGetPushAllAsync(this ICakeContext context, BuildData data) 121 | { 122 | const string nupkgMask = "*.nupkg"; 123 | if (!SysDirectory.EnumerateFiles(data.ArtifactsPath.FullPath, nupkgMask).Any()) 124 | { 125 | context.Verbose("No .nupkg files to push."); 126 | return; 127 | } 128 | 129 | var isPrivate = await context.IsPrivateRepositoryAsync(data); 130 | var nugetSource = context.GetOptionOrFail(isPrivate ? "privateNugetSource" : data.IsPrerelease ? "prereleaseNugetSource" : "releaseNugetSource"); 131 | var nugetApiKey = context.GetOptionOrFail(isPrivate ? "privateNugetKey" : data.IsPrerelease ? "prereleaseNugetKey" : "releaseNugetKey"); 132 | var nugetPushSettings = new DotNetNuGetPushSettings { 133 | ForceEnglishOutput = true, 134 | Source = nugetSource, 135 | ApiKey = nugetApiKey, 136 | SkipDuplicate = true, 137 | }; 138 | 139 | var packages = SysPath.Combine(data.ArtifactsPath.FullPath, nupkgMask); 140 | foreach (var path in context.GetFiles(packages)) 141 | { 142 | context.Information($"Pushing {path} to {nugetSource}..."); 143 | context.DotNetNuGetPush(path, nugetPushSettings); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /build/environment.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Environment helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | /* 11 | * Summary : Gets a string from the environment, failing if the value is not found or is the empty string. 12 | * Params : context - The Cake context. 13 | * name - The name of the environment variable to read. 14 | * fallbackName - The name of another environment variable to read if name is not found or its value is the empty string. 15 | * Returns : The value of an environment variable. 16 | */ 17 | static string GetEnvironmentString(this ICakeContext context, string name, string fallbackName = "") 18 | { 19 | var result = context.EnvironmentVariable(name, string.Empty); 20 | if (!string.IsNullOrEmpty(result)) 21 | { 22 | return result; 23 | } 24 | 25 | context.Ensure(!string.IsNullOrEmpty(fallbackName), $"Environment variable {name} is missing or has an empty value."); 26 | result = context.EnvironmentVariable(fallbackName, string.Empty); 27 | context.Ensure(!string.IsNullOrEmpty(result), 255, $"Both environment variables {name} and {fallbackName} are missing or have an empty value."); 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /build/fail.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Build failure helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.Diagnostics.CodeAnalysis; 11 | 12 | /* 13 | * Summary : Fails the build with the specified message. 14 | * This method does not return. 15 | * Params : context - The Cake context. 16 | * message - A message explaining the reason for failing the build. 17 | */ 18 | [DoesNotReturn] 19 | static void Fail(this ICakeContext context, string message) 20 | { 21 | context.Error(message); 22 | throw new CakeException(message); 23 | } 24 | 25 | /* 26 | * Summary : Fails the build with the specified message. 27 | * This method does not return. 28 | * Type : T - The expected return type. 29 | * Params : context - The Cake context. 30 | * message - A message explaining the reason for failing the build. 31 | * Returns : This method never returns. 32 | */ 33 | [DoesNotReturn] 34 | static T Fail(this ICakeContext context, string message) 35 | { 36 | context.Error(message); 37 | throw new CakeException(message); 38 | } 39 | 40 | /* 41 | * Summary : Fails the build with the specified exit code and message. 42 | * This method does not return. 43 | * Params : context - The Cake context. 44 | * exitCode - The Cake exit code. 45 | * message - A message explaining the reason for failing the build. 46 | */ 47 | [DoesNotReturn] 48 | static void Fail(this ICakeContext context, int exitCode, string message) 49 | { 50 | context.Error(message); 51 | throw new CakeException(exitCode, message); 52 | } 53 | 54 | /* 55 | * Summary : Fails the build with the specified exit code and message. 56 | * This method does not return. 57 | * Type : T - The expected return type. 58 | * Params : context - The Cake context. 59 | * exitCode - The Cake exit code. 60 | * message - A message explaining the reason for failing the build. 61 | * Returns : This method never returns. 62 | */ 63 | [DoesNotReturn] 64 | static T Fail(this ICakeContext context, int exitCode, string message) 65 | { 66 | context.Error(message); 67 | throw new CakeException(exitCode, message); 68 | } 69 | 70 | /* 71 | * Summary : Fails the build with the specified message if a condition is not verified. 72 | * Params : context - The Cake context. 73 | * condition - The condition to verify. 74 | * message - A message explaining the reason for failing the build. 75 | */ 76 | static void Ensure(this ICakeContext context, [DoesNotReturnIf(false)] bool condition, string message) 77 | { 78 | if (!condition) 79 | { 80 | context.Error(message); 81 | throw new CakeException(message); 82 | } 83 | } 84 | 85 | /* 86 | * Summary : Fails the build with the specified message if a condition is not verified. 87 | * Params : context - The Cake context. 88 | * condition - The condition to verify. 89 | * exitCode - The Cake exit code. 90 | * message - A message explaining the reason for failing the build. 91 | */ 92 | static void Ensure(this ICakeContext context, [DoesNotReturnIf(false)] bool condition, int exitCode, string message) 93 | { 94 | if (!condition) 95 | { 96 | context.Error(message); 97 | throw new CakeException(exitCode, message); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /build/filesystem.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // File system helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | /* 11 | * Summary : Delete a directory, including its contents, if it exists. 12 | * Params : context - The Cake context. 13 | * directory - The directory to delete. 14 | */ 15 | static void DeleteDirectoryIfExists(this ICakeContext context, DirectoryPath directory) 16 | { 17 | if (!context.DirectoryExists(directory)) 18 | { 19 | context.Verbose($"Skipping non-existent directory: {directory}"); 20 | return; 21 | } 22 | 23 | context.Information($"Deleting directory: {directory}"); 24 | context.DeleteDirectory(directory, new() { Force = false, Recursive = true }); 25 | } 26 | -------------------------------------------------------------------------------- /build/git.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Git repository helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System; 11 | using System.Linq; 12 | 13 | /* 14 | * Summary : Gets the name of the current Git branch. 15 | * Params : context - The Cake context. 16 | * Returns : If HEAD is on a branch, the name of the branch; otherwise, the empty string. 17 | */ 18 | static string GetCurrentGitBranch(this ICakeContext context) => context.Exec("git", "branch --show-current").FirstOrDefault(string.Empty); 19 | 20 | /* 21 | * Summary : Attempts to get information about the remote repository. 22 | * Params : context - The Cake context. 23 | * Returns : Remote - The Git remote name. 24 | * HostUrl - The base URL of the Git repository host. 25 | * Owner - The repository owner. 26 | * Name - The repository name. 27 | * Remarks : - If the githubRepository argument is given, or the GITHUB_REPOSITORY environment variable is set 28 | * (as it happens in GitHub Actions,) Owner and Name are taken from there, while Remote is set 29 | * to the first Git remote found whose fetch URL matches them. 30 | * - If GITHUB_REPOSITORY is not available, Git remote fetch URLs are parsed for Owner and Name; 31 | * remotes "upstream" and "origin" are tested, in that order, in case "origin" is a fork. 32 | */ 33 | static bool TryGetRepositoryInfo(this ICakeContext context, out (string Remote, string HostUrl, string Owner, string Name) result) 34 | { 35 | return TryGetRepositoryInfoFromGitHubActions(out result) 36 | || TryGetRepositoryInfoFromGitRemote("upstream", out result) 37 | || TryGetRepositoryInfoFromGitRemote("origin", out result); 38 | 39 | bool TryGetRepositoryInfoFromGitHubActions(out (string Remote, string HostUrl, string Owner, string Name) result) 40 | { 41 | var repository = context.GetOption("githubRepository", string.Empty); 42 | if (string.IsNullOrEmpty(repository)) 43 | { 44 | result = default; 45 | return false; 46 | } 47 | 48 | var hostUrl = context.GetOptionOrFail("githubServerUrl"); 49 | var segments = repository.Split('/'); 50 | foreach (var remote in context.Exec("git", "remote")) 51 | { 52 | if (TryGetRepositoryInfoFromGitRemote(remote, out result) 53 | && string.Equals(result.HostUrl, hostUrl, StringComparison.Ordinal) 54 | && string.Equals(result.Owner, segments[0], StringComparison.Ordinal) 55 | && string.Equals(result.Name, segments[1], StringComparison.Ordinal)) 56 | { 57 | return true; 58 | } 59 | } 60 | 61 | result = default; 62 | return false; 63 | } 64 | 65 | bool TryGetRepositoryInfoFromGitRemote(string remote, out (string Remote, string HostUrl, string Owner, string Name) result) 66 | { 67 | if (context.Exec("git", "remote get-url " + remote, out var output) != 0) 68 | { 69 | result = default; 70 | return false; 71 | } 72 | 73 | var url = output.FirstOrDefault(); 74 | if (string.IsNullOrEmpty(url)) 75 | { 76 | result = default; 77 | return false; 78 | } 79 | 80 | Uri uri; 81 | try 82 | { 83 | uri = new Uri(url); 84 | } 85 | catch (UriFormatException) 86 | { 87 | result = default; 88 | return false; 89 | } 90 | 91 | var path = uri.AbsolutePath; 92 | path = path.EndsWith(".git", StringComparison.Ordinal) 93 | ? path.Substring(1, path.Length - 5) 94 | : path.Substring(1); 95 | 96 | var segments = path.Split('/'); 97 | if (segments.Length != 2) 98 | { 99 | result = default; 100 | return false; 101 | } 102 | 103 | result = (remote, $"{uri.Scheme}://{uri.Host}{(uri.IsDefaultPort ? null : ":" + uri.Port.ToString())}", segments[0], segments[1]); 104 | return true; 105 | } 106 | } 107 | 108 | /* 109 | * Summary : Tells whether a tag exists in the local Git repository. 110 | * Params : context - The Cake context. 111 | * tag - The tag to check for. 112 | * Returns : True if the tag exists; false otherwise. 113 | */ 114 | static bool GitTagExists(this ICakeContext context, string tag) => context.Exec("git", "tag").Any(s => string.Equals(tag, s, StringComparison.Ordinal)); 115 | 116 | /* 117 | * Summary : Gets the latest version and the latest stable version in commit history. 118 | * Params : context - The Cake context. 119 | * Returns : A tuple of the latest version and the latest stable version; 120 | * Remarks : - If no version tag is found in commit history, this method returns a tuple of two nulls. 121 | * - If no stable version tag is found in commit history, this method returns a tuple of the latest version and null. 122 | */ 123 | static (SemanticVersion? Latest, SemanticVersion? LatestStable) GitGetLatestVersions(this ICakeContext context) 124 | { 125 | context.Verbose("Looking for latest stable version tag in Git commit history..."); 126 | var output = context.Exec("git", "log --pretty=format:%D"); 127 | var versions = output.Where(static x => !string.IsNullOrEmpty(x)) 128 | .SelectMany(static x => x.Split(", ")) 129 | .Where(static x => x.StartsWith("tag: ")) 130 | .Select(static x => x.Substring(5)) 131 | .Select(static x => { 132 | _ = SemanticVersion.TryParse(x, out var version); 133 | return version; 134 | }) 135 | .WhereNotNull(); 136 | 137 | SemanticVersion? latest = null; 138 | SemanticVersion? latestStable = null; 139 | foreach (var version in versions) 140 | { 141 | if (latest == null) 142 | { 143 | latest = version; 144 | } 145 | 146 | if (!version.IsPrerelease) 147 | { 148 | latestStable = version; 149 | break; 150 | } 151 | } 152 | 153 | return (latest, latestStable); 154 | } 155 | 156 | /* 157 | * Summary : Sets Git user name and email. 158 | * Params : context - The Cake context. 159 | * name - The name of the user. 160 | * email - The email address of the user. 161 | */ 162 | static void GitSetUserIdentity(this ICakeContext context, string name, string email) 163 | { 164 | context.Information($"Setting Git user name to '{name}'..."); 165 | _ = context.Exec( 166 | "git", 167 | new ProcessArgumentBuilder() 168 | .Append("config") 169 | .Append("user.name") 170 | .AppendQuoted(name)); 171 | 172 | context.Information($"Setting Git user email to '{email}'..."); 173 | _ = context.Exec( 174 | "git", 175 | new ProcessArgumentBuilder() 176 | .Append("config") 177 | .Append("user.email") 178 | .AppendQuoted(email)); 179 | } 180 | -------------------------------------------------------------------------------- /build/json.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // JSON helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.Text.Encodings.Web; 11 | using System.Text.Json; 12 | using System.Text.Json.Nodes; 13 | 14 | using SysFile = System.IO.File; 15 | 16 | /* 17 | * Summary : Parses a JSON object from a string. Fails the build if not successful. 18 | * Params : context - The Cake context. 19 | * str - The string to parse. 20 | * description - A description of the string for exception messages. 21 | * Returns : The parsed object. 22 | */ 23 | static JsonObject ParseJsonObject(this ICakeContext context, string str, string description = "The provided string") 24 | { 25 | JsonNode? node; 26 | try 27 | { 28 | node = JsonNode.Parse( 29 | str, 30 | new JsonNodeOptions { PropertyNameCaseInsensitive = false }, 31 | new JsonDocumentOptions 32 | { 33 | AllowTrailingCommas = true, 34 | CommentHandling = JsonCommentHandling.Skip, 35 | }); 36 | } 37 | catch (JsonException) 38 | { 39 | context.Fail($"{description} is not valid JSON."); 40 | throw null; 41 | } 42 | 43 | return node switch { 44 | null => context.Fail($"{description} was parsed as JSON null."), 45 | JsonObject obj => obj, 46 | object other => context.Fail($"{description} was parsed as a {other.GetType().Name}, not a {nameof(JsonObject)}."), 47 | }; 48 | } 49 | 50 | /* 51 | * Summary : Loads a JSON object from a file. Fails the build if not successful. 52 | * Params : context - The Cake context. 53 | * path - The path of the file to parse. 54 | * Returns : The parsed object. 55 | */ 56 | static JsonObject LoadJsonObject(this ICakeContext context, FilePath path) 57 | { 58 | var fullPath = path.FullPath; 59 | JsonNode? node; 60 | try 61 | { 62 | using var stream = SysFile.OpenRead(fullPath); 63 | node = JsonNode.Parse( 64 | stream, 65 | new JsonNodeOptions { PropertyNameCaseInsensitive = false }, 66 | new JsonDocumentOptions 67 | { 68 | AllowTrailingCommas = true, 69 | CommentHandling = JsonCommentHandling.Skip, 70 | }); 71 | } 72 | catch (IOException e) 73 | { 74 | context.Fail($"Could not read from {fullPath}: {e.Message}"); 75 | throw null; 76 | } 77 | catch (JsonException) 78 | { 79 | context.Fail($"{fullPath} does not contain valid JSON."); 80 | throw null; 81 | } 82 | 83 | return node switch { 84 | null => context.Fail($"{fullPath} was parsed as JSON null."), 85 | JsonObject obj => obj, 86 | object other => context.Fail($"{fullPath} was parsed as a {other.GetType().Name}, not a {nameof(JsonObject)}."), 87 | }; 88 | } 89 | 90 | /* 91 | * Summary : Saves a JSON object to a file. Fails the build if not successful. 92 | * Params : context - The Cake context. 93 | * path - The path of the file to parse. 94 | * Returns : The parsed object. 95 | */ 96 | static void SaveJson(this ICakeContext context, JsonNode json, FilePath path) 97 | { 98 | var fullPath = path.FullPath; 99 | try 100 | { 101 | using var stream = SysFile.OpenWrite(fullPath); 102 | var writerOptions = new JsonWriterOptions 103 | { 104 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 105 | Indented = true, 106 | }; 107 | 108 | using var writer = new Utf8JsonWriter(stream, writerOptions); 109 | json.WriteTo(writer); 110 | stream.SetLength(stream.Position); 111 | } 112 | catch (IOException e) 113 | { 114 | context.Fail($"Could not write to {fullPath}: {e.Message}"); 115 | throw null; 116 | } 117 | } 118 | 119 | /* 120 | * Summary : Gets the value of a property from a JSON object. Fails the build if not successful. 121 | * Types : T - The desired type of the property value. 122 | * Params : context - The Cake context. 123 | * json - The JSON object. 124 | * propertyName - The name of the property to get. 125 | * description - A description of the object for exception messages. 126 | * Returns : The value of the specified property. 127 | */ 128 | static T GetJsonPropertyValue(this ICakeContext context, JsonObject json, string propertyName, string objectDescription = "JSON object") 129 | { 130 | context.Ensure(json.TryGetPropertyValue(propertyName, out var property), $"Json property {propertyName} not found in {objectDescription}."); 131 | switch (property) 132 | { 133 | case null: 134 | return context.Fail($"Json property {propertyName} in {objectDescription} is null."); 135 | case JsonValue value: 136 | context.Ensure(value.TryGetValue(out var result), $"Json property {propertyName} in {objectDescription} cannot be converted to a {typeof(T).Name}."); 137 | return result ?? context.Fail($"Json property {propertyName} in {objectDescription} has a null value."); 138 | default: 139 | return context.Fail($"Json property {propertyName} in {objectDescription} is a {property.GetType().Name}, not a {nameof(JsonValue)}."); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /build/nbgv.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Nerdbank.GitVersioning helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.Text; 11 | using System.Text.Json.Nodes; 12 | 13 | /* 14 | * Summary : Gets version information using the NBGV tool. 15 | * Params : context - The Cake context. 16 | * Returns : VersionStr - The project version. 17 | * Ref - The Git ref from which we are building. 18 | * IsPublicRelease - True if a public release can be built, false otherwise. 19 | * IsPrerelease - True if the project version is tagged as prerelease, false otherwise. 20 | */ 21 | static (string VersionStr, string Ref, bool IsPublicRelease, bool IsPrerelease) GetVersionInformation(this ICakeContext context) 22 | { 23 | var nbgvOutput = new StringBuilder(); 24 | context.DotNetTool( 25 | "nbgv get-version --format json", 26 | new DotNetToolSettings { 27 | SetupProcessSettings = s => s 28 | .SetRedirectStandardOutput(true) 29 | .SetRedirectedStandardOutputHandler(x => { 30 | nbgvOutput.AppendLine(x); 31 | return x; 32 | }), 33 | }); 34 | 35 | var json = context.ParseJsonObject(nbgvOutput.ToString(), "The output of nbgv"); 36 | return ( 37 | VersionStr: context.GetJsonPropertyValue(json, "SemVer2", "the output of nbgv"), 38 | Ref: context.GetJsonPropertyValue(json, "BuildingRef", "the output of nbgv"), 39 | IsPublicRelease: context.GetJsonPropertyValue(json, "PublicRelease", "the output of nbgv"), 40 | IsPrerelease: !string.IsNullOrEmpty(context.GetJsonPropertyValue(json, "PrereleaseVersion", "the output of nbgv"))); 41 | } 42 | -------------------------------------------------------------------------------- /build/options.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Option helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.ComponentModel; 11 | using System.Linq; 12 | 13 | /* 14 | * Summary : Tells whether the specified option is present, either as an argument 15 | * or as an environment variable. 16 | * Params : context - The Cake context. 17 | * name - The option name. 18 | * environmentPrefix - An optional prefix for the environment variable name; 19 | * for example, camelCasedOption (prefix = "MYAPP_") -> MYAPP_CAMEL_CASED_OPTION 20 | * Returns : If an argument with the specified name is present, true; 21 | * if an environment variable with the specified name (converted according to environmentPrefix) 22 | * is present, true; otherwise, false. 23 | */ 24 | static bool HasOption(this ICakeContext context, string name, string? environmentPrefix = null) 25 | => context.HasArgument(name) || context.HasEnvironmentVariable(OptionNameToEnvironmentVariableName(name, environmentPrefix)); 26 | 27 | /* 28 | * Summary : Gets an option from, in this order: 29 | * * a command line argument with the specified name; 30 | * * an environment variable with the specified name converted to UNDERSCORE_UPPER_CASE; 31 | * * the provided default value. 32 | * Params : context - The Cake context. 33 | * name - The option name. 34 | * defaultValue - The value returned if neither a corresponding argument 35 | * nor environment variable was found. 36 | */ 37 | static T GetOption(this ICakeContext context, string name, T defaultValue) 38 | where T : notnull 39 | => context.GetOption(name, null, defaultValue); 40 | 41 | /* 42 | * Summary : Gets an option from, in this order: 43 | * * a command line argument with the specified name; 44 | * * an environment variable with the specified name converted to UNDERSCORE_UPPER_CASE 45 | * and optionally prefixed with the specified environmentPrefix; 46 | * * the provided default value. 47 | * Params : context - The Cake context. 48 | * name - The option name. 49 | * environmentPrefix - An optional prefix for the environment variable name; 50 | * for example, "camelCasedOption" with an environmentPrefix 51 | * of "MYAPP_" becomes "MYAPP_CAMEL_CASED_OPTION". 52 | * defaultValue - The value returned if neither a corresponding argument 53 | * nor environment variable was found. 54 | */ 55 | static T GetOption(this ICakeContext context, string name, string? environmentPrefix, T defaultValue) 56 | where T : notnull 57 | { 58 | var value = context.Arguments.GetArguments(name)?.FirstOrDefault(); 59 | if (value != null) 60 | { 61 | return ConvertOption(value); 62 | } 63 | 64 | value = context.Environment.GetEnvironmentVariable(OptionNameToEnvironmentVariableName(name, environmentPrefix)); 65 | return value == null ? defaultValue : ConvertOption(value); 66 | } 67 | 68 | /* 69 | * Summary : Gets an option from, in this order: 70 | * * a command line argument with the specified name; 71 | * * an environment variable with the specified name converted to UNDERSCORE_UPPER_CASE; 72 | * * the provided default value. 73 | * Throw an exception if the option is not found or has an empty value. 74 | * Params : context - The Cake context. 75 | * name - The option name. 76 | */ 77 | static T GetOptionOrFail(this ICakeContext context, string name) 78 | where T : notnull 79 | => context.GetOptionOrFail(name, null); 80 | 81 | /* 82 | * Summary : Gets an option from, in this order: 83 | * * a command line argument with the specified name; 84 | * * an environment variable with the specified name converted to UNDERSCORE_UPPER_CASE 85 | * and optionally prefixed with the specified environmentPrefix; 86 | * * the provided default value. 87 | * Throw an exception if the option is not found or has an empty value. 88 | * Params : context - The Cake context. 89 | * name - The option name. 90 | * environmentPrefix - An optional prefix for the environment variable name; 91 | * for example, "camelCasedOption" with an environmentPrefix 92 | * of "MYAPP_" becomes "MYAPP_CAMEL_CASED_OPTION". 93 | */ 94 | static T GetOptionOrFail(this ICakeContext context, string name, string? environmentPrefix) 95 | where T : notnull 96 | { 97 | var value = context.Arguments.GetArguments(name)?.FirstOrDefault(); 98 | if (value != null) 99 | { 100 | return ConvertOption(value); 101 | } 102 | 103 | var envName = OptionNameToEnvironmentVariableName(name, environmentPrefix); 104 | value = context.Environment.GetEnvironmentVariable(envName); 105 | if (value != null) 106 | { 107 | return ConvertOption(value); 108 | } 109 | 110 | throw new CakeException($"Option {name} / environment variable {envName} not found or empty."); 111 | } 112 | 113 | /* 114 | * Summary : Converts an option name (which is supposed to be in camelCase) 115 | * to an environment variable name (UNDERSCORE_UPPER_CASE). 116 | * Params : prefix - An optional prefix for the environment variable name; 117 | * for example, camelCasedOption (prefix = "MYAPP_") -> MYAPP_CAMEL_CASED_OPTION 118 | */ 119 | // Copyright (c) .NET Foundation and Contributors - MIT License - https://github.com/Humanizr/Humanizer 120 | static string OptionNameToEnvironmentVariableName(string name, string? prefix = null) 121 | => (prefix ?? string.Empty) + Regex.Replace( 122 | Regex.Replace( 123 | Regex.Replace( 124 | name, 125 | @"([\p{Lu}]+)([\p{Lu}][\p{Ll}])", 126 | "$1_$2"), 127 | @"([\p{Ll}\d])([\p{Lu}])", 128 | "$1_$2"), 129 | @"[-\s]", 130 | "_") 131 | .ToUpperInvariant(); 132 | 133 | /* 134 | * Summary : Convert an option to the desired type. 135 | * Types : T - The type to convert the option to. 136 | * Params : value - The value of the option. 137 | * Returns : The converted value. 138 | */ 139 | static T ConvertOption(string value) 140 | where T : notnull 141 | { 142 | var converter = TypeDescriptor.GetConverter(typeof(T)); 143 | return (T)converter.ConvertFromInvariantString(value)!; 144 | } 145 | -------------------------------------------------------------------------------- /build/process.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Process helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.Collections.Generic; 11 | 12 | /* 13 | * Summary : Executes an external command, capturing standard output and failing if the exit code is not zero. 14 | * Params : context - The Cake context. 15 | * command - The name of the command to execute. 16 | * arguments - The arguments to pass to the command. 17 | * Returns : The captured output of the command. 18 | */ 19 | static IEnumerable Exec(this ICakeContext context, string command, ProcessArgumentBuilder arguments) 20 | { 21 | var exitCode = context.Exec(command, arguments, out var output); 22 | context.Ensure(exitCode == 0, $"'{command} {arguments.RenderSafe()}' exited with code {exitCode}."); 23 | return output; 24 | } 25 | 26 | /* 27 | * Summary : Executes an external command, capturing standard output and failing if the exit code is not zero. 28 | * Params : context - The Cake context. 29 | * command - The name of the command to execute. 30 | * arguments - The arguments to pass to the command. 31 | * out output - The captured output of the command. 32 | * Returns : The exit code of the command. 33 | */ 34 | static int Exec(this ICakeContext context, string command, ProcessArgumentBuilder arguments, out IEnumerable output) 35 | => context.StartProcess( 36 | command, 37 | new ProcessSettings { Arguments = arguments, RedirectStandardOutput = true }, 38 | out output); 39 | -------------------------------------------------------------------------------- /build/public-api.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Public API helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Text; 13 | 14 | using SysFile = System.IO.File; 15 | 16 | /* 17 | * Summary : Specifies the kind of changes public APIs have undergone between an older and a newer version. 18 | * Remarks : The values of this enum are sorted in ascending order of importance, 19 | * so that they may be compared. 20 | */ 21 | enum ApiChangeKind 22 | { 23 | /* 24 | * Summary : Public APIs have not changed between two versions. 25 | */ 26 | None, 27 | 28 | /* 29 | * Summary : A newer version has only added public APIs with respect to an older version. 30 | */ 31 | Additive, 32 | 33 | /* 34 | * Summary : A newer version's public APIs have undergone breaking changes since an older version was published. 35 | */ 36 | Breaking, 37 | } 38 | 39 | /* 40 | * Summary : Gets the kind of change public APIs underwent, according to the presence of new public APIs 41 | * and/or the removal of existing public APIs in all PublicAPI.Unshipped.txt files 42 | * of the repository. 43 | * Params : context - The Cake context. 44 | * Returns : If at least one public API was removed, ApiChangeKind.Breaking; 45 | * if no public API was removed, but at least one was added, ApiChangeKind.Additive; 46 | * if no public API was removed nor added, ApiChangeKind.None. 47 | */ 48 | static ApiChangeKind GetPublicApiChangeKind(this ICakeContext context) 49 | { 50 | context.Information("Computing API change kind according to unshipped public API files..."); 51 | var result = ApiChangeKind.None; 52 | foreach (var unshippedPath in context.GetAllPublicApiFilePairs().Select(pair => pair.UnshippedPath)) 53 | { 54 | var fileResult = context.GetPublicApiChangeKind(unshippedPath); 55 | context.Verbose($"{unshippedPath} -> {fileResult}"); 56 | if (fileResult == ApiChangeKind.Breaking) 57 | { 58 | return ApiChangeKind.Breaking; 59 | } 60 | else if (fileResult > result) 61 | { 62 | result = fileResult; 63 | } 64 | } 65 | 66 | return result; 67 | } 68 | 69 | /* 70 | * Summary : Transfers unshipped public API definitions to PublicAPI.Shipped.txt 71 | * in all directories of the repository. 72 | * Params : context - The Cake context. 73 | * Returns : An enumeration of the modified files. 74 | */ 75 | static IEnumerable TransferAllPublicApiToShipped(this ICakeContext context) 76 | { 77 | context.Information("Updating public API files..."); 78 | foreach (var pair in context.GetAllPublicApiFilePairs()) 79 | { 80 | context.Verbose($"Updating {pair.ShippedPath}..."); 81 | if (context.TransferPublicApiToShipped(pair.UnshippedPath, pair.ShippedPath)) 82 | { 83 | yield return pair.ShippedPath; 84 | yield return pair.UnshippedPath; 85 | } 86 | } 87 | } 88 | 89 | /* 90 | * Summary : Gets all public API definition file pairs in the repository. 91 | * Params : context - The Cake context. 92 | * Returns : An enumeration of (UnshippedPath, ShippedPath) tuples. 93 | */ 94 | static IEnumerable<(FilePath UnshippedPath, FilePath ShippedPath)> GetAllPublicApiFilePairs(this ICakeContext context) 95 | { 96 | (FilePath UnshippedPath, FilePath ShippedPath)? GetPair(FilePath shippedPath) 97 | { 98 | var unshippedPath = shippedPath.GetDirectory().CombineWithFilePath("PublicAPI.Unshipped.txt"); 99 | return context.FileSystem.Exist(unshippedPath) ? (unshippedPath, shippedPath) : null; 100 | } 101 | 102 | return context 103 | .GetFiles("**/PublicAPI.Shipped.txt", new() { IsCaseSensitive = true }) 104 | .Select(GetPair) 105 | .Where(maybePair => maybePair.HasValue) 106 | .Select(maybePair => maybePair!.Value); 107 | } 108 | 109 | /* 110 | * Summary : Gets the kind of change public APIs underwent, according to the presence of new public APIs 111 | * and/or the removal of existing public APIs. 112 | * Params : context - The Cake context. 113 | * unshippedPath - The FilePath of PublicAPI.Unshipped.txt 114 | * Returns : If at least one public API was removed, ApiChangeKind.Breaking; 115 | * if no public API was removed, but at least one was added, ApiChangeKind.Additive; 116 | * if no public API was removed nor added, ApiChangeKind.None. 117 | */ 118 | static ApiChangeKind GetPublicApiChangeKind(this ICakeContext context, FilePath unshippedPath) 119 | { 120 | var unshippedLines = SysFile.ReadAllLines(unshippedPath.FullPath, Encoding.UTF8); 121 | static bool IsEmptyOrStartsWithHash(string s) => s.Length == 0 || s[0] == '#'; 122 | var unshippedPublicApiLines = unshippedLines.SkipWhile(IsEmptyOrStartsWithHash); 123 | const string RemovedPrefix = "*REMOVED*"; 124 | var newApiPresent = false; 125 | foreach (var line in unshippedPublicApiLines) 126 | { 127 | if (line.StartsWith(RemovedPrefix, StringComparison.Ordinal)) 128 | { 129 | return ApiChangeKind.Breaking; 130 | } 131 | 132 | newApiPresent = true; 133 | } 134 | 135 | return newApiPresent ? ApiChangeKind.Additive : ApiChangeKind.None; 136 | } 137 | 138 | /* 139 | * Summary : Transfers unshipped public API definitions to PublicAPI.Shipped.txt 140 | * Params : context - The Cake context. 141 | * unshippedPath - The FilePath of PublicAPI.Unshipped.txt 142 | * shippedPath - The FilePath of PublicAPI.Shipped.txt 143 | * Returns : true if files were modified; false otherwise. 144 | */ 145 | static bool TransferPublicApiToShipped(this ICakeContext context, FilePath unshippedPath, FilePath shippedPath) 146 | { 147 | var utf8 = new UTF8Encoding(false); 148 | var unshippedLines = SysFile.ReadAllLines(unshippedPath.FullPath, utf8); 149 | var unshippedHeaderLines = unshippedLines.TakeWhile(IsEmptyOrStartsWithHash).ToArray(); 150 | if (unshippedHeaderLines.Length == unshippedLines.Length) 151 | { 152 | return false; 153 | } 154 | 155 | static bool IsEmptyOrStartsWithHash(string s) => s.Length == 0 || s[0] == '#'; 156 | var shippedLines = SysFile.ReadAllLines(shippedPath.FullPath, utf8); 157 | var shippedHeaderLines = shippedLines.TakeWhile(IsEmptyOrStartsWithHash).ToArray(); 158 | 159 | const string RemovedPrefix = "*REMOVED*"; 160 | static bool StartsWithRemovedPrefix(string s) => s.StartsWith(RemovedPrefix, StringComparison.Ordinal); 161 | static bool DoesNotStartWithRemovedPrefix(string s) => !StartsWithRemovedPrefix(s); 162 | var removedLines = unshippedLines 163 | .Skip(unshippedHeaderLines.Length) 164 | .Where(StartsWithRemovedPrefix) 165 | .Select(l => l[(RemovedPrefix.Length)..]) 166 | .OrderBy(l => l, StringComparer.Ordinal) // For BinarySearch 167 | .ToArray(); 168 | 169 | bool IsNotRemoved(string s) => Array.BinarySearch(removedLines, s, StringComparer.Ordinal) < 0; 170 | var newShippedLines = shippedLines 171 | .Skip(shippedHeaderLines.Length) 172 | .Where(IsNotRemoved) 173 | .Concat(unshippedLines 174 | .Skip(unshippedHeaderLines.Length) 175 | .Where(DoesNotStartWithRemovedPrefix)) 176 | .OrderBy(l => l, StringComparer.Ordinal); 177 | 178 | SysFile.WriteAllLines(shippedPath.FullPath, shippedHeaderLines.Concat(newShippedLines), utf8); 179 | SysFile.WriteAllLines(unshippedPath.FullPath, unshippedHeaderLines, utf8); 180 | return true; 181 | } 182 | -------------------------------------------------------------------------------- /build/setup-teardown.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // ============================================================================================= 7 | // Setup and Teardown, common to all scripts 8 | // ============================================================================================= 9 | 10 | Setup(context => 11 | { 12 | var data = new BuildData(context); 13 | if (data.IsCI && !data.IsGitHubAction) 14 | { 15 | throw new CakeException(255, "This script can only run locally or in a GitHub Actions workflow."); 16 | } 17 | 18 | return data; 19 | }); 20 | 21 | Teardown((context, data) => 22 | { 23 | // For some reason, DotNetBuildServerShutdown hangs in a GitHub Actions runner; 24 | // it is still useful on a local machine though 25 | if (!data.IsCI) 26 | { 27 | context.DotNetBuildServerShutdown(new DotNetBuildServerShutdownSettings 28 | { 29 | Razor = true, 30 | VBCSCompiler = true, 31 | }); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /build/utilities.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Miscellaneous utilities 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | using System; 11 | using System.Linq; 12 | 13 | /* 14 | * Summary : Filters a sequence of nullable values, taking only those that are not null. 15 | * Type params : T - The type of the elements of this. 16 | * Params : this - An IEnumerable to filter. 17 | * Returns : An IEnumerable that contains elements from the input sequence that are not null. 18 | */ 19 | static IEnumerable WhereNotNull(this IEnumerable @this) 20 | where T : class 21 | { 22 | return @this.Where(IsNotNull) as IEnumerable; 23 | 24 | static bool IsNotNull(T? x) => x is not null; 25 | } 26 | 27 | /* 28 | * Summary : Filters a sequence of nullable values, taking only those that are not null. 29 | * Type params : T - The type of the elements of this. 30 | * Params : this - An IEnumerable to filter. 31 | * Returns : An IEnumerable that contains elements from the input sequence that are not null. 32 | */ 33 | public static IEnumerable WhereNotNull(this IEnumerable @this) 34 | where T : struct 35 | { 36 | return @this.Where(IsNotNull).Select(GetValue); 37 | 38 | static bool IsNotNull(T? x) => x.HasValue; 39 | 40 | static T GetValue(T? x) => x!.Value; 41 | } 42 | -------------------------------------------------------------------------------- /build/workspace.cake: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See LICENSE file in the project root for full license information. 3 | 4 | #nullable enable 5 | 6 | // --------------------------------------------------------------------------------------------- 7 | // Workspace helpers 8 | // --------------------------------------------------------------------------------------------- 9 | 10 | /* 11 | * Summary : Delete all intermediate and output directories. 12 | * On a local machine, also delete Visual Studio and ReSharper caches. 13 | * Params : context - The Cake context. 14 | */ 15 | static void CleanAll(this ICakeContext context, BuildData data) 16 | { 17 | context.DeleteDirectoryIfExists(".vs"); 18 | context.DeleteDirectoryIfExists("_ReSharper.Caches"); 19 | context.DeleteDirectoryIfExists("artifacts"); 20 | context.DeleteDirectoryIfExists("logs"); 21 | context.DeleteDirectoryIfExists("TestResults"); 22 | foreach (var project in data.Solution.Projects) 23 | { 24 | var projectDirectory = project.Path.GetDirectory(); 25 | context.DeleteDirectoryIfExists(projectDirectory.Combine("bin")); 26 | context.DeleteDirectoryIfExists(projectDirectory.Combine("obj")); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.100", 4 | "rollForward": "latestMinor", 5 | "allowPrerelease": false 6 | }, 7 | "msbuild-sdks": { 8 | "Buildvana.Sdk": "1.0.122-preview", 9 | "Microsoft.Build.NoTargets": "3.7.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /graphics/PackageIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tenacom/PolyKit/97de16ce19a0b67791000839106715bee6393400/graphics/PackageIcon.png -------------------------------------------------------------------------------- /graphics/README.md: -------------------------------------------------------------------------------- 1 | # Graphics 2 | 3 | All the graphic elements listed below, except where otherwise specified, are Copyright (C) Tenacom and Contributors and are licensed under the MIT license. See the LICENSE file in the project root for full license information. 4 | 5 | ## `SquareLogo` 6 | 7 | Reference logo, basic square logo. Used as NuGet package icon, favicon for web-based documentation, and anywhere a square-shaped logo is needed or preferred. 8 | 9 | This is a modifed version of [Putty Knife](https://thenounproject.com/icon/3765029) by Ranah Pixel Studio. The original file was obtained from [the Noun Project](https://thenounproject.com/) under the [Creative Commons Attribution 3.0 Unported (CC BY 3.0)](https://creativecommons.org/licenses/by/3.0/) license. 10 | 11 | Modified by [@rdeago](https://github.com/rdeago). 12 | 13 | Related files: 14 | 15 | - `PackageIcon.png` (512x512px) 16 | ![PackageIcon.png](https://raw.githubusercontent.com/Tenacom/PolyKit/main/graphics/PackageIcon.png) 17 | 18 | - `docs/logo.svg` (optimized) 19 | ![docs/logo.svg](https://raw.githubusercontent.com/Tenacom/PolyKit/main/graphics/docs/logo.png) 20 | 21 | - `docs/favicon.ico` (16x16px,32bpp; 32x32px,32bpp; 48x48px,32bpp; 64x64px,32bpp; 128x128px,32bpp) 22 | ![docs/favicon.ico](https://raw.githubusercontent.com/Tenacom/PolyKit/main/graphics/docs/favicon.ico) 23 | 24 | ## `Readme` 25 | 26 | Graphic header for README file. 27 | 28 | Uses the following material: [SquareLogo](#squarelogo); [Repo](#repo). 29 | 30 | Related files: 31 | 32 | - `Readme.png` (540x160px) 33 | ![Readme.png](https://raw.githubusercontent.com/Tenacom/PolyKit/main/graphics/Readme.png) 34 | 35 | ## `SocialCard` 36 | 37 | Social card for GitHub project. 38 | 39 | Uses the following material: [SquareLogo](#squarelogo); [Repo](#repo); [Courier Prime](#courier-prime). 40 | 41 | Related files: 42 | 43 | - `SocialCard.png` (1280x640px) 44 | ![SocialCard.png](https://raw.githubusercontent.com/Tenacom/PolyKit/main/graphics/SocialCard.png) 45 | 46 | ## Third-party material 47 | 48 | The following third-party material was used to produce the above files. 49 | 50 | ### Repo 51 | 52 | The [Repo](https://fontlibrary.org/en/font/repo) font, by Stefan Peev, was obtained from [Font Library](https://fontlibrary.org) under the [SIL Open Font License (OFL)](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL). 53 | 54 | ### Courier Prime 55 | 56 | The [Courier Prime](https://fontlibrary.org/en/font/courier-prime) font, by Alan Dague-Greene of Quote-Unquote Apps, was obtained from [Font Library](https://fontlibrary.org) under the [SIL Open Font License (OFL)](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL). 57 | -------------------------------------------------------------------------------- /graphics/Readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tenacom/PolyKit/97de16ce19a0b67791000839106715bee6393400/graphics/Readme.png -------------------------------------------------------------------------------- /graphics/SocialCard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tenacom/PolyKit/97de16ce19a0b67791000839106715bee6393400/graphics/SocialCard.png -------------------------------------------------------------------------------- /graphics/SquareLogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 23 | 25 | 26 | 28 | image/svg+xml 29 | 31 | 32 | 33 | 34 | 36 | 39 | 43 | 47 | 48 | 57 | 58 | 96 | 104 | 105 | 109 | 112 | 116 | 120 | 124 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /graphics/docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tenacom/PolyKit/97de16ce19a0b67791000839106715bee6393400/graphics/docs/favicon.ico -------------------------------------------------------------------------------- /graphics/docs/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/PolyKit.Embedded/PolyKit.Embedded.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Embeds polyfills in your project, creating either internal or public types. 5 | net8.0 6 | true 7 | 8 | true 9 | 10 | 11 | 15 | 16 | true 17 | $(BaseIntermediateOutputPath)\Generated 18 | false 19 | 20 | 21 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/PolyKit.Generator/PolyKit.Generator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | true 7 | false 8 | 9 | false 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/PolyKit.Generator/PolyfillGenerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) Tenacom and contributors. Licensed under the MIT license. 2 | // See the LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Reflection; 9 | using System.Text; 10 | using System.Text.RegularExpressions; 11 | using Microsoft.CodeAnalysis; 12 | 13 | #pragma warning disable CA1050 // Declare types in namespaces 14 | 15 | /// 16 | /// Adds polyfill source files to a project. 17 | /// 18 | [Generator(LanguageNames.CSharp)] 19 | public class PolyfillGenerator : IIncrementalGenerator 20 | { 21 | private const string Eol = "\r\n"; 22 | 23 | // All polyfill source files are saved as UTF-8 with BOM, with lines separated by CR+LF. 24 | // (see .editorconfig in the project root) 25 | private static readonly IReadOnlyCollection Header = new[] 26 | { 27 | "// ", 28 | "// >>>> DO NOT MODIFY THIS FILE <<<<", 29 | "//", 30 | "// This file is part of the PolyKit.Embedded NuGet package and resides in your local NuGet cache.", 31 | "// Any modification you make will influence all projects on your machine that reference PolyKit.Embedded.", 32 | "// Modifications will be undone anyway as soon as you update PolyKit.Embedded or clear your local NuGet cache.", 33 | "//", 34 | "// If there seems to be a problem with this file:", 35 | "// - First of all, be sure to read the documentation at https://github.com/Tenacom/PolyKit#readme", 36 | "// - If you have a doubt or want to ask a question, you are welcome to our Discussions area", 37 | "// at https://github.com/Tenacom/PolyKit/discussions", 38 | "// - Please check whether there is already an issue that applies to your problem", 39 | "// at https://github.com/Tenacom/PolyKit/issues - you may find an existing solution or workaround", 40 | "// - If you think you have found a bug that has not been reported yet,", 41 | "// or have an idea that may help improve the PolyKit project,", 42 | "// you are welcome to open a new issue at https://github.com/Tenacom/PolyKit/issues/new", 43 | "//", 44 | "// This file is part of PolyKit.Embedded version " + ThisAssembly.AssemblyInformationalVersion, 45 | "// and is provided under one or more license agreements.", 46 | "// Please see https://github.com/Tenacom/PolyKit for full license information.", 47 | "// ", 48 | string.Empty, 49 | "#nullable enable", 50 | string.Empty, 51 | "#pragma warning disable RS0016 // Add public types and members to the declared API", 52 | "#pragma warning disable RS0041 // Public members should not use oblivious types", 53 | string.Empty, 54 | }; 55 | 56 | private static readonly Regex PolyfillRegex = new( 57 | @"^(\s*)public(?:\s*)//(?:\s*)polyfill!((?:\+|-)?)(?:\s|$)", 58 | RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.Singleline); 59 | 60 | // For the rationale behind the added attributes, see this article: 61 | // https://riccar.do/posts/2022/2022-05-30-well-behaved-guest-code.html 62 | private static readonly IReadOnlyCollection AdditionalPolyfillLines = new[] 63 | { 64 | "[System.Diagnostics.DebuggerNonUserCode]", 65 | "[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]", 66 | }; 67 | private static readonly IReadOnlyCollection PolyfillLines = new[] 68 | { 69 | "[System.CodeDom.Compiler.GeneratedCode(\"PolyKit.Embedded\", \"" + ThisAssembly.AssemblyInformationalVersion + "\")]", 70 | "#if POLYKIT_PUBLIC", 71 | "public", 72 | "#else", 73 | "internal", 74 | "#endif", 75 | }; 76 | 77 | /// 78 | public void Initialize(IncrementalGeneratorInitializationContext context) 79 | => context.RegisterPostInitializationOutput(static ctx => 80 | { 81 | var assembly = Assembly.GetExecutingAssembly(); 82 | var names = assembly.GetManifestResourceNames() 83 | .Where(n => n.EndsWith(".cs", StringComparison.Ordinal)) 84 | .Select(s => s.Substring(0, s.Length - 3)); 85 | 86 | var sb = new StringBuilder(16 * 1024); 87 | foreach (var line in Header) 88 | { 89 | _ = sb.Append(line).Append(Eol); 90 | } 91 | 92 | var headerLength = sb.Length; 93 | foreach (var name in names) 94 | { 95 | using (var inStream = assembly.GetManifestResourceStream(name + ".cs")) 96 | using (var reader = new StreamReader(inStream, Encoding.UTF8)) 97 | { 98 | for (; ;) 99 | { 100 | var line = reader.ReadLine(); 101 | if (line == null) 102 | { 103 | break; 104 | } 105 | 106 | var match = PolyfillRegex.Match(line); 107 | if (!match.Success) 108 | { 109 | _ = sb.Append(line).Append(Eol); 110 | continue; 111 | } 112 | 113 | var indentation = match.Groups[1].Captures[0].Value; 114 | var modifier = match.Groups[2].Captures[0].Value; 115 | 116 | // Additional polyfill lines contain attributes that are not valid on enums and interfaces 117 | var replacementLines = modifier == "-" 118 | ? PolyfillLines 119 | : AdditionalPolyfillLines.Concat(PolyfillLines); 120 | 121 | foreach (var replacementLine in replacementLines) 122 | { 123 | // Only indent non-empty lines; never indent preprocessor directives 124 | if (replacementLine.Length > 0 && replacementLine[0] != '#') 125 | { 126 | _ = sb.Append(indentation); 127 | } 128 | 129 | _ = sb.Append(replacementLine).Append(Eol); 130 | } 131 | } 132 | } 133 | 134 | ctx.AddSource(name + ".g.cs", sb.ToString()); 135 | sb.Length = headerLength; 136 | } 137 | }); 138 | } 139 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/PolyKit.Polyfills.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | netstandard2.0;netstandard2.1;net462;net47;net6.0;net7.0;net8.0 14 | 12 15 | 16 | false 17 | 18 | 19 | 20 | 21 | None 22 | false 23 | 24 | 25 | 26 | 27 | $(NoWarn);CA1812 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/PolyKit/Diagnostics/CodeAnalysis/ValidatedNotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PolyKit.Diagnostics.CodeAnalysis; 4 | 5 | /// 6 | /// Indicates to Code Analysis that a method validates a parameter, 7 | /// so that if / when the method returns the parameter is known to be non-null. 8 | /// 9 | [AttributeUsage(AttributeTargets.Parameter)] 10 | public // polyfill! 11 | sealed class ValidatedNotNullAttribute : Attribute 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/AllowNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.AllowNullAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L7 14 | 15 | /// 16 | /// Specifies that null is allowed as an input even if the corresponding type disallows it. 17 | /// 18 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] 19 | public // polyfill! 20 | sealed class AllowNullAttribute : Attribute 21 | { 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/ConstantExpectedAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.ConstantExpectedAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System.Diagnostics.CodeAnalysis; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/ConstantExpectedAttribute.cs 15 | 16 | /// 17 | /// Indicates that the specified method parameter expects a constant. 18 | /// 19 | /// 20 | /// This can be used to inform tooling that a constant should be used as an argument for the annotated parameter. 21 | /// 22 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 23 | public // polyfill! 24 | sealed class ConstantExpectedAttribute : Attribute 25 | { 26 | /// 27 | /// Gets or sets the minimum bound of the expected constant, inclusive. 28 | /// 29 | public object? Min { get; set; } 30 | 31 | /// 32 | /// Gets or sets the maximum bound of the expected constant, inclusive. 33 | /// 34 | public object? Max { get; set; } 35 | } 36 | 37 | #endif 38 | #endif 39 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/DisallowNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DisallowNullAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L16 14 | 15 | /// 16 | /// Specifies that null is disallowed as an input even if the corresponding type allows it. 17 | /// 18 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] 19 | public // polyfill! 20 | sealed class DisallowNullAttribute : Attribute 21 | { 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/DoesNotReturnAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L100 14 | 15 | /// 16 | /// Applied to a method that will never return under any circumstance. 17 | /// 18 | [AttributeUsage(AttributeTargets.Method, Inherited = false)] 19 | public // polyfill! 20 | sealed class DoesNotReturnAttribute : Attribute 21 | { 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/DoesNotReturnIfAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L109 14 | 15 | /// 16 | /// Applied to a method that will never return under any circumstance. 17 | /// 18 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 19 | public // polyfill! 20 | sealed class DoesNotReturnIfAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class 24 | /// with the specified parameter value. 25 | /// 26 | /// 27 | /// The condition parameter value. 28 | /// Code after the method will be considered unreachable by diagnostics 29 | /// if the argument to the associated parameter matches this value. 30 | /// 31 | public DoesNotReturnIfAttribute(bool parameterValue) 32 | { 33 | ParameterValue = parameterValue; 34 | } 35 | 36 | #pragma warning disable SA1623 // Property summary documentation should match accessors - "Gets a value indicating whether..." is not suitable here. 37 | /// 38 | /// Gets the condition parameter value. 39 | /// 40 | public bool ParameterValue { get; } 41 | #pragma warning restore SA1623 // Property summary documentation should match accessors 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs 14 | 15 | /// 16 | /// States a dependency that one member has on another. 17 | /// 18 | /// 19 | /// This can be used to inform tooling of a dependency that is otherwise not evident purely from 20 | /// metadata and IL, for example a member relied on via reflection. 21 | /// 22 | [AttributeUsage( 23 | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method, 24 | AllowMultiple = true, 25 | Inherited = false)] 26 | public // polyfill! 27 | sealed class DynamicDependencyAttribute : Attribute 28 | { 29 | /// 30 | /// Initializes a new instance of the class 31 | /// with the specified signature of a member on the same type as the consumer. 32 | /// 33 | /// The signature of the member depended on. 34 | public DynamicDependencyAttribute(string memberSignature) 35 | { 36 | MemberSignature = memberSignature; 37 | } 38 | 39 | /// 40 | /// Initializes a new instance of the class 41 | /// with the specified signature of a member on a . 42 | /// 43 | /// The signature of the member depended on. 44 | /// The containing . 45 | public DynamicDependencyAttribute(string memberSignature, Type type) 46 | { 47 | MemberSignature = memberSignature; 48 | Type = type; 49 | } 50 | 51 | /// 52 | /// Initializes a new instance of the class 53 | /// with the specified signature of a member on a type in an assembly. 54 | /// 55 | /// The signature of the member depended on. 56 | /// The full name of the type containing the specified member. 57 | /// The assembly name of the type containing the specified member. 58 | public DynamicDependencyAttribute(string memberSignature, string typeName, string assemblyName) 59 | { 60 | MemberSignature = memberSignature; 61 | TypeName = typeName; 62 | AssemblyName = assemblyName; 63 | } 64 | 65 | /// 66 | /// Initializes a new instance of the class 67 | /// with the specified types of members on a . 68 | /// 69 | /// The types of members depended on. 70 | /// The containing the specified members. 71 | public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, Type type) 72 | { 73 | MemberTypes = memberTypes; 74 | Type = type; 75 | } 76 | 77 | /// 78 | /// Initializes a new instance of the class 79 | /// with the specified types of members on a type in an assembly. 80 | /// 81 | /// The types of members depended on. 82 | /// The full name of the type containing the specified members. 83 | /// The assembly name of the type containing the specified members. 84 | public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) 85 | { 86 | MemberTypes = memberTypes; 87 | TypeName = typeName; 88 | AssemblyName = assemblyName; 89 | } 90 | 91 | /// 92 | /// Gets the signature of the member depended on. 93 | /// 94 | /// 95 | /// Either must be a valid string or 96 | /// must not equal , but not both. 97 | /// 98 | public string? MemberSignature { get; } 99 | 100 | /// 101 | /// Gets the which specifies the type 102 | /// of members depended on. 103 | /// 104 | /// 105 | /// Either must be a valid string or 106 | /// must not equal , but not both. 107 | /// 108 | public DynamicallyAccessedMemberTypes MemberTypes { get; } 109 | 110 | /// 111 | /// Gets the containing the specified member. 112 | /// 113 | /// 114 | /// If neither nor are specified, 115 | /// the type of the consumer is assumed. 116 | /// 117 | public Type? Type { get; } 118 | 119 | /// 120 | /// Gets the full name of the type containing the specified member. 121 | /// 122 | /// 123 | /// If neither nor are specified, 124 | /// the type of the consumer is assumed. 125 | /// 126 | public string? TypeName { get; } 127 | 128 | /// 129 | /// Gets the assembly name of the specified type. 130 | /// 131 | /// 132 | /// is only valid when is specified. 133 | /// 134 | public string? AssemblyName { get; } 135 | 136 | /// 137 | /// Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG". 138 | /// 139 | public string? Condition { get; set; } 140 | } 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMemberTypes.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMemberTypes.cs 14 | 15 | /// 16 | /// Specifies the types of members that are dynamically accessed. 17 | /// 18 | /// This enumeration has a attribute that allows a 19 | /// bitwise combination of its member values. 20 | /// 21 | [Flags] 22 | public // polyfill!- 23 | enum DynamicallyAccessedMemberTypes 24 | { 25 | /// 26 | /// Specifies no members. 27 | /// 28 | None = 0, 29 | 30 | /// 31 | /// Specifies the default, parameterless public constructor. 32 | /// 33 | PublicParameterlessConstructor = 0x0001, 34 | 35 | /// 36 | /// Specifies all public constructors. 37 | /// 38 | PublicConstructors = 0x0002 | PublicParameterlessConstructor, 39 | 40 | /// 41 | /// Specifies all non-public constructors. 42 | /// 43 | NonPublicConstructors = 0x0004, 44 | 45 | /// 46 | /// Specifies all public methods. 47 | /// 48 | PublicMethods = 0x0008, 49 | 50 | /// 51 | /// Specifies all non-public methods. 52 | /// 53 | NonPublicMethods = 0x0010, 54 | 55 | /// 56 | /// Specifies all public fields. 57 | /// 58 | PublicFields = 0x0020, 59 | 60 | /// 61 | /// Specifies all non-public fields. 62 | /// 63 | NonPublicFields = 0x0040, 64 | 65 | /// 66 | /// Specifies all public nested types. 67 | /// 68 | PublicNestedTypes = 0x0080, 69 | 70 | /// 71 | /// Specifies all non-public nested types. 72 | /// 73 | NonPublicNestedTypes = 0x0100, 74 | 75 | /// 76 | /// Specifies all public properties. 77 | /// 78 | PublicProperties = 0x0200, 79 | 80 | /// 81 | /// Specifies all non-public properties. 82 | /// 83 | NonPublicProperties = 0x0400, 84 | 85 | /// 86 | /// Specifies all public events. 87 | /// 88 | PublicEvents = 0x0800, 89 | 90 | /// 91 | /// Specifies all non-public events. 92 | /// 93 | NonPublicEvents = 0x1000, 94 | 95 | /// 96 | /// Specifies all interfaces implemented by the type. 97 | /// 98 | Interfaces = 0x2000, 99 | 100 | /// 101 | /// Specifies all members. 102 | /// 103 | All = ~None, 104 | } 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttribute.cs 14 | 15 | /// 16 | /// Indicates that certain members on a specified are accessed dynamically, 17 | /// for example through . 18 | /// 19 | /// 20 | /// This allows tools to understand which members are being accessed during the execution 21 | /// of a program. 22 | /// This attribute is valid on members whose type is or . 23 | /// When this attribute is applied to a location of type , the assumption is 24 | /// that the string represents a fully qualified type name. 25 | /// When this attribute is applied to a class, interface, or struct, the members specified 26 | /// can be accessed dynamically on instances returned from calling 27 | /// on instances of that class, interface, or struct. 28 | /// If the attribute is applied to a method it's treated as a special case and it implies 29 | /// the attribute should be applied to the "this" parameter of the method. As such the attribute 30 | /// should only be used on instance methods of types assignable to System.Type (or string, but no methods 31 | /// will use it there). 32 | /// 33 | [AttributeUsage( 34 | AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | 35 | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | 36 | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, 37 | Inherited = false)] 38 | public // polyfill! 39 | sealed class DynamicallyAccessedMembersAttribute : Attribute 40 | { 41 | /// 42 | /// Initializes a new instance of the class 43 | /// with the specified member types. 44 | /// 45 | /// The types of members dynamically accessed. 46 | public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) 47 | { 48 | MemberTypes = memberTypes; 49 | } 50 | 51 | /// 52 | /// Gets the which specifies the type 53 | /// of members dynamically accessed. 54 | /// 55 | public DynamicallyAccessedMemberTypes MemberTypes { get; } 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/ExperimentalAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK8_0_OR_GREATER 2 | #if NET8_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.ExperimentalAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | 13 | namespace System.Diagnostics.CodeAnalysis; 14 | 15 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/ExperimentalAttribute.cs 16 | 17 | /// 18 | /// Indicates that an API is experimental and it may change in the future. 19 | /// 20 | /// 21 | /// This attribute allows call sites to be flagged with a diagnostic that indicates that an experimental feature is used. 22 | /// Authors can use this attribute to ship preview features in their assemblies. 23 | /// 24 | [AttributeUsage( 25 | AttributeTargets.Assembly 26 | | AttributeTargets.Module 27 | | AttributeTargets.Class 28 | | AttributeTargets.Struct 29 | | AttributeTargets.Enum 30 | | AttributeTargets.Constructor 31 | | AttributeTargets.Method 32 | | AttributeTargets.Property 33 | | AttributeTargets.Field 34 | | AttributeTargets.Event 35 | | AttributeTargets.Interface 36 | | AttributeTargets.Delegate, 37 | Inherited = false)] 38 | public // polyfill! 39 | sealed class ExperimentalAttribute : Attribute 40 | { 41 | /// 42 | /// Initializes a new instance of the class, specifying the ID that the compiler will use 43 | /// when reporting a use of the API the attribute applies to. 44 | /// 45 | /// The ID that the compiler will use when reporting a use of the API the attribute applies to. 46 | public ExperimentalAttribute(string diagnosticId) 47 | { 48 | DiagnosticId = diagnosticId; 49 | } 50 | 51 | /// 52 | /// Gets the ID that the compiler will use when reporting a use of the API the attribute applies to. 53 | /// 54 | /// The unique diagnostic ID. 55 | /// 56 | /// The diagnostic ID is shown in build output for warnings and errors. 57 | /// This property represents the unique ID that can be used to suppress the warnings or errors, if needed. 58 | /// 59 | public string DiagnosticId { get; } 60 | 61 | /// 62 | /// Gets or sets the URL for corresponding documentation. 63 | /// The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID. 64 | /// 65 | /// The format string that represents a URL to corresponding documentation. 66 | /// 67 | /// An example format string is https://contoso.com/obsoletion-warnings/{0}. 68 | /// 69 | public string? UrlFormat { get; set; } 70 | } 71 | 72 | #endif 73 | #endif 74 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/MaybeNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MaybeNullAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L25 14 | 15 | /// 16 | /// Specifies that an output may be null even if the corresponding type disallows it. 17 | /// 18 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] 19 | public // polyfill! 20 | sealed class MaybeNullAttribute : Attribute 21 | { 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/MaybeNullWhenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L43 14 | 15 | /// 16 | /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. 17 | /// 18 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 19 | public // polyfill! 20 | sealed class MaybeNullWhenAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class 24 | /// with the specified return value condition. 25 | /// 26 | /// 27 | /// The return value condition. If the method returns this value, the associated parameter may be null. 28 | /// 29 | public MaybeNullWhenAttribute(bool returnValue) 30 | { 31 | ReturnValue = returnValue; 32 | } 33 | 34 | #pragma warning disable SA1623 // Property summary documentation should match accessors - "Gets a value indicating whether..." is not suitable here. 35 | /// 36 | /// Gets the return value condition. 37 | /// 38 | /// The return value condition. 39 | public bool ReturnValue { get; } 40 | #pragma warning restore SA1623 // Property summary documentation should match accessors 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/MemberNotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MemberNotNullAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L130 14 | 15 | /// 16 | /// Specifies that the method or property will ensure that the listed field and property members have not-null values. 17 | /// 18 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] 19 | public // polyfill! 20 | sealed class MemberNotNullAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class 24 | /// with a field or property member. 25 | /// 26 | /// 27 | /// The field or property member that is promised to be not-null. 28 | /// 29 | #pragma warning disable CA1019 // Define accessors for attribute arguments - The member parameter initializes the Members property so we're fine. 30 | public MemberNotNullAttribute(string member) 31 | #pragma warning restore CA1019 // Define accessors for attribute arguments 32 | { 33 | Members = new[] { member }; 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the class 38 | /// with the list of field and property members. 39 | /// 40 | /// 41 | /// The list of field and property members that are promised to be not-null. 42 | /// 43 | public MemberNotNullAttribute(params string[] members) 44 | { 45 | Members = members; 46 | } 47 | 48 | /// 49 | /// Gets field or property member names. 50 | /// 51 | public string[] Members { get; } 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/MemberNotNullWhenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L155 14 | 15 | /// 16 | /// Specifies that the method or property will ensure that the listed field and property members 17 | /// have not-null values when returning with the specified return value condition. 18 | /// 19 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] 20 | public // polyfill! 21 | sealed class MemberNotNullWhenAttribute : Attribute 22 | { 23 | /// 24 | /// Initializes a new instance of the class 25 | /// with the specified return value condition and a field or property member. 26 | /// 27 | /// 28 | /// The return value condition. 29 | /// If the method returns this value, the associated parameter will not be null. 30 | /// 31 | /// 32 | /// The field or property member that is promised to be not-null. 33 | /// 34 | #pragma warning disable CA1019 // Define accessors for attribute arguments - The member parameter initializes the Members property so we're fine. 35 | public MemberNotNullWhenAttribute(bool returnValue, string member) 36 | #pragma warning restore CA1019 // Define accessors for attribute arguments 37 | { 38 | ReturnValue = returnValue; 39 | Members = new[] { member }; 40 | } 41 | 42 | /// 43 | /// Initializes a new instance of the class 44 | /// with the specified return value condition and list of field and property members. 45 | /// 46 | /// 47 | /// The return value condition. 48 | /// If the method returns this value, the associated parameter will not be null. 49 | /// 50 | /// 51 | /// The list of field and property members that are promised to be not-null. 52 | /// 53 | public MemberNotNullWhenAttribute(bool returnValue, params string[] members) 54 | { 55 | ReturnValue = returnValue; 56 | Members = members; 57 | } 58 | 59 | #pragma warning disable SA1623 // Property summary documentation should match accessors - "Gets a value indicating whether..." is not suitable here. 60 | /// 61 | /// Gets the return value condition. 62 | /// 63 | public bool ReturnValue { get; } 64 | #pragma warning restore SA1623 // Property summary documentation should match accessors 65 | 66 | /// 67 | /// Gets field or property member names. 68 | /// 69 | public string[] Members { get; } 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/NotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.NotNullAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L34 14 | 15 | /// 16 | /// Specifies that an output will not be null even if the corresponding type allows it. 17 | /// Specifies that an input argument was not null when the call returns. 18 | /// 19 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] 20 | public // polyfill! 21 | sealed class NotNullAttribute : Attribute 22 | { 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/NotNullIfNotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L81 14 | 15 | /// 16 | /// Specifies that the output will be non-null if the named parameter is non-null. 17 | /// 18 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] 19 | public // polyfill! 20 | sealed class NotNullIfNotNullAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class 24 | /// with the associated parameter name. 25 | /// 26 | /// 27 | /// The associated parameter name. 28 | /// The output will be non-null if the argument to the parameter specified is non-null. 29 | /// 30 | public NotNullIfNotNullAttribute(string parameterName) 31 | { 32 | ParameterName = parameterName; 33 | } 34 | 35 | /// 36 | /// Gets the associated parameter name. 37 | /// 38 | public string ParameterName { get; } 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/NotNullWhenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.NotNullWhenAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L62 14 | 15 | /// 16 | /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. 17 | /// 18 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 19 | public // polyfill! 20 | sealed class NotNullWhenAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class 24 | /// with the specified return value condition. 25 | /// 26 | /// 27 | /// The return value condition. If the method returns this value, the associated parameter may be null. 28 | /// 29 | public NotNullWhenAttribute(bool returnValue) 30 | { 31 | ReturnValue = returnValue; 32 | } 33 | 34 | #pragma warning disable SA1623 // Property summary documentation should match accessors - "Gets a value indicating whether..." is not suitable here. 35 | /// 36 | /// Gets the return value condition. 37 | /// 38 | /// The return value condition. 39 | public bool ReturnValue { get; } 40 | #pragma warning restore SA1623 // Property summary documentation should match accessors 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/RequiresAssemblyFilesAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.RequiresAssemblyFilesAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresAssemblyFilesAttribute.cs 14 | 15 | /// 16 | /// Indicates that the specified member requires assembly files to be on disk. 17 | /// 18 | [AttributeUsage( 19 | AttributeTargets.Constructor | 20 | AttributeTargets.Event | 21 | AttributeTargets.Method | 22 | AttributeTargets.Property, 23 | Inherited = false, 24 | AllowMultiple = false)] 25 | public // polyfill! 26 | sealed class RequiresAssemblyFilesAttribute : Attribute 27 | { 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | public RequiresAssemblyFilesAttribute() 32 | { 33 | } 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | /// 39 | /// A message that contains information about the need for assembly files to be on disk. 40 | /// 41 | public RequiresAssemblyFilesAttribute(string message) 42 | { 43 | Message = message; 44 | } 45 | 46 | /// 47 | /// Gets an optional message that contains information about the need for 48 | /// assembly files to be on disk. 49 | /// 50 | public string? Message { get; } 51 | 52 | /// 53 | /// Gets or sets an optional URL that contains more information about the member, 54 | /// why it requires assembly files to be on disk, and what options a consumer has 55 | /// to deal with it. 56 | /// 57 | public string? Url { get; set; } 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/RequiresDynamicCodeAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System.Diagnostics.CodeAnalysis; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresDynamicCodeAttribute.cs 15 | 16 | /// 17 | /// Indicates that the specified method requires the ability to generate new code at runtime, 18 | /// for example through . 19 | /// 20 | /// 21 | /// This allows tools to understand which methods are unsafe to call when compiling ahead of time. 22 | /// 23 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)] 24 | public // polyfill! 25 | sealed class RequiresDynamicCodeAttribute : Attribute 26 | { 27 | /// 28 | /// Initializes a new instance of the class 29 | /// with the specified message. 30 | /// 31 | /// 32 | /// A message that contains information about the usage of dynamic code. 33 | /// 34 | public RequiresDynamicCodeAttribute(string message) 35 | { 36 | Message = message; 37 | } 38 | 39 | /// 40 | /// Gets a message that contains information about the usage of dynamic code. 41 | /// 42 | public string Message { get; } 43 | 44 | /// 45 | /// Gets or sets an optional URL that contains more information about the method, 46 | /// why it requires dynamic code, and what options a consumer has to deal with it. 47 | /// 48 | public string? Url { get; set; } 49 | } 50 | 51 | #endif 52 | #endif 53 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttribute.cs 14 | 15 | /// 16 | /// Indicates that the specified method requires dynamic access to code that is not referenced 17 | /// statically, for example through . 18 | /// 19 | /// 20 | /// This allows tools to understand which methods are unsafe to call when removing unreferenced 21 | /// code from an application. 22 | /// 23 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)] 24 | public // polyfill! 25 | sealed class RequiresUnreferencedCodeAttribute : Attribute 26 | { 27 | /// 28 | /// Initializes a new instance of the class 29 | /// with the specified message. 30 | /// 31 | /// 32 | /// A message that contains information about the usage of unreferenced code. 33 | /// 34 | public RequiresUnreferencedCodeAttribute(string message) 35 | { 36 | Message = message; 37 | } 38 | 39 | /// 40 | /// Gets a message that contains information about the usage of unreferenced code. 41 | /// 42 | public string Message { get; } 43 | 44 | /// 45 | /// Gets or sets an optional URL that contains more information about the method, 46 | /// why it requires unreferenced code, and what options a consumer has to deal with it. 47 | /// 48 | public string? Url { get; set; } 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/SetsRequiredMembersAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System.Diagnostics.CodeAnalysis; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/SetsRequiredMembersAttribute.cs 15 | 16 | /// 17 | /// Specifies that this constructor sets all required members for the current type, and callers 18 | /// do not need to set any required members themselves. 19 | /// 20 | [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] 21 | public // polyfill! 22 | sealed class SetsRequiredMembersAttribute : Attribute 23 | { 24 | } 25 | 26 | #endif 27 | #endif 28 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System.Diagnostics.CodeAnalysis; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs 15 | 16 | /// Specifies the syntax used in a string. 17 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 18 | public // polyfill! 19 | sealed class StringSyntaxAttribute : Attribute 20 | { 21 | /// The syntax identifier for strings containing composite formats for string formatting. 22 | public const string CompositeFormat = nameof(CompositeFormat); 23 | 24 | /// The syntax identifier for strings containing date format specifiers. 25 | public const string DateOnlyFormat = nameof(DateOnlyFormat); 26 | 27 | /// The syntax identifier for strings containing date and time format specifiers. 28 | public const string DateTimeFormat = nameof(DateTimeFormat); 29 | 30 | /// The syntax identifier for strings containing format specifiers. 31 | public const string EnumFormat = nameof(EnumFormat); 32 | 33 | /// The syntax identifier for strings containing format specifiers. 34 | public const string GuidFormat = nameof(GuidFormat); 35 | 36 | /// The syntax identifier for strings containing JavaScript Object Notation (JSON). 37 | public const string Json = nameof(Json); 38 | 39 | /// The syntax identifier for strings containing numeric format specifiers. 40 | public const string NumericFormat = nameof(NumericFormat); 41 | 42 | /// The syntax identifier for strings containing regular expressions. 43 | public const string Regex = nameof(Regex); 44 | 45 | /// The syntax identifier for strings containing time format specifiers. 46 | public const string TimeOnlyFormat = nameof(TimeOnlyFormat); 47 | 48 | /// The syntax identifier for strings containing format specifiers. 49 | public const string TimeSpanFormat = nameof(TimeSpanFormat); 50 | 51 | /// The syntax identifier for strings containing URIs. 52 | public const string Uri = nameof(Uri); 53 | 54 | /// The syntax identifier for strings containing XML. 55 | public const string Xml = nameof(Xml); 56 | 57 | /// Initializes a new instance of the class 58 | /// with the identifier of the syntax used. 59 | /// The syntax identifier. 60 | public StringSyntaxAttribute(string syntax) 61 | { 62 | Syntax = syntax; 63 | Arguments = Array.Empty(); 64 | } 65 | 66 | /// Initializes a new instance of the class 67 | /// with the identifier of the syntax used. 68 | /// The syntax identifier. 69 | /// Optional arguments associated with the specific syntax employed. 70 | public StringSyntaxAttribute(string syntax, params object?[] arguments) 71 | { 72 | Syntax = syntax; 73 | Arguments = arguments; 74 | } 75 | 76 | /// Gets the identifier of the syntax used. 77 | public string Syntax { get; } 78 | 79 | /// Gets optional arguments associated with the specific syntax employed. 80 | public object?[] Arguments { get; } 81 | } 82 | 83 | #endif 84 | #endif 85 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics.CodeAnalysis; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs 14 | 15 | /// 16 | /// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a 17 | /// single code artifact. 18 | /// 19 | /// 20 | /// is different than 21 | /// in that it doesn't have a 22 | /// . So it is always preserved in the compiled assembly. 23 | /// 24 | [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] 25 | public // polyfill! 26 | sealed class UnconditionalSuppressMessageAttribute : Attribute 27 | { 28 | /// 29 | /// Initializes a new instance of the 30 | /// class, specifying the category of the tool and the identifier for an analysis rule. 31 | /// 32 | /// The category for the attribute. 33 | /// The identifier of the analysis rule the attribute applies to. 34 | public UnconditionalSuppressMessageAttribute(string category, string checkId) 35 | { 36 | Category = category; 37 | CheckId = checkId; 38 | } 39 | 40 | /// 41 | /// Gets the category identifying the classification of the attribute. 42 | /// 43 | /// 44 | /// The property describes the tool or tool analysis category 45 | /// for which a message suppression attribute applies. 46 | /// 47 | public string Category { get; } 48 | 49 | /// 50 | /// Gets the identifier of the analysis tool rule to be suppressed. 51 | /// 52 | /// 53 | /// Concatenated together, the and 54 | /// properties form a unique check identifier. 55 | /// 56 | public string CheckId { get; } 57 | 58 | /// 59 | /// Gets or sets the scope of the code that is relevant for the attribute. 60 | /// 61 | /// 62 | /// The Scope property is an optional argument that specifies the metadata scope for which 63 | /// the attribute is relevant. 64 | /// 65 | public string? Scope { get; set; } 66 | 67 | /// 68 | /// Gets or sets a fully qualified path that represents the target of the attribute. 69 | /// 70 | /// 71 | /// The property is an optional argument identifying the analysis target 72 | /// of the attribute. An example value is "System.IO.Stream.ctor():System.Void". 73 | /// Because it is fully qualified, it can be long, particularly for targets such as parameters. 74 | /// The analysis tool user interface should be capable of automatically formatting the parameter. 75 | /// 76 | public string? Target { get; set; } 77 | 78 | /// 79 | /// Gets or sets an optional argument expanding on exclusion criteria. 80 | /// 81 | /// 82 | /// The property is an optional argument that specifies additional 83 | /// exclusion where the literal metadata target is not sufficiently precise. For example, 84 | /// the cannot be applied within a method, 85 | /// and it may be desirable to suppress a violation against a statement in the method that will 86 | /// give a rule violation, but not against all statements in the method. 87 | /// 88 | public string? MessageId { get; set; } 89 | 90 | /// 91 | /// Gets or sets the justification for suppressing the code analysis message. 92 | /// 93 | public string? Justification { get; set; } 94 | } 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.UnscopedRefAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System.Diagnostics.CodeAnalysis; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs 15 | 16 | /// 17 | /// Used to indicate a byref escapes and is not scoped. 18 | /// 19 | /// 20 | /// 21 | /// There are several cases where the C# compiler treats a as implicitly 22 | /// - where the compiler does not allow the to escape the method. 23 | /// 24 | /// 25 | /// For example: 26 | /// 27 | /// for instance methods. 28 | /// parameters that refer to types. 29 | /// parameters. 30 | /// 31 | /// 32 | /// 33 | /// This attribute is used in those instances where the should be allowed to escape. 34 | /// 35 | /// 36 | /// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for 37 | /// API authors to understand the lifetime implications of applying this attribute and how it may impact their users. 38 | /// 39 | /// 40 | [AttributeUsage( 41 | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, 42 | AllowMultiple = false, 43 | Inherited = false)] 44 | public // polyfill! 45 | sealed class UnscopedRefAttribute : Attribute 46 | { 47 | /// 48 | /// Initializes a new instance of the class. 49 | /// 50 | public UnscopedRefAttribute() 51 | { 52 | } 53 | } 54 | 55 | #endif 56 | #endif 57 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/StackTraceHiddenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.StackTraceHiddenAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Diagnostics; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTraceHiddenAttribute.cs 14 | 15 | /// 16 | /// Types and methods attributed with StackTraceHidden will be omitted from the stack trace text returned by 17 | /// . 18 | /// 19 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct, Inherited = false)] 20 | public // polyfill! 21 | sealed class StackTraceHiddenAttribute : Attribute 22 | { 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | public StackTraceHiddenAttribute() 27 | { 28 | } 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Diagnostics/TraceFormat.cs: -------------------------------------------------------------------------------- 1 | #if !NET6_0_OR_GREATER 2 | 3 | // Licensed to the .NET Foundation under one or more agreements. 4 | // The .NET Foundation licenses this file to you under the MIT license. 5 | namespace System.Diagnostics; 6 | 7 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs#L186 8 | // TraceFormat is used to specify options for how the string-representation of a StackTrace should be generated. 9 | internal enum TraceFormat 10 | { 11 | Normal, 12 | TrailingNewLine, // include a trailing new line character 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/ISpanFormattable.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_USE_SPAN 2 | #if NET6_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.ISpanFormattable))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/ISpanFormattable.cs 15 | 16 | /// Provides functionality to format the string representation of an object into a span. 17 | public // polyfill!- 18 | interface ISpanFormattable : IFormattable 19 | { 20 | /// Tries to format the value of the current instance into the provided span of characters. 21 | /// When this method returns, this instance's value formatted as a span of characters. 22 | /// When this method returns, the number of characters that were written in . 23 | /// A span containing the characters that represent a standard or custom format string that defines the acceptable format for . 24 | /// An optional object that supplies culture-specific formatting information for . 25 | /// if the formatting was successful; otherwise, . 26 | /// 27 | /// An implementation of this interface should produce the same string of characters as an implementation of 28 | /// on the same type. 29 | /// TryFormat should return false only if there is not enough space in the destination buffer. Any other failures should throw an exception. 30 | /// 31 | bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider); 32 | } 33 | 34 | #endif 35 | #endif 36 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Index.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Index))] 5 | #endif 6 | 7 | #elif POLYKIT_USE_VALUETUPLE 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | using System.Diagnostics.CodeAnalysis; 12 | using System.Runtime.CompilerServices; 13 | 14 | namespace System; 15 | 16 | #pragma warning disable CA1305 // Specify IFormatProvider - Preserving original code. 17 | #pragma warning disable CA1815 // Override equals and operator equals on value types - Preserving original code. 18 | #pragma warning disable CA2225 // Operator overloads have named alternates - Preserving original code. 19 | #pragma warning disable CA2231 // Overload operator equals on overriding value type Equals - Preserving original code. 20 | #pragma warning disable SA1201 // Elements should appear in the correct order - Preserving original code. 21 | #pragma warning disable SA1623 // Property summary documentation should match accessors - Copied from dotnet/runtime. 22 | #pragma warning disable SA1642 // Constructor summary documentation should begin with standard text - Copied from dotnet/runtime. 23 | 24 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Index.cs 25 | 26 | /// 27 | /// Represent a type can be used to index a collection either from the start or the end. 28 | /// 29 | /// 30 | /// Index is used by the C# compiler to support the index syntax. 31 | /// 32 | /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ; 33 | /// int lastElement = someArray[^1]; // lastElement = 5 34 | /// 35 | /// 36 | public // polyfill! 37 | readonly struct Index : IEquatable 38 | { 39 | private readonly int _value; 40 | 41 | /// 42 | /// Construct an Index using a value and indicating if the index is from the start or from the end. 43 | /// 44 | /// The index value. it has to be zero or positive number. 45 | /// Indicating if the index is from the start or from the end. 46 | /// is negative. 47 | /// 48 | /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element. 49 | /// 50 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 51 | public Index(int value, bool fromEnd = false) 52 | { 53 | if (value < 0) 54 | { 55 | ThrowValueArgumentOutOfRange_NeedNonNegNumException(); 56 | } 57 | 58 | _value = fromEnd ? ~value : value; 59 | } 60 | 61 | // The following private constructors mainly created for perf reason to avoid the checks 62 | private Index(int value) 63 | { 64 | _value = value; 65 | } 66 | 67 | /// 68 | /// Create an Index pointing at first element. 69 | /// 70 | public static Index Start => new(0); 71 | 72 | /// 73 | /// Create an Index pointing at beyond last element. 74 | /// 75 | public static Index End => new(~0); 76 | 77 | /// 78 | /// Create an Index from the start at the position indicated by the value. 79 | /// 80 | /// The index value from the start. 81 | /// A newly-created Index. 82 | /// is negative. 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | public static Index FromStart(int value) 85 | { 86 | if (value < 0) 87 | { 88 | ThrowValueArgumentOutOfRange_NeedNonNegNumException(); 89 | } 90 | 91 | return new Index(value); 92 | } 93 | 94 | /// 95 | /// Create an Index from the end at the position indicated by the value. 96 | /// 97 | /// The index value from the end. 98 | /// is negative. 99 | /// A newly-created Index. 100 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 101 | public static Index FromEnd(int value) 102 | { 103 | if (value < 0) 104 | { 105 | ThrowValueArgumentOutOfRange_NeedNonNegNumException(); 106 | } 107 | 108 | return new Index(~value); 109 | } 110 | 111 | /// 112 | /// Gets the index value. 113 | /// 114 | public int Value => _value switch 115 | { 116 | < 0 => ~_value, 117 | _ => _value, 118 | }; 119 | 120 | /// Indicates whether the index is from the start or the end. 121 | public bool IsFromEnd => _value < 0; 122 | 123 | /// 124 | /// Calculate the offset from the start using the giving collection length. 125 | /// 126 | /// The length of the collection that the Index will be used with. 127 | /// This has to be a positive value. 128 | /// The offset from the start of the collection. 129 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 130 | public int GetOffset(int length) 131 | { 132 | var offset = _value; 133 | if (IsFromEnd) 134 | { 135 | // offset = length - (~value) 136 | // offset = length + (~(~value) + 1) 137 | // offset = length + value + 1 138 | offset += length + 1; 139 | } 140 | 141 | return offset; 142 | } 143 | 144 | /// 145 | /// Indicates whether the current Index object is equal to another object of the same type. 146 | /// 147 | /// An object to compare with this object. 148 | /// if the objects are equal; 149 | /// otherwise, . 150 | public override bool Equals([NotNullWhen(true)] object? obj) => obj is Index other && _value == other._value; 151 | 152 | /// 153 | /// Indicates whether the current Index object is equal to another Index object. 154 | /// 155 | /// An object to compare with this object. 156 | /// if the objects are equal; 157 | /// otherwise, . 158 | public bool Equals(Index other) => _value == other._value; 159 | 160 | /// 161 | /// Returns the hash code for this instance. 162 | /// 163 | /// The hash code. 164 | public override int GetHashCode() => _value; 165 | 166 | /// 167 | /// Converts an integer number to an Index. 168 | /// 169 | /// The number to convert. 170 | public static implicit operator Index(int value) => FromStart(value); 171 | 172 | /// 173 | /// Converts the value of the current Index object to its equivalent string representation. 174 | /// 175 | /// A string representation of the current instance. 176 | public override string ToString() => IsFromEnd 177 | ? '^' + Value.ToString() 178 | : ((uint)Value).ToString(); 179 | 180 | private static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() 181 | { 182 | throw new ArgumentOutOfRangeException("value", "Non-negative number required."); 183 | } 184 | } 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Linq/PolyKitEnumerable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace System.Linq; 5 | 6 | /// 7 | /// Provides extension methods for enumerables 8 | /// 9 | public // polyfill! 10 | static class PolyKitEnumerable 11 | { 12 | // Licensed to the .NET Foundation under one or more agreements. 13 | // The .NET Foundation licenses this file to you under the MIT license. 14 | /* Adapted from System.Linq.Enumerable.TryGetNonEnumeratedCount in .NET 8.0.0 15 | * https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Linq/src/System/Linq/Count.cs#L75 16 | * without the check for IListProvider, as it is an internal interface in System.Linq. 17 | */ 18 | // Conditional compilation inside XML doc blocks is not supported. 19 | // https://github.com/dotnet/csharplang/discussions/295 20 | #if NET6_0_OR_GREATER 21 | /// 22 | /// Attempts to determine the number of elements in a sequence without forcing an enumeration. 23 | /// 24 | /// The type of the elements of . 25 | /// A sequence that contains elements to be counted. 26 | /// When this method returns, contains the count of if successful, 27 | /// or zero if the method failed to determine the count. 28 | /// if the count of can be determined without enumeration; 29 | /// otherwise, . 30 | /// 31 | /// On .NET 6.0 and later, this method just calls . 32 | /// The following remarks only refer to the implementation for older frameworks. 33 | /// The method performs a series of type tests, identifying common subtypes whose 34 | /// count can be determined without enumerating; this includes , 35 | /// , and . 36 | /// The method is typically a constant-time operation, but ultimately this depends on the complexity 37 | /// characteristics of the underlying collection implementation. 38 | /// 39 | #else 40 | /// 41 | /// Attempts to determine the number of elements in a sequence without forcing an enumeration. 42 | /// 43 | /// The type of the elements of . 44 | /// A sequence that contains elements to be counted. 45 | /// When this method returns, contains the count of if successful, 46 | /// or zero if the method failed to determine the count. 47 | /// if the count of can be determined without enumeration; 48 | /// otherwise, . 49 | /// 50 | /// On .NET 6.0 and later, this method just calls Enumerable.TryGetNonEnumeratedCount<TSource>. 51 | /// The following remarks only refer to the implementation for older frameworks. 52 | /// The method performs a series of type tests, identifying common subtypes whose 53 | /// count can be determined without enumerating; this includes , 54 | /// , and . 55 | /// The method is typically a constant-time operation, but ultimately this depends on the complexity 56 | /// characteristics of the underlying collection implementation. 57 | /// 58 | #endif 59 | public static bool TryGetCountWithoutEnumerating(this IEnumerable source, out int count) 60 | { 61 | #if NET6_0_OR_GREATER 62 | // System.Linq will throw ArgumentNullException if necessary 63 | return source.TryGetNonEnumeratedCount(out count); 64 | #else 65 | switch (source) 66 | { 67 | case null: 68 | throw new ArgumentNullException(nameof(source)); 69 | case ICollection genericCollection: 70 | count = genericCollection.Count; 71 | return true; 72 | case ICollection collection: 73 | count = collection.Count; 74 | return true; 75 | default: 76 | count = 0; 77 | return false; 78 | } 79 | #endif 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/PolyKitExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0_OR_GREATER 2 | 3 | namespace System; 4 | 5 | /// 6 | /// Provides extension methods for exceptions to support polyfilled features. 7 | /// 8 | public // polyfill! 9 | static class PolyKitExceptionExtensions 10 | { 11 | /// 12 | /// Gets a string representation of the immediate frames on the call stack. 13 | /// This method returns the value of the exception's StackTrace property. 14 | /// 15 | /// The on which this method is called. 16 | /// A string that describes the immediate frames of the call stack. 17 | public static string? GetStackTraceHidingFrames(this Exception @this) => @this.StackTrace; 18 | } 19 | 20 | #else 21 | 22 | // Licensed to the .NET Foundation under one or more agreements. 23 | // The .NET Foundation licenses this file to you under the MIT license. 24 | using System.Diagnostics; 25 | 26 | namespace System; 27 | 28 | /// 29 | /// Provides extension methods for exceptions to support polyfilled features. 30 | /// 31 | public // polyfill! 32 | static class PolyKitExceptionExtensions 33 | { 34 | /// 35 | /// Gets a string representation of the immediate frames on the call stack, 36 | /// hiding stack frames marked with . 37 | /// 38 | /// The on which this method is called. 39 | /// A string that describes the immediate frames of the call stack. 40 | /// 41 | /// Unlike , this method honors the presence of 42 | /// on stack frame methods. 43 | /// There are, however, some limitations: 44 | /// 45 | /// the returned stack trace description is always in English, irrespective of current culture; 46 | /// external exception stack trace boundaries ("End of stack trace from previous location" lines) are missing from the returned string. 47 | /// 48 | /// 49 | /* Adapted from System.Exception.GetStackTrace() in .NET 8.0.0 50 | * https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Exception.cs#L229 51 | */ 52 | // Do not include a trailing newline for backwards compatibility 53 | public static string GetStackTraceHidingFrames(this Exception @this) 54 | => new StackTrace(@this, fNeedFileInfo: true).ToStringHidingFrames(TraceFormat.Normal); 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Range.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Range))] 5 | #endif 6 | 7 | #elif POLYKIT_USE_VALUETUPLE 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | using System.Diagnostics.CodeAnalysis; 12 | using System.Runtime.CompilerServices; 13 | 14 | namespace System; 15 | 16 | #pragma warning disable CA1815 // Override equals and operator equals on value types - Preserving original code. 17 | #pragma warning disable CA2231 // Overload operator equals on overriding value type Equals - Preserving original code. 18 | #pragma warning disable SA1201 // Elements should appear in the correct order - Preserving original code. 19 | #pragma warning disable SA1204 // Static elements should appear before instance elements - Preserving original code. 20 | #pragma warning disable SA1623 // Property summary documentation should match accessors - Copied from dotnet/runtime. 21 | #pragma warning disable SA1642 // Constructor summary documentation should begin with standard text - Copied from dotnet/runtime. 22 | 23 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Range.cs 24 | 25 | /// 26 | /// Represent a range that has start and end indexes. 27 | /// 28 | /// 29 | /// Range is used by the C# compiler to support the range syntax. 30 | /// 31 | /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 }; 32 | /// int[] subArray1 = someArray[0..2]; // { 1, 2 } 33 | /// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 } 34 | /// 35 | /// 36 | public // polyfill! 37 | readonly struct Range : IEquatable 38 | { 39 | /// 40 | /// Represents the inclusive start index of the Range. 41 | /// 42 | public Index Start { get; } 43 | 44 | /// 45 | /// Represents the exclusive end index of the Range. 46 | /// 47 | public Index End { get; } 48 | 49 | /// 50 | /// Construct a Range object using the start and end indexes. 51 | /// 52 | /// The inclusive start index of the range. 53 | /// The exclusive end index of the range. 54 | public Range(Index start, Index end) 55 | { 56 | Start = start; 57 | End = end; 58 | } 59 | 60 | /// 61 | /// Indicates whether the current Range object is equal to another object of the same type. 62 | /// 63 | /// An object to compare with this object. 64 | /// if the objects are equal; 65 | /// otherwise, . 66 | public override bool Equals([NotNullWhen(true)] object? obj) 67 | => obj is Range other && other.Start.Equals(Start) && other.End.Equals(End); 68 | 69 | /// 70 | /// Indicates whether the current Range object is equal to another Range object. 71 | /// 72 | /// An object to compare with this object. 73 | /// if the objects are equal; 74 | /// otherwise, . 75 | public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End); 76 | 77 | /// 78 | /// Returns the hash code for this instance. 79 | /// 80 | /// The hash code. 81 | public override int GetHashCode() => HashCode.Combine(Start.GetHashCode(), End.GetHashCode()); 82 | 83 | /// 84 | /// Converts the value of the current Range object to its equivalent string representation. 85 | /// 86 | /// A string representation of the current instance. 87 | public override string ToString() => Start + ".." + End; 88 | 89 | /// 90 | /// Create a Range object starting from start index to the end of the collection. 91 | /// 92 | /// The inclusive start index of the range. 93 | /// A newly-created Range. 94 | public static Range StartAt(Index start) => new(start, Index.End); 95 | 96 | /// 97 | /// Create a Range object starting from first element in the collection to the end Index. 98 | /// 99 | /// The exclusive end index of the range. 100 | /// A newly-created Range. 101 | public static Range EndAt(Index end) => new(Index.Start, end); 102 | 103 | /// 104 | /// Create a Range object starting from first element to the end. 105 | /// 106 | /// A newly-created Range. 107 | public static Range All => new(Index.Start, Index.End); 108 | 109 | /// 110 | /// Calculate the start offset and length of range object using a collection length. 111 | /// 112 | /// The length of the collection that the range will be used with. This has to be a positive value. 113 | /// A containing the start offset and length of the range. 114 | /// The range exceeds the boundaries of the collection. 115 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 116 | public (int Offset, int Length) GetOffsetAndLength(int length) 117 | { 118 | var start = Start.GetOffset(length); 119 | var end = End.GetOffset(length); 120 | if ((uint)end > (uint)length || (uint)start > (uint)end) 121 | { 122 | ThrowArgumentOutOfRangeException(); 123 | } 124 | 125 | return (start, end - start); 126 | } 127 | 128 | private static void ThrowArgumentOutOfRangeException() 129 | { 130 | throw new ArgumentOutOfRangeException("length"); 131 | } 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP1_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.AsyncMethodBuilderAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.CompilerServices; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs 14 | 15 | /// 16 | /// Indicates the type of the async method builder that should be used by a language compiler to 17 | /// build the attributed async method or to build the attributed type when used as the return type 18 | /// of an async method. 19 | /// 20 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Method, Inherited = false, AllowMultiple = false)] 21 | public // polyfill! 22 | sealed class AsyncMethodBuilderAttribute : Attribute 23 | { 24 | /// Initializes a new instance of the class. 25 | /// The of the associated builder. 26 | public AsyncMethodBuilderAttribute(Type builderType) 27 | { 28 | BuilderType = builderType; 29 | } 30 | 31 | /// Gets the of the associated builder. 32 | public Type BuilderType { get; } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/CallerArgumentExpressionAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP3_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.CompilerServices; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallerArgumentExpressionAttribute.cs 14 | 15 | /// 16 | /// Indicates that a parameter captures the expression passed for another parameter as a string. 17 | /// 18 | [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] 19 | public // polyfill! 20 | sealed class CallerArgumentExpressionAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The name of the parameter whose expression should be captured as a string. 26 | public CallerArgumentExpressionAttribute(string parameterName) 27 | { 28 | ParameterName = parameterName; 29 | } 30 | 31 | /// 32 | /// Gets the name of the parameter whose expression should be captured as a string. 33 | /// 34 | /// The name of the parameter whose expression should be captured. 35 | public string ParameterName { get; } 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/CompilerFeatureRequiredAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | namespace System.Runtime.CompilerServices; 13 | 14 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompilerFeatureRequiredAttribute.cs 15 | 16 | /// 17 | /// Indicates that compiler support for a particular feature is required for the location where this attribute is applied. 18 | /// 19 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] 20 | public // polyfill! 21 | sealed class CompilerFeatureRequiredAttribute : Attribute 22 | { 23 | /// 24 | /// The used for the ref structs C# feature. 25 | /// 26 | public const string RefStructs = nameof(RefStructs); 27 | 28 | /// 29 | /// The used for the required members C# feature. 30 | /// 31 | public const string RequiredMembers = nameof(RequiredMembers); 32 | 33 | /// 34 | /// Initializes a new instance of the class. 35 | /// 36 | /// The name of the required compiler feature. 37 | public CompilerFeatureRequiredAttribute(string featureName) 38 | { 39 | FeatureName = featureName; 40 | } 41 | 42 | /// 43 | /// Gets the name of the compiler feature. 44 | /// 45 | public string FeatureName { get; } 46 | 47 | /// 48 | /// Gets a value indicating whether the compiler can choose to allow access to the location where this attribute is applied 49 | /// if it does not understand . 50 | /// 51 | public bool IsOptional { get; init; } 52 | } 53 | 54 | #endif 55 | #endif 56 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/InterpolatedStringHandlerArgumentAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.CompilerServices; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/InterpolatedStringHandlerArgumentAttribute.cs 14 | 15 | /// 16 | /// Indicates which arguments to a method involving an interpolated string handler should be passed to that handler. 17 | /// 18 | [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] 19 | public // polyfill! 20 | sealed class InterpolatedStringHandlerArgumentAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The name of the argument that should be passed to the handler. 26 | /// The empty string may be used as the name of the receiver in an instance method. 27 | #pragma warning disable CA1019 // Define accessors for attribute arguments - Preserving original code. 28 | public InterpolatedStringHandlerArgumentAttribute(string argument) 29 | #pragma warning restore CA1019 // Define accessors for attribute arguments 30 | { 31 | Arguments = new string[] { argument }; 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | /// The names of the arguments that should be passed to the handler. 38 | /// The empty string may be used as the name of the receiver in an instance method. 39 | public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) 40 | { 41 | Arguments = arguments; 42 | } 43 | 44 | /// Gets the names of the arguments that should be passed to the handler. 45 | /// The empty string may be used as the name of the receiver in an instance method. 46 | public string[] Arguments { get; } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/InterpolatedStringHandlerAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.CompilerServices; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/InterpolatedStringHandlerAttribute.cs 14 | 15 | /// 16 | /// Indicates the attributed type is to be used as an interpolated string handler. 17 | /// 18 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] 19 | public // polyfill! 20 | sealed class InterpolatedStringHandlerAttribute : Attribute 21 | { 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | public InterpolatedStringHandlerAttribute() 26 | { 27 | } 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/IsExternalInit.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.IsExternalInit))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | using System.ComponentModel; 12 | 13 | namespace System.Runtime.CompilerServices; 14 | 15 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/IsExternalInit.cs 16 | 17 | /// 18 | /// Reserved to be used by the compiler for tracking metadata. 19 | /// This class should not be used by developers in source code. 20 | /// 21 | [EditorBrowsable(EditorBrowsableState.Never)] 22 | public // polyfill! 23 | static class IsExternalInit 24 | { 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/ModuleInitializerAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.ModuleInitializerAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.CompilerServices; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ModuleInitializerAttribute.cs 14 | 15 | /// 16 | /// Used to indicate to the compiler that a method should be called 17 | /// in its containing module's initializer. 18 | /// 19 | /// 20 | /// When one or more valid methods with this attribute are found in a compilation, 21 | /// the compiler will emit a module initializer which calls each of the attributed methods. 22 | /// Certain requirements are imposed on any method targeted with this attribute: 23 | /// 24 | /// The method must be . 25 | /// The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. 26 | /// The method must be parameterless. 27 | /// The method must return . 28 | /// The method must not be generic or be contained in a generic type. 29 | /// The method's effective accessibility must be or . 30 | /// 31 | /// For more information, see the specification for module initializers. 33 | /// 34 | [AttributeUsage(AttributeTargets.Method, Inherited = false)] 35 | public // polyfill! 36 | sealed class ModuleInitializerAttribute : Attribute 37 | { 38 | /// 39 | /// Initializes a new instance of the class. 40 | /// 41 | public ModuleInitializerAttribute() 42 | { 43 | } 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/RequiredMemberAttribute.cs: -------------------------------------------------------------------------------- 1 | #if POLYKIT_NETSDK7_0_OR_GREATER 2 | #if NET7_0_OR_GREATER 3 | 4 | #if POLYKIT_PUBLIC 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.RequiredMemberAttribute))] 6 | #endif 7 | 8 | #else 9 | 10 | // Licensed to the .NET Foundation under one or more agreements. 11 | // The .NET Foundation licenses this file to you under the MIT license. 12 | using System.ComponentModel; 13 | 14 | namespace System.Runtime.CompilerServices; 15 | 16 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RequiredMemberAttribute.cs 17 | 18 | /// Specifies that a type has required members or that a member is required. 19 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 20 | [EditorBrowsable(EditorBrowsableState.Never)] 21 | public // polyfill! 22 | sealed class RequiredMemberAttribute : Attribute 23 | { 24 | } 25 | 26 | #endif 27 | #endif 28 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.SkipLocalsInitAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.CompilerServices; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs 14 | 15 | /// 16 | /// Used to indicate to the compiler that the .locals init 17 | /// flag should not be set in method headers. 18 | /// 19 | /// 20 | /// This attribute is unsafe because it may reveal uninitialized memory to 21 | /// the application in certain instances (e.g., reading from uninitialized 22 | /// stackalloc'd memory). If applied to a method directly, the attribute 23 | /// applies to that method and all nested functions (lambdas, local 24 | /// functions) below it. If applied to a type or module, it applies to all 25 | /// methods nested inside. This attribute is intentionally not permitted on 26 | /// assemblies. Use at the module level instead to apply to multiple type 27 | /// declarations. 28 | /// 29 | [AttributeUsage( 30 | AttributeTargets.Module 31 | | AttributeTargets.Class 32 | | AttributeTargets.Struct 33 | | AttributeTargets.Interface 34 | | AttributeTargets.Constructor 35 | | AttributeTargets.Method 36 | | AttributeTargets.Property 37 | | AttributeTargets.Event, 38 | Inherited = false)] 39 | public // polyfill! 40 | sealed class SkipLocalsInitAttribute : Attribute 41 | { 42 | /// 43 | /// Initializes a new instance of the class. 44 | /// 45 | public SkipLocalsInitAttribute() 46 | { 47 | } 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/InteropServices/UnmanagedCallersOnlyAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET5_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | #pragma warning disable CA1051 // Do not declare visible instance fields - Consistency with original source. 10 | #pragma warning disable CS0649 // Field is never assigned to - Consistency with original source. 11 | #pragma warning disable SA1401 // Fields should be private - Consistency with original source. 12 | 13 | // Licensed to the .NET Foundation under one or more agreements. 14 | // The .NET Foundation licenses this file to you under the MIT license. 15 | namespace System.Runtime.InteropServices; 16 | 17 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/UnmanagedCallersOnlyAttribute.cs 18 | 19 | /// 20 | /// Any method marked with this attribute can be directly called from native code. 21 | /// The function token can be loaded to a local variable using the 22 | /// address-of 23 | /// operator in C# and passed as a callback to a native method. 24 | /// 25 | /// 26 | /// Methods marked with this attribute have the following restrictions: 27 | /// 28 | /// Method must be marked . 29 | /// Must not be called from managed code. 30 | /// Must only have blittable arguments. 31 | /// 32 | /// 33 | [AttributeUsage(AttributeTargets.Method, Inherited = false)] 34 | public // polyfill! 35 | sealed class UnmanagedCallersOnlyAttribute : Attribute 36 | { 37 | /// 38 | /// Optional. If omitted, the runtime will use the default platform calling convention. 39 | /// 40 | /// 41 | /// Supplied types must be from the official "System.Runtime.CompilerServices" namespace and 42 | /// be of the form "CallConvXXX". 43 | /// 44 | public Type[]? CallConvs; 45 | 46 | /// 47 | /// Optional. If omitted, no named export is emitted during compilation. 48 | /// 49 | public string? EntryPoint; 50 | 51 | /// 52 | /// Initializes a new instance of the class. 53 | /// 54 | public UnmanagedCallersOnlyAttribute() 55 | { 56 | } 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/PolyKit.Polyfills/System/Runtime/Versioning/RequiresPreviewFeaturesAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0_OR_GREATER 2 | 3 | #if POLYKIT_PUBLIC 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.RequiresPreviewFeaturesAttribute))] 5 | #endif 6 | 7 | #else 8 | 9 | // Licensed to the .NET Foundation under one or more agreements. 10 | // The .NET Foundation licenses this file to you under the MIT license. 11 | namespace System.Runtime.Versioning; 12 | 13 | // https://github.com/dotnet/runtime/blob/v8.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/RequiresPreviewFeaturesAttribute.cs 14 | 15 | /// 16 | /// Indicates that an API is in preview. 17 | /// This attribute allows call sites to be flagged with a diagnostic that indicates that a preview feature is used. 18 | /// Authors can use this attribute to ship preview features in their assemblies. 19 | /// 20 | /// 21 | /// See also Preview Features. 22 | /// 23 | [AttributeUsage( 24 | AttributeTargets.Assembly | 25 | AttributeTargets.Module | 26 | AttributeTargets.Class | 27 | AttributeTargets.Interface | 28 | AttributeTargets.Delegate | 29 | AttributeTargets.Struct | 30 | AttributeTargets.Enum | 31 | AttributeTargets.Constructor | 32 | AttributeTargets.Method | 33 | AttributeTargets.Property | 34 | AttributeTargets.Field | 35 | AttributeTargets.Event, 36 | Inherited = false)] 37 | public // polyfill! 38 | sealed class RequiresPreviewFeaturesAttribute : Attribute 39 | { 40 | /// 41 | /// Initializes a new instance of the class. 42 | /// 43 | public RequiresPreviewFeaturesAttribute() 44 | { 45 | } 46 | 47 | /// 48 | /// Initializes a new instance of the class with the specified message. 49 | /// 50 | /// An optional message associated with this attribute instance. 51 | public RequiresPreviewFeaturesAttribute(string? message) 52 | { 53 | Message = message; 54 | } 55 | 56 | /// 57 | /// Gets the optional message associated with this attribute instance. 58 | /// 59 | public string? Message { get; } 60 | 61 | /// 62 | /// Gets or sets the optional URL associated with this attribute instance. 63 | /// 64 | public string? Url { get; set; } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/PolyKit/PolyKit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Provides a set of polyfills that can be shared among projects. 5 | netstandard2.0;netstandard2.1;net462;net47;net6.0;net7.0;net8.0 6 | 7 | 8 | 9 | 10 | 11 | true 12 | high 13 | 14 | 15 | 19 | 20 | netstandard2.0;net462;net47 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | net462 32 | 33 | 34 | 35 | 36 | 37 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | true 52 | true 53 | true 54 | snupkg 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /stylecop.json: -------------------------------------------------------------------------------- 1 | // See https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/Configuration.md 2 | // for a reference guide to the contents of this file. 3 | { 4 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 5 | 6 | "settings": { 7 | 8 | "spacingRules": { 9 | }, 10 | 11 | "readabilityRules": { 12 | "allowBuiltInTypeAliases": true 13 | }, 14 | 15 | "orderingRules": { 16 | "elementOrder": [ "kind", "accessibility", "constant", "static", "readonly" ], 17 | "systemUsingDirectivesFirst": true, 18 | "usingDirectivesPlacement": "outsideNamespace", 19 | "blankLinesBetweenUsingGroups": "omit" 20 | }, 21 | 22 | "namingRules": { 23 | "allowCommonHungarianPrefixes": true, 24 | "allowedHungarianPrefixes": [], 25 | "allowedNamespaceComponents": [], 26 | "includeInferredTupleElementNames": false, 27 | "tupleElementNameCasing": "PascalCase" 28 | }, 29 | 30 | "maintainabilityRules": { 31 | "topLevelTypes": [ "class", "interface", "struct", "enum", "delegate" ] 32 | }, 33 | 34 | "layoutRules": { 35 | "newlineAtEndOfFile": "require", 36 | "allowConsecutiveUsings": true, 37 | "allowDoWhileOnClosingBrace": true 38 | }, 39 | 40 | "documentationRules": { 41 | "companyName": "Tenacom", 42 | "copyrightText": "Copyright (C) {companyName} and contributors. Licensed under the MIT license.\r\nSee the LICENSE file in the project root for full license information.", 43 | "xmlHeader": false, 44 | "documentInterfaces": true, 45 | "documentExposedElements": true, 46 | "documentInternalElements": false, 47 | "documentPrivateElements": false, 48 | "documentPrivateFields": false, 49 | "documentationCulture": "en-US", 50 | "fileNamingConvention": "metadata", 51 | "excludeFromPunctuationCheck": [ "exception", "seealso" ] 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "3.0", 4 | "assemblyVersion": { 5 | "precision": "major" 6 | }, 7 | "nuGetPackageVersion": { 8 | "semVer": 2.0 9 | }, 10 | "publicReleaseRefSpec": [ 11 | "^refs/heads/main$", 12 | "^refs/heads/v\\d+\\.\\d+$" 13 | ], 14 | "release": { 15 | "firstUnstableTag": "preview" 16 | }, 17 | "pathFilters": [] 18 | } --------------------------------------------------------------------------------