diff --git a/.editorconfig b/.editorconfig index f8ad6ea8e56..711ffa681ab 100644 --- a/.editorconfig +++ b/.editorconfig @@ -78,7 +78,8 @@ csharp_prefer_static_local_function = true:suggestion dotnet_diagnostic.IDE0010.severity = suggestion # IDE0010: Add missing cases to switch statement dotnet_style_object_initializer = true:suggestion # IDE0017: Use object initializers csharp_style_inlined_variable_declaration = true:suggestion # IDE0018: Inline variable declaration -dotnet_style_collection_initializer = true:suggestion # IDE0028: Use collection initializers +dotnet_style_collection_initializer = true:suggestion # IDE0028: Use collection initializers or expressions +dotnet_style_prefer_collection_expression = true:suggestion # IDE0028: Use collection initializers or expressions dotnet_style_prefer_auto_properties = true:suggestion # IDE0032: Use auto-implemented property dotnet_style_explicit_tuple_names = true:suggestion # IDE0033: Use explicitly provided tuple name csharp_prefer_simple_default_expression = true:suggestion # IDE0034: Simplify default expression @@ -153,7 +154,7 @@ dotnet_style_namespace_match_folder = true:suggestion # IDE013 dotnet_diagnostic.IDE0001.severity = suggestion # IDE0001: Simplify name dotnet_diagnostic.IDE0002.severity = suggestion # IDE0002: Simplify member access dotnet_diagnostic.IDE0004.severity = suggestion # IDE0004: Remove unnecessary cast -dotnet_diagnostic.IDE0005.severity = suggestion # IDE0005: Remove unnecessary import +dotnet_diagnostic.IDE0005.severity = warning # IDE0005: Remove unnecessary import dotnet_diagnostic.IDE0035.severity = suggestion # IDE0035: Remove unreachable code dotnet_diagnostic.IDE0051.severity = suggestion # IDE0051: Remove unused private member dotnet_diagnostic.IDE0052.severity = suggestion # IDE0052: Remove unread private member diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fbcefc84a4..93b3e6d0d29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: jobs: test: runs-on: ${{ matrix.os }} + timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -45,6 +46,11 @@ jobs: env: PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} + - uses: codecov/codecov-action@v5 + if: matrix.os == 'ubuntu-latest' + with: + fail_ci_if_error: true + - run: echo "DOTNET_DbgEnableMiniDump=1" >> $GITHUB_ENV if: matrix.os == 'ubuntu-latest' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000000..aedbb8704f2 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,44 @@ +name: lint + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + workflow_dispatch: + +jobs: + build: + name: Lint + runs-on: ubuntu-latest + timeout-minutes: 30 + if: github.event.pull_request.draft == false + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.x + + - name: Run `dotnet format` command + run: | + dotnet restore + dotnet format --no-restore --verify-no-changes + + - name: Report failures as Job Summary + if: ${{ failure() }} + shell: pwsh + run: | + $content = ' + ## Failed to run the `lint.yml` workflow + To fix workflow errors. Please follow the steps below. + 1. Run `dotnet format` command. + 2. Commit changes as separated commit. + 3. Push changes to source branch of PR. + ' + Write-Output $content >> $env:GITHUB_STEP_SUMMARY diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 6ba3f724aba..c799d493e7d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,5 +1,6 @@ name: nightly on: + workflow_dispatch: schedule: - cron: '0 0 * * *' @@ -10,6 +11,7 @@ jobs: publish-github-packages: if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest + timeout-minutes: 30 permissions: packages: write steps: @@ -40,3 +42,44 @@ jobs: run: | dotnet nuget push drop/nuget/*.nupkg --api-key "${{ secrets.GITHUB_TOKEN }}" --skip-duplicate --source https://nuget.pkg.github.com/dotnet/index.json + test-nightly-package: + if: github.repository == 'dotnet/docfx' + runs-on: ubuntu-latest + needs: [publish-github-packages] + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Create NuGet.config + shell: pwsh + run: | + @' + + + + + + + + + + + + + + '@ | Out-File NuGet.config -Encoding UTF8 + + - name: Install nightly build package + run: | + dotnet tool install docfx -g --prerelease + + - name: Run docfx commands for test + working-directory: samples/seed + run: | + docfx metadata + docfx build + docfx pdf + diff --git a/.github/workflows/reports.yml b/.github/workflows/reports.yml index 88edd1c0b69..92281b63644 100644 --- a/.github/workflows/reports.yml +++ b/.github/workflows/reports.yml @@ -15,6 +15,7 @@ permissions: jobs: report: runs-on: ubuntu-latest + timeout-minutes: 30 if: ${{ github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure' }} steps: - name: Create Test Report diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 4d383270736..6aa7d813f61 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -11,6 +11,7 @@ on: jobs: snapshot: runs-on: ubuntu-latest + timeout-minutes: 30 environment: ci strategy: fail-fast: false diff --git a/Directory.Build.props b/Directory.Build.props index 9ec7dd187a7..c2c1f4bd877 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ true net8.0;net9.0 - net8.0;net9.0 + net8.0;net9.0 Preview enable true @@ -19,9 +19,8 @@ warning NU1507: There are 2 package sources defined in your configuration. warning NU5104: A stable release of a package should not have a prerelease dependency. Either modify the version spec of dependency "PdfPig [0.1.9-alpha-20240510-d86c2, )" or update the version field in the nuspec. warning NU5111: The script file 'tools\.playwright\package\bin\install_media_pack.ps1' is not recognized by NuGet and hence will not be executed during installation of this package. - warning CS0436: IgnoresAccessChecksTo redefinition due to InternalsVisibleTo --> - $(NoWarn);NU1507;NU5104;NU5111;CS0436 + $(NoWarn);NU1507;NU5104;NU5111 @@ -30,8 +29,8 @@ true true snupkg - true - + true + .NET Foundation and Contributors Copyright (c) .NET Foundation and Contributors Technical documentation tool with markdown, API docs for .NET, REST API and more. @@ -45,13 +44,6 @@ - - - all - runtime; build; native; contentfiles; analyzers - - - diff --git a/Directory.Packages.props b/Directory.Packages.props index 2ca7cb4b913..78c7cbe693c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,14 +4,12 @@ true - + - - - + @@ -20,33 +18,25 @@ - - - - + + + + - - - - - - - - + + + + + + + + - - - - - - - - - + diff --git a/Dockerfile b/Dockerfile index d46998ee16a..ec5ca671b1c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,28 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim +FROM mcr.microsoft.com/dotnet/sdk:8.0-noble # Add dotnet tools to path. ENV PATH="${PATH}:/root/.dotnet/tools" +# Set Node.js path +ENV PLAYWRIGHT_NODEJS_PATH="/usr/bin/node" + # Set target docfx version. -ARG DOCFX_VERSION=2.77.0 +ARG DOCFX_VERSION=2.78.2 # Install DocFX as a dotnet tool. RUN dotnet tool install docfx -g --version ${DOCFX_VERSION} && \ docfx --version && \ rm -f /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/docfx.nupkg && \ rm -f /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/docfx.${DOCFX_VERSION}.nupkg && \ - rm -rf /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/net6.0 - -# Install Node.js and dependences for chromium PDF. -RUN apt-get update -qq && \ - apt-get install -y -qq --no-install-recommends \ - nodejs \ - libglib2.0-0 libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \ - libdbus-1-3 libxcb1 libxkbcommon0 libatspi2.0-0 libx11-6 libxcomposite1 libxdamage1 \ - libxext6 libxfixes3 libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound2 && \ - rm -rf /var/lib/apt/lists/* /tmp/* + rm -rf /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/net9.0 -# Install Chromium. -RUN PLAYWRIGHT_NODEJS_PATH="/usr/bin/node" && \ - ln -s /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/.playwright /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/net8.0/any/.playwright && \ - pwsh -File /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/net8.0/any/playwright.ps1 install chromium && \ - unlink /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/net8.0/any/.playwright +# Install Node.js and browser(chromium) with dependencies +RUN apt-get install -y -qq --update --no-install-recommends nodejs && \ + pwsh -File /root/.dotnet/tools/.store/docfx/${DOCFX_VERSION}/docfx/${DOCFX_VERSION}/tools/net8.0/any/playwright.ps1 install --with-deps chromium && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /tmp/* WORKDIR /opt/prj VOLUME [ "/opt/prj" ] -ENTRYPOINT [ "docfx" ] \ No newline at end of file +ENTRYPOINT [ "docfx" ] diff --git a/docfx.sln b/docfx.sln index 9e732c85f0f..a5974afe119 100644 --- a/docfx.sln +++ b/docfx.sln @@ -15,6 +15,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{926A0726-B806-4215-82EF-AF8E22D0FACF}" ProjectSection(SolutionItems) = preProject test\Directory.Build.props = test\Directory.Build.props + test\Directory.Packages.props = test\Directory.Packages.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docfx", "src\docfx\docfx.csproj", "{EF53214F-BA98-4026-BEED-CF771865C312}" @@ -97,6 +98,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Docfx.Build.OverwriteDocume EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Docfx.Build.OverwriteDocuments.Tests", "test\Docfx.Build.OverwriteDocuments.Tests\Docfx.Build.OverwriteDocuments.Tests.csproj", "{CAECA6C3-3317-4E6E-8927-9186857B23E8}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/docs/docs/links-and-cross-references.md b/docs/docs/links-and-cross-references.md index 9afad763ae4..eb7b0f5cee5 100644 --- a/docs/docs/links-and-cross-references.md +++ b/docs/docs/links-and-cross-references.md @@ -178,6 +178,8 @@ You can create a cross link with following options: - `displayProperty`: the property of display text when the cross reference is has resolved correctly. e.g.: `` will be resolved as . + + e.g.: `` will be resolved as . - `altProperty`: the property of display text when the cross reference does not have a `href` property. e.g.: ```` will be resolved as . diff --git a/docs/index.md b/docs/index.md index ee497ffed05..0ea52aeee8d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,7 @@ In this section we will build a simple documentation site on your local machine. > Prerequisites > - Familiarity with the command line > - Install [.NET SDK](https://dotnet.microsoft.com/en-us/download) 8.0 or higher -> - Install [Node.js](https://nodejs.org/) v20 or higher +> - Install [Node.js](https://nodejs.org/) v20 or higher (Optional: It's required when using [Create PDF Files](https://filzrev.github.io/docfx/docs/pdf.html)) Make sure you have [.NET SDK](https://dotnet.microsoft.com/en-us/download) installed, then open a terminal and enter the following command to install the latest docfx: @@ -114,6 +114,53 @@ await Docfx.Docset.Build("docfx.json"); See [API References](api/Docfx.yml) for additional APIs. +## How to use prerelease version of docfx + +Docfx publishes nightly builds to [GitHub Packages](https://github.com/dotnet/docfx/pkgs/nuget/docfx). +If you want to use prerelease version, you can install package with following steps. + +### Prerequisite + +1. Install [GitHub CLI](https://github.com/cli/cli) command. +2. Install PowerShell 7.x or later. + +### Steps + +1. Open PowerShell on working directory. + +2. Login to GitHub with additional scope request + + ```pwsh + gh auth login --scopes "read:packages" --host github.com + ``` + +3. Follow the instructions and complete the login steps. + +4. Download docfx nuget package from GitHub Packages + + ```pwsh + # Gets Access Token + $token = gh auth token + + # Gets the version of latest nightly build + $version = gh api /orgs/dotnet/packages/nuget/docfx/versions --jq '.[0].name' + + # Gets nupkg download URL. + $downloadUrl = "https://nuget.pkg.github.com/dotnet/download/docfx/${version}/${version}.nupkg" + + # Download nupkg to current directory. + Write-Host ('Download nupkg from: {0}' -f $downloadUrl) + Invoke-RestMethod -Method Get -Uri $downloadUrl -OutFile "docfx.${version}.nupkg" -Headers @{ + Authorization = "Bearer $token" + } + ``` + +5. Install docfx as .NET Global Package from local source + + ```pwsh + dotnet tool update docfx -g --prerelease --source ./ + ``` + ## Next Steps - [Write Articles](docs/markdown.md) diff --git a/docs/reference/docfx-cli-reference/docfx-metadata.md b/docs/reference/docfx-cli-reference/docfx-metadata.md index fc679ed5142..fcf55620fd2 100644 --- a/docs/reference/docfx-cli-reference/docfx-metadata.md +++ b/docs/reference/docfx-cli-reference/docfx-metadata.md @@ -77,6 +77,10 @@ Run `docfx metadata --help` or `docfx -h` to get a list of all available options Disable the default API filter (default filter only generate public or protected APIs). +- **--noRestore** + + Do not run `dotnet restore` before building the projects. + - **--namespaceLayout** Determines the namespace layout in table of contents. diff --git a/samples/seed/docfx.json b/samples/seed/docfx.json index 6dcf2b76192..3dfed8aca10 100644 --- a/samples/seed/docfx.json +++ b/samples/seed/docfx.json @@ -70,7 +70,7 @@ { "files": [ "**" ], "src": "obj/md", "dest": "md" }, { "files": [ "**" ], "src": "obj/apipage", "dest": "apipage" }, { "files": [ "articles/**/*.{md,yml}", "*.md", "toc.yml", "restapi/**" ] }, - { "files": [ "pdf/**" ] } + { "files": [ "pdf/*.{md,yml}" ] } ], "resource": [ { diff --git a/samples/seed/dotnet/assembly/BuildFromAssembly.csproj b/samples/seed/dotnet/assembly/BuildFromAssembly.csproj index b42d68e6ba4..1707423aa11 100644 --- a/samples/seed/dotnet/assembly/BuildFromAssembly.csproj +++ b/samples/seed/dotnet/assembly/BuildFromAssembly.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable true diff --git a/src/Docfx.App/Config/BuildJsonConfig.cs b/src/Docfx.App/Config/BuildJsonConfig.cs index c9dd2a4003a..ed4b395004f 100644 --- a/src/Docfx.App/Config/BuildJsonConfig.cs +++ b/src/Docfx.App/Config/BuildJsonConfig.cs @@ -72,7 +72,7 @@ internal class BuildJsonConfig /// [JsonProperty("globalMetadataFiles")] [JsonPropertyName("globalMetadataFiles")] - public ListWithStringFallback GlobalMetadataFiles { get; set; } = new(); + public ListWithStringFallback GlobalMetadataFiles { get; set; } = []; /// /// Metadata that applies to some specific files. @@ -99,7 +99,7 @@ internal class BuildJsonConfig /// [JsonProperty("template")] [JsonPropertyName("template")] - public ListWithStringFallback Template { get; set; } = new(); + public ListWithStringFallback Template { get; set; } = []; /// /// The themes applied to the documentation. @@ -123,7 +123,7 @@ internal class BuildJsonConfig /// [JsonProperty("postProcessors")] [JsonPropertyName("postProcessors")] - public ListWithStringFallback PostProcessors { get; set; } = new(); + public ListWithStringFallback PostProcessors { get; set; } = []; /// /// Run in debug mode. With debug mode, raw model and view model will be exported diff --git a/src/Docfx.App/Config/FileMetadataPairs.cs b/src/Docfx.App/Config/FileMetadataPairs.cs index 7390e638ad1..b816e909576 100644 --- a/src/Docfx.App/Config/FileMetadataPairs.cs +++ b/src/Docfx.App/Config/FileMetadataPairs.cs @@ -39,7 +39,7 @@ public FileMetadataPairs(IEnumerable items) /// public FileMetadataPairs(FileMetadataPairsItem item) { - _items = new List { item }; + _items = [item]; } /// diff --git a/src/Docfx.App/Config/FileMetadataPairsConverter.SystemTextJson.cs b/src/Docfx.App/Config/FileMetadataPairsConverter.SystemTextJson.cs index 5d294a0e691..7756e581a4b 100644 --- a/src/Docfx.App/Config/FileMetadataPairsConverter.SystemTextJson.cs +++ b/src/Docfx.App/Config/FileMetadataPairsConverter.SystemTextJson.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Docfx.Common; diff --git a/src/Docfx.App/Config/FileMetadataPairsConverter.cs b/src/Docfx.App/Config/FileMetadataPairsConverter.cs index 71dcc5f3458..a982a1a9c28 100644 --- a/src/Docfx.App/Config/FileMetadataPairsConverter.cs +++ b/src/Docfx.App/Config/FileMetadataPairsConverter.cs @@ -1,11 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Docfx.Common; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - namespace Docfx; /// diff --git a/src/Docfx.App/Config/GroupConfig.cs b/src/Docfx.App/Config/GroupConfig.cs index c6346938de3..f443a717c1a 100644 --- a/src/Docfx.App/Config/GroupConfig.cs +++ b/src/Docfx.App/Config/GroupConfig.cs @@ -23,5 +23,5 @@ internal class GroupConfig /// [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.App/Config/ListWithStringFallbackConverter.SystemTextJson.cs b/src/Docfx.App/Config/ListWithStringFallbackConverter.SystemTextJson.cs index 219ec035958..1c1ef94d29a 100644 --- a/src/Docfx.App/Config/ListWithStringFallbackConverter.SystemTextJson.cs +++ b/src/Docfx.App/Config/ListWithStringFallbackConverter.SystemTextJson.cs @@ -1,10 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.IO; using System.Text.Json; using System.Text.Json.Serialization; -using YamlDotNet.Serialization; namespace Docfx; @@ -35,7 +33,7 @@ public override ListWithStringFallback Read(ref Utf8JsonReader reader, Type type { using var document = JsonDocument.ParseValue(ref reader); JsonElement root = document.RootElement; - var values = root.EnumerateObject().Select(x=>x.ToString()); + var values = root.EnumerateObject().Select(x => x.ToString()); return new ListWithStringFallback(values); } default: diff --git a/src/Docfx.App/Config/ListWithStringFallbackConverter.cs b/src/Docfx.App/Config/ListWithStringFallbackConverter.cs index 12188991a86..ea91f6aa239 100644 --- a/src/Docfx.App/Config/ListWithStringFallbackConverter.cs +++ b/src/Docfx.App/Config/ListWithStringFallbackConverter.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - namespace Docfx; diff --git a/src/Docfx.App/Config/MergeJsonConfigConverter.NewtonsoftJson.cs b/src/Docfx.App/Config/MergeJsonConfigConverter.NewtonsoftJson.cs index 344c352c61f..2c72f7efef4 100644 --- a/src/Docfx.App/Config/MergeJsonConfigConverter.NewtonsoftJson.cs +++ b/src/Docfx.App/Config/MergeJsonConfigConverter.NewtonsoftJson.cs @@ -65,4 +65,4 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s serializer.Serialize(writer, ((MergeJsonConfig)value).ToArray()); } } -} \ No newline at end of file +} diff --git a/src/Docfx.App/Config/MergeJsonConfigConverter.SystemTextJson.cs b/src/Docfx.App/Config/MergeJsonConfigConverter.SystemTextJson.cs index 90ebe522bd1..fcb0825a71a 100644 --- a/src/Docfx.App/Config/MergeJsonConfigConverter.SystemTextJson.cs +++ b/src/Docfx.App/Config/MergeJsonConfigConverter.SystemTextJson.cs @@ -3,7 +3,6 @@ using System.Text.Json; using System.Text.Json.Serialization; -using YamlDotNet.Serialization; namespace Docfx; diff --git a/src/Docfx.App/Config/MergeJsonConfigConverter.cs b/src/Docfx.App/Config/MergeJsonConfigConverter.cs index 64d4e815013..03c9836af2f 100644 --- a/src/Docfx.App/Config/MergeJsonConfigConverter.cs +++ b/src/Docfx.App/Config/MergeJsonConfigConverter.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - namespace Docfx; /// diff --git a/src/Docfx.App/Docfx.App.csproj b/src/Docfx.App/Docfx.App.csproj index 12db285be2e..e4d0f5d7804 100644 --- a/src/Docfx.App/Docfx.App.csproj +++ b/src/Docfx.App/Docfx.App.csproj @@ -18,11 +18,6 @@ - - - - - diff --git a/src/Docfx.App/Helpers/DocumentBuilderWrapper.cs b/src/Docfx.App/Helpers/DocumentBuilderWrapper.cs index 2bafb81bef6..c9324530912 100644 --- a/src/Docfx.App/Helpers/DocumentBuilderWrapper.cs +++ b/src/Docfx.App/Helpers/DocumentBuilderWrapper.cs @@ -263,7 +263,7 @@ private static FileMetadata GetFileMetadata(string baseDirectory, BuildJsonConfi { foreach (var (key, value) in config.FileMetadata) { - var list = result.TryGetValue(key, out var items) ? items : result[key] = new(); + var list = result.TryGetValue(key, out var items) ? items : result[key] = []; foreach (var pair in value.Items) { list.Add(new FileMetadataItem(pair.Glob, key, pair.Value)); @@ -277,7 +277,7 @@ private static FileMetadata GetFileMetadata(string baseDirectory, BuildJsonConfi { foreach (var (key, value) in JsonUtility.Deserialize>(path)) { - var list = result.TryGetValue(key, out var items) ? items : result[key] = new(); + var list = result.TryGetValue(key, out var items) ? items : result[key] = []; foreach (var pair in value.Items) { list.Add(new FileMetadataItem(pair.Glob, key, pair.Value)); diff --git a/src/Docfx.App/Helpers/MetadataMerger.cs b/src/Docfx.App/Helpers/MetadataMerger.cs index 2dee2e496f3..c4b80118d2f 100644 --- a/src/Docfx.App/Helpers/MetadataMerger.cs +++ b/src/Docfx.App/Helpers/MetadataMerger.cs @@ -14,8 +14,8 @@ namespace Docfx; internal class MetadataMerger { - private readonly Dictionary> _metaTable = new(); - private readonly Dictionary> _propTable = new(); + private readonly Dictionary> _metaTable = []; + private readonly Dictionary> _propTable = []; public void Merge(MetadataMergeParameters parameters) { diff --git a/src/Docfx.App/Helpers/PdfPigTypeExtensions.cs b/src/Docfx.App/Helpers/PdfPigTypeExtensions.cs new file mode 100644 index 00000000000..8b0391424c0 --- /dev/null +++ b/src/Docfx.App/Helpers/PdfPigTypeExtensions.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using UglyToad.PdfPig.Content; +using UglyToad.PdfPig.Outline.Destinations; + +#nullable enable + +namespace Docfx; + +internal static class PdfPigTypeExtensions +{ + public static NamedDestinations GetNamedDestinations(this Catalog catalog) + => GetNamedDestinationsProperty(catalog); + + public static bool TryGet(this NamedDestinations namedDestinations, string name, out ExplicitDestination dest) + => TryGetNamedDestinations(namedDestinations, name, out dest); + + // Gets property value of catalog.NamedDestination. + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_NamedDestinations")] + private static extern NamedDestinations GetNamedDestinationsProperty(Catalog value); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "TryGet")] + private static extern bool TryGetNamedDestinations(NamedDestinations namedDestinations, string name, out ExplicitDestination dest); +} + diff --git a/src/Docfx.App/PdfBuilder.cs b/src/Docfx.App/PdfBuilder.cs index fdb1312dc36..c5a40cf603c 100644 --- a/src/Docfx.App/PdfBuilder.cs +++ b/src/Docfx.App/PdfBuilder.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Concurrent; using System.Diagnostics; using System.Reflection; @@ -32,6 +33,8 @@ namespace Docfx.Pdf; static class PdfBuilder { + private static readonly SearchValues InvalidPathChars = SearchValues.Create(Path.GetInvalidPathChars()); + class Outline { public string name { get; init; } = ""; @@ -48,11 +51,6 @@ class Outline public string? pdfFooterTemplate { get; init; } } - static PdfBuilder() - { - PlaywrightHelper.EnsurePlaywrightNodeJsPath(); - } - public static Task Run(BuildJsonConfig config, string configDirectory, string? outputDirectory = null) { var outputFolder = Path.GetFullPath(Path.Combine( @@ -70,7 +68,9 @@ public static async Task CreatePdf(string outputFolder) if (pdfTocs.Count == 0) return; - Program.Main(["install", "chromium"]); + PlaywrightHelper.EnsurePlaywrightNodeJsPath(); + + Program.Main(["install", "chromium", "--only-shell"]); var builder = WebApplication.CreateBuilder(); builder.Logging.ClearProviders(); @@ -97,7 +97,8 @@ public static async Task CreatePdf(string outputFolder) using var pageLimiter = new SemaphoreSlim(Environment.ProcessorCount, Environment.ProcessorCount); var pagePool = new ConcurrentBag(); - var headerFooterCache = new ConcurrentDictionary<(string, string), Task>(); + var headerFooterTemplateCache = new ConcurrentDictionary(); + var headerFooterPageCache = new ConcurrentDictionary<(string, string), Task>(); await AnsiConsole.Progress().StartAsync(async progress => { @@ -109,7 +110,7 @@ await Parallel.ForEachAsync(pdfTocs, async (item, _) => var outputPath = Path.Combine(outputFolder, outputName); await CreatePdf( - PrintPdf, PrintHeaderFooter, task, new(baseUrl, url), toc, outputPath, + PrintPdf, PrintHeaderFooter, task, new(baseUrl, url), toc, outputFolder, outputPath, pageNumbers => pdfPageNumbers[url] = pageNumbers); task.Value = task.MaxValue; @@ -190,7 +191,7 @@ Task PrintHeaderFooter(Outline toc, int pageNumber, int totalPages, Page var headerTemplate = ExpandTemplate(GetHeaderFooter(toc.pdfHeaderTemplate), pageNumber, totalPages); var footerTemplate = ExpandTemplate(GetHeaderFooter(toc.pdfFooterTemplate) ?? DefaultFooterTemplate, pageNumber, totalPages); - return headerFooterCache.GetOrAdd((headerTemplate, footerTemplate), _ => PrintHeaderFooterCore()); + return headerFooterPageCache.GetOrAdd((headerTemplate, footerTemplate), _ => PrintHeaderFooterCore()); async Task PrintHeaderFooterCore() { @@ -244,26 +245,36 @@ static string ExpandTemplate(string? pdfTemplate, int pageNumber, int totalPages if (string.IsNullOrEmpty(template)) return template; - try - { - var path = Path.Combine(outputFolder, template); - return File.Exists(path) ? File.ReadAllText(path) : template; - } - catch - { + // Check path chars. If it's contains HTML chars. Skip access to file content to optimmize performance + if (template.AsSpan().ContainsAny(InvalidPathChars)) return template; - } + + return headerFooterTemplateCache.GetOrAdd(template, (_) => + { + // Note: This valueFactory might be called multiple times. + try + { + var path = Path.GetFullPath(Path.Combine(outputFolder, template)); + if (!File.Exists(path)) + return template; + + var templateContent = File.ReadAllText(path); + return templateContent; + } + catch + { + return template; + } + }); } + } } static async Task CreatePdf( Func> printPdf, Func> printHeaderFooter, ProgressTask task, - Uri outlineUrl, Outline outline, string outputPath, Action> updatePageNumbers) + Uri outlineUrl, Outline outline, string outputFolder, string outputPath, Action> updatePageNumbers) { - var tempDirectory = Path.Combine(Path.GetTempPath(), ".docfx", "pdf", "pages"); - Directory.CreateDirectory(tempDirectory); - var pages = GetPages(outline).ToArray(); if (pages.Length == 0) return; @@ -300,8 +311,8 @@ await Parallel.ForEachAsync(pages, async (item, _) => var key = CleanUrl(url); if (!pagesByUrl.TryGetValue(key, out var dests)) - pagesByUrl[key] = dests = new(); - dests.Add((node, document.Structure.Catalog.NamedDestinations)); + pagesByUrl[key] = dests = []; + dests.Add((node, document.Structure.Catalog.GetNamedDestinations())); pageBytes[node] = bytes; pageNumbers[node] = numberOfPages + 1; @@ -360,6 +371,8 @@ async Task MergePdf() if (!pageBytes.TryGetValue(node, out var bytes)) continue; + var isCoverPage = IsCoverPage(url, outputFolder, outline.pdfCoverPage); + var isTocPage = IsTocPage(url); if (isTocPage) { @@ -378,6 +391,9 @@ async Task MergePdf() var pageBuilder = builder.AddPage(document, i, x => CopyLink(node, x)); + if (isCoverPage) + continue; + if (isTocPage) continue; @@ -438,6 +454,19 @@ PdfAction HandleUriAction(UriAction url) static Uri CleanUrl(Uri url) => new UriBuilder(url) { Query = null, Fragment = null }.Uri; + static bool IsCoverPage(Uri pageUri, string baseFolder, string? pdfCoverPage) + { + Debug.Assert(Path.IsPathFullyQualified(baseFolder)); + + if (string.IsNullOrEmpty(pdfCoverPage)) + return false; + + string pagePath = pageUri.AbsolutePath.TrimStart('/'); + string covePagePath = PathUtility.MakeRelativePath(baseFolder, Path.GetFullPath(Path.Combine(baseFolder, pdfCoverPage))); + + return pagePath.Equals(covePagePath, GetStringComparison()); + } + static bool IsTocPage(Uri url) => url.AbsolutePath.StartsWith("/_pdftoc/"); Bookmarks CreateBookmarks(Outline[]? items) @@ -618,4 +647,12 @@ static string getMillimeter(double pt) return $"{Math.Round(pt * MillimeterPerInch / Dpi)}mm"; } } + + // Gets StringComparison instance for path string. + private static StringComparison GetStringComparison() + { + return PathUtility.IsPathCaseInsensitive() + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + } } diff --git a/src/Docfx.App/RunBuild.cs b/src/Docfx.App/RunBuild.cs index 5501ae9e856..0549827bfd3 100644 --- a/src/Docfx.App/RunBuild.cs +++ b/src/Docfx.App/RunBuild.cs @@ -21,7 +21,7 @@ public static string Exec(BuildJsonConfig config, BuildOptions options, string c var stopwatch = Stopwatch.StartNew(); if (config.Template == null || config.Template.Count == 0) { - config.Template = new ListWithStringFallback { "default" }; + config.Template = ["default"]; } var baseDirectory = Path.GetFullPath(string.IsNullOrEmpty(configDirectory) ? Directory.GetCurrentDirectory() : configDirectory); diff --git a/src/Docfx.App/RunMerge.cs b/src/Docfx.App/RunMerge.cs index 76df5b5ed51..1b6ed57744a 100644 --- a/src/Docfx.App/RunMerge.cs +++ b/src/Docfx.App/RunMerge.cs @@ -56,7 +56,7 @@ private static MetadataMergeParameters ConfigToParameter(MergeJsonItemConfig con OutputBaseDir = outputDirectory, Metadata = config.GlobalMetadata?.ToImmutableDictionary() ?? ImmutableDictionary.Empty, FileMetadata = ConvertToFileMetadataItem(baseDirectory, config.FileMetadata), - TocMetadata = config.TocMetadata?.ToImmutableList() ?? ImmutableList.Empty, + TocMetadata = config.TocMetadata?.ToImmutableList() ?? [], Files = GetFileCollectionFromFileMapping( baseDirectory, DocumentType.Article, diff --git a/src/Docfx.Build.Common/MarkdownReader.cs b/src/Docfx.Build.Common/MarkdownReader.cs index 1aae2b1eaf8..66e9a40fc33 100644 --- a/src/Docfx.Build.Common/MarkdownReader.cs +++ b/src/Docfx.Build.Common/MarkdownReader.cs @@ -13,7 +13,7 @@ namespace Docfx.Build.Common; public class MarkdownReader { - private static readonly ImmutableList RequiredProperties = ImmutableList.Create(Constants.PropertyName.Uid); + private static readonly ImmutableList RequiredProperties = [Constants.PropertyName.Uid]; public static IEnumerable ReadMarkdownAsOverwrite(IHostService host, FileAndType ft) { diff --git a/src/Docfx.Build.Common/ModelAttributeHandlers/HandleModelAttributesContext.cs b/src/Docfx.Build.Common/ModelAttributeHandlers/HandleModelAttributesContext.cs index 10f37bc5c1c..87a6811be05 100644 --- a/src/Docfx.Build.Common/ModelAttributeHandlers/HandleModelAttributesContext.cs +++ b/src/Docfx.Build.Common/ModelAttributeHandlers/HandleModelAttributesContext.cs @@ -14,11 +14,11 @@ public class HandleModelAttributesContext public bool EnableContentPlaceholder { get; set; } public string PlaceholderContent { get; set; } public bool ContainsPlaceholder { get; set; } - public HashSet Dependency { get; set; } = new(); + public HashSet Dependency { get; set; } = []; public FileAndType FileAndType { get; set; } public HashSet LinkToFiles { get; set; } = new(FilePathComparer.OSPlatformSensitiveStringComparer); - public HashSet LinkToUids { get; set; } = new(); - public List Uids { get; set; } = new(); - public Dictionary> UidLinkSources { get; set; } = new(); - public Dictionary> FileLinkSources { get; set; } = new(); + public HashSet LinkToUids { get; set; } = []; + public List Uids { get; set; } = []; + public Dictionary> UidLinkSources { get; set; } = []; + public Dictionary> FileLinkSources { get; set; } = []; } diff --git a/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/BaseModelAttributeHandler.cs b/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/BaseModelAttributeHandler.cs index 1178c9062bf..50ca4526e80 100644 --- a/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/BaseModelAttributeHandler.cs +++ b/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/BaseModelAttributeHandler.cs @@ -78,7 +78,7 @@ public object Handle(object obj, HandleModelAttributesContext context) protected virtual bool ShouldHandle(object currentObj, object declaringObject, PropInfo currentPropInfo, HandleModelAttributesContext context) { - return currentPropInfo is {Attr: not null}; + return currentPropInfo is { Attr: not null }; } /// diff --git a/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/UrlContentHandler.cs b/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/UrlContentHandler.cs index 369a59e41f3..9cd182da3fa 100644 --- a/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/UrlContentHandler.cs +++ b/src/Docfx.Build.Common/ModelAttributeHandlers/Handlers/UrlContentHandler.cs @@ -98,7 +98,7 @@ private static string GetHrefFromRoot(string originalHref, HandleModelAttributes if (!context.FileLinkSources.TryGetValue(file, out List sources)) { - sources = new List(); + sources = []; context.FileLinkSources[file] = sources; } sources.Add(new LinkSourceInfo diff --git a/src/Docfx.Build.Common/Reference/OverwriteDocumentModel.cs b/src/Docfx.Build.Common/Reference/OverwriteDocumentModel.cs index 8ac8f568cbb..90d9118ba0c 100644 --- a/src/Docfx.Build.Common/Reference/OverwriteDocumentModel.cs +++ b/src/Docfx.Build.Common/Reference/OverwriteDocumentModel.cs @@ -17,7 +17,7 @@ public class OverwriteDocumentModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; /// /// The uid for this overwrite document, as defined in YAML header @@ -49,7 +49,7 @@ public class OverwriteDocumentModel [YamlIgnore] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public HashSet LinkToFiles { get; set; } = new(); + public HashSet LinkToFiles { get; set; } = []; /// /// Links to other Uids @@ -57,7 +57,7 @@ public class OverwriteDocumentModel [YamlIgnore] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public HashSet LinkToUids { get; set; } = new(); + public HashSet LinkToUids { get; set; } = []; /// /// Link sources information for file @@ -65,7 +65,7 @@ public class OverwriteDocumentModel [YamlIgnore] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public Dictionary> FileLinkSources { get; set; } = new(); + public Dictionary> FileLinkSources { get; set; } = []; /// /// Link sources information for Uid @@ -73,7 +73,7 @@ public class OverwriteDocumentModel [YamlIgnore] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public Dictionary> UidLinkSources { get; set; } = new(); + public Dictionary> UidLinkSources { get; set; } = []; /// /// Dependencies extracted from the markdown content diff --git a/src/Docfx.Build.ManagedReference/ApplyPlatformVersion.cs b/src/Docfx.Build.ManagedReference/ApplyPlatformVersion.cs index 9135d8c370a..87da14659f5 100644 --- a/src/Docfx.Build.ManagedReference/ApplyPlatformVersion.cs +++ b/src/Docfx.Build.ManagedReference/ApplyPlatformVersion.cs @@ -60,7 +60,7 @@ private static List GetPlatformVersionFromMetadata(object value) { if (value is string text) { - return new List { text }; + return [text]; } if (value is IEnumerable collection) diff --git a/src/Docfx.Build.ManagedReference/BuildOutputs/ApiBuildOutput.cs b/src/Docfx.Build.ManagedReference/BuildOutputs/ApiBuildOutput.cs index d3087ea9a83..989e40db3f4 100644 --- a/src/Docfx.Build.ManagedReference/BuildOutputs/ApiBuildOutput.cs +++ b/src/Docfx.Build.ManagedReference/BuildOutputs/ApiBuildOutput.cs @@ -184,7 +184,7 @@ public class ApiBuildOutput [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; public static ApiBuildOutput FromModel(PageViewModel model) { diff --git a/src/Docfx.Build.ManagedReference/BuildOutputs/ApiReferenceBuildOutput.cs b/src/Docfx.Build.ManagedReference/BuildOutputs/ApiReferenceBuildOutput.cs index 14416d04deb..dda51eaf027 100644 --- a/src/Docfx.Build.ManagedReference/BuildOutputs/ApiReferenceBuildOutput.cs +++ b/src/Docfx.Build.ManagedReference/BuildOutputs/ApiReferenceBuildOutput.cs @@ -174,7 +174,7 @@ public class ApiReferenceBuildOutput [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] [System.Text.Json.Serialization.JsonPropertyName("__metadata__")] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; [EditorBrowsable(EditorBrowsableState.Never)] [YamlIgnore] @@ -300,7 +300,7 @@ public void Expand(Dictionary references, strin public static List GetSpecNames(string xref, string[] supportedLanguages, SortedList> specs = null) { - if (specs is {Count: > 0}) + if (specs is { Count: > 0 }) { return (from spec in specs where supportedLanguages.Contains(spec.Key) diff --git a/src/Docfx.Build.ManagedReference/FillReferenceInformation.cs b/src/Docfx.Build.ManagedReference/FillReferenceInformation.cs index 1935a7a605b..63356c20225 100644 --- a/src/Docfx.Build.ManagedReference/FillReferenceInformation.cs +++ b/src/Docfx.Build.ManagedReference/FillReferenceInformation.cs @@ -14,7 +14,7 @@ namespace Docfx.Build.ManagedReference; [Export(nameof(ManagedReferenceDocumentProcessor), typeof(IDocumentBuildStep))] public class FillReferenceInformation : BaseDocumentBuildStep { - private readonly Dictionary _items = new(); + private readonly Dictionary _items = []; public override string Name => nameof(FillReferenceInformation); @@ -22,16 +22,14 @@ public class FillReferenceInformation : BaseDocumentBuildStep public override void Postbuild(ImmutableList models, IHostService host) { - if (models.Count > 0) + foreach (var model in models) { - foreach (var model in models) + if (model.Type != DocumentType.Article) { - if (model.Type != DocumentType.Article) - { - continue; - } - FillCore((PageViewModel)model.Content, host, model.OriginalFileAndType.File); + continue; } + + FillCore((PageViewModel)model.Content, host, model.OriginalFileAndType.File); } } @@ -113,10 +111,10 @@ private void TraceSourceInfo(PageViewModel model, string file) private static IEnumerable GetUidsToFill(PageViewModel pageViewModel) { return from i in pageViewModel.Items - from c in (i.Children ?? Enumerable.Empty()) - .Concat(i.ExtensionMethods ?? Enumerable.Empty()) - .Concat(i.InheritedMembers ?? Enumerable.Empty()) - select c; + from c in (i.Children ?? Enumerable.Empty()) + .Concat(i.ExtensionMethods ?? Enumerable.Empty()) + .Concat(i.InheritedMembers ?? Enumerable.Empty()) + select c; } #endregion diff --git a/src/Docfx.Build.ManagedReference/ManagedReferenceDocumentProcessor.cs b/src/Docfx.Build.ManagedReference/ManagedReferenceDocumentProcessor.cs index 31b49b99d47..ecf6d2c0b8c 100644 --- a/src/Docfx.Build.ManagedReference/ManagedReferenceDocumentProcessor.cs +++ b/src/Docfx.Build.ManagedReference/ManagedReferenceDocumentProcessor.cs @@ -205,34 +205,25 @@ private static IEnumerable GetXRefInfo(ItemViewModel item, string key, Href = ((RelativePath)key).UrlEncode().ToString(), CommentId = item.CommentId, }; - if (item.Names.Count > 0) + foreach (var pair in item.Names) { - foreach (var pair in item.Names) - { - result["name." + pair.Key] = pair.Value; - } + result["name." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.FullName)) { result["fullName"] = item.FullName; } - if (item.FullNames.Count > 0) + foreach (var pair in item.FullNames) { - foreach (var pair in item.FullNames) - { - result["fullName." + pair.Key] = pair.Value; - } + result["fullName." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.NameWithType)) { result["nameWithType"] = item.NameWithType; } - if (item.NamesWithType.Count > 0) + foreach (var pair in item.NamesWithType) { - foreach (var pair in item.NamesWithType) - { - result["nameWithType." + pair.Key] = pair.Value; - } + result["nameWithType." + pair.Key] = pair.Value; } yield return result; // generate overload xref spec. @@ -263,34 +254,25 @@ private static XRefSpec GetXRefSpecFromReference(ReferenceViewModel item) CommentId = item.CommentId, IsSpec = item.IsExternal != true, }; - if (item.NameInDevLangs.Count > 0) + foreach (var pair in item.NameInDevLangs) { - foreach (var pair in item.NameInDevLangs) - { - result["name." + pair.Key] = pair.Value; - } + result["name." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.FullName)) { result["fullName"] = item.FullName; } - if (item.FullNameInDevLangs.Count > 0) + foreach (var pair in item.FullNameInDevLangs) { - foreach (var pair in item.FullNameInDevLangs) - { - result["fullName." + pair.Key] = pair.Value; - } + result["fullName." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.NameWithType)) { result["nameWithType"] = item.NameWithType; } - if (item.NameWithTypeInDevLangs.Count > 0) + foreach (var pair in item.NameWithTypeInDevLangs) { - foreach (var pair in item.NameWithTypeInDevLangs) - { - result["nameWithType." + pair.Key] = pair.Value; - } + result["nameWithType." + pair.Key] = pair.Value; } if (item.Additional != null) { diff --git a/src/Docfx.Build.ManagedReference/MergeManagedReferenceDocument.cs b/src/Docfx.Build.ManagedReference/MergeManagedReferenceDocument.cs index acf4e8e7c7a..6f823e326a6 100644 --- a/src/Docfx.Build.ManagedReference/MergeManagedReferenceDocument.cs +++ b/src/Docfx.Build.ManagedReference/MergeManagedReferenceDocument.cs @@ -176,7 +176,7 @@ private static PageViewModel ConvertToVM(MergeItem mergeItem) { var vm = new PageViewModel { - Items = new List(), + Items = [], References = mergeItem.References?.Values.ToList(), Metadata = mergeItem.Metadata, }; diff --git a/src/Docfx.Build.ManagedReference/SplitClassPageToMemberLevel.cs b/src/Docfx.Build.ManagedReference/SplitClassPageToMemberLevel.cs index 874bfb5ec06..934c312bcdd 100644 --- a/src/Docfx.Build.ManagedReference/SplitClassPageToMemberLevel.cs +++ b/src/Docfx.Build.ManagedReference/SplitClassPageToMemberLevel.cs @@ -21,8 +21,8 @@ public class SplitClassPageToMemberLevel : BaseDocumentBuildStep private const string SplitFromPropertyName = "_splitFrom"; private const string IsOverloadPropertyName = "_isOverload"; private const int MaximumFileNameLength = 180; - private static readonly List EmptyList = new(); - private static readonly string[] EmptyArray = Array.Empty(); + private static readonly List EmptyList = []; + private static readonly string[] EmptyArray = []; public override string Name => nameof(SplitClassPageToMemberLevel); @@ -95,7 +95,7 @@ private static void RenewDupeFileModels(FileModel dupeModel, Dictionary { }); + var newModel = GenerateNewFileModel(dupeModel, page, Path.GetFileNameWithoutExtension(newFilePath), []); modelsDict[newFilePath] = newModel; } @@ -180,7 +180,7 @@ private SplittedResult SplitModelToOverloadLevel(FileModel model, Dictionary { primaryItem }; + page.Items = [primaryItem]; page.Metadata[SplitReferencePropertyName] = true; page.Metadata[SplitFromPropertyName] = true; @@ -210,7 +210,7 @@ private static IEnumerable GetNewPages(PageViewModel page) { foreach (var item in overload) { - yield return ExtractPageViewModel(page, new List { item }); + yield return ExtractPageViewModel(page, [item]); } } else @@ -296,7 +296,7 @@ private static List GetVersionFromMetadata(object value) { if (value is string text) { - return new List { text }; + return [text]; } return GetListFromObject(value); @@ -343,26 +343,17 @@ private ReferenceViewModel ConvertToReference(ItemViewModel item) FullName = item.FullName, }; - if (item.Names.Count > 0) + foreach (var pair in item.Names) { - foreach (var pair in item.Names) - { - reference.NameInDevLangs[pair.Key] = pair.Value; - } + reference.NameInDevLangs[pair.Key] = pair.Value; } - if (item.FullNames.Count > 0) + foreach (var pair in item.FullNames) { - foreach (var pair in item.FullNames) - { - reference.FullNameInDevLangs[pair.Key] = pair.Value; - } + reference.FullNameInDevLangs[pair.Key] = pair.Value; } - if (item.NamesWithType.Count > 0) + foreach (var pair in item.NamesWithType) { - foreach (var pair in item.NamesWithType) - { - reference.NameWithTypeInDevLangs[pair.Key] = pair.Value; - } + reference.NameWithTypeInDevLangs[pair.Key] = pair.Value; } return reference; @@ -375,26 +366,17 @@ private static void MergeWithReference(ItemViewModel item, ReferenceViewModel re item.FullName = reference.FullName; item.CommentId = reference.CommentId; - if (reference.NameInDevLangs.Count > 0) + foreach (var pair in reference.NameInDevLangs) { - foreach (var pair in reference.NameInDevLangs) - { - item.Names[pair.Key] = pair.Value; - } + item.Names[pair.Key] = pair.Value; } - if (reference.FullNameInDevLangs.Count > 0) + foreach (var pair in reference.FullNameInDevLangs) { - foreach (var pair in reference.FullNameInDevLangs) - { - item.FullNames[pair.Key] = pair.Value; - } + item.FullNames[pair.Key] = pair.Value; } - if (reference.NameWithTypeInDevLangs.Count > 0) + foreach (var pair in reference.NameWithTypeInDevLangs) { - foreach (var pair in reference.NameWithTypeInDevLangs) - { - item.NamesWithType[pair.Key] = pair.Value; - } + item.NamesWithType[pair.Key] = pair.Value; } // SHOULD sync with ItemViewModel & ReferenceViewModel diff --git a/src/Docfx.Build.OperationLevelRestApi/SplitRestApiToOperationLevel.cs b/src/Docfx.Build.OperationLevelRestApi/SplitRestApiToOperationLevel.cs index b108f10f8cb..6d520c7b5a7 100644 --- a/src/Docfx.Build.OperationLevelRestApi/SplitRestApiToOperationLevel.cs +++ b/src/Docfx.Build.OperationLevelRestApi/SplitRestApiToOperationLevel.cs @@ -77,9 +77,9 @@ private static Tuple, List> SplitModelToOpe } // Reset children - content.Children = new List(); + content.Children = []; content.Metadata["_isSplittedByOperation"] = true; - content.Tags = new List(); + content.Tags = []; model.Content = content; // Reset uid definition @@ -123,8 +123,8 @@ private static IEnumerable GenerateOperationModels(Res Summary = child.Summary, Remarks = child.Remarks, Documentation = child.Documentation, - Children = new List { child }, - Tags = new List(), + Children = [child], + Tags = [], Metadata = MergeChildMetadata(root, child) }; @@ -139,7 +139,7 @@ private static IEnumerable GenerateOperationModels(Res child.Description = null; child.Summary = null; child.Remarks = null; - child.Tags = new List(); + child.Tags = []; yield return model; } diff --git a/src/Docfx.Build.OverwriteDocuments/MarkdownFragmentsCreator.cs b/src/Docfx.Build.OverwriteDocuments/MarkdownFragmentsCreator.cs index 34a8c202ecc..0eebf55cdd9 100644 --- a/src/Docfx.Build.OverwriteDocuments/MarkdownFragmentsCreator.cs +++ b/src/Docfx.Build.OverwriteDocuments/MarkdownFragmentsCreator.cs @@ -69,7 +69,7 @@ private List PropertySection() { PropertyName = key, PropertyNameSource = Next(), - PropertyValue = new List(), + PropertyValue = [], }; Block block; while ((block = Peek()) != null && !_inlineCodeHeadingRule.Parse(block, out var _)) diff --git a/src/Docfx.Build.OverwriteDocuments/OverwriteDocumentModelCreator.cs b/src/Docfx.Build.OverwriteDocuments/OverwriteDocumentModelCreator.cs index 5a9f3f2af30..2d4bc3a3fa7 100644 --- a/src/Docfx.Build.OverwriteDocuments/OverwriteDocumentModelCreator.cs +++ b/src/Docfx.Build.OverwriteDocuments/OverwriteDocumentModelCreator.cs @@ -37,7 +37,7 @@ internal static Dictionary ConvertYamlCodeBlock(string yamlCodeB { if (string.IsNullOrEmpty(yamlCodeBlock) || yamlCodeBlockSource == null) { - return new Dictionary(); + return []; } using var reader = new StringReader(yamlCodeBlock); @@ -202,7 +202,7 @@ private MarkdownDocument CreateDocument(MarkdownPropertyModel model) private static Dictionary CreateDictionaryObject() { - return new Dictionary(); + return []; } private static List CreateDictionaryArrayObject(OPathSegment segment) diff --git a/src/Docfx.Build.OverwriteDocuments/OverwriteUtility.cs b/src/Docfx.Build.OverwriteDocuments/OverwriteUtility.cs index 275874b7e5e..04744dd0e43 100644 --- a/src/Docfx.Build.OverwriteDocuments/OverwriteUtility.cs +++ b/src/Docfx.Build.OverwriteDocuments/OverwriteUtility.cs @@ -7,14 +7,12 @@ namespace Docfx.Build.OverwriteDocuments; -public static class OverwriteUtility +public static partial class OverwriteUtility { private static readonly string[] UidWrappers = ["`", "``", "```", "````", "`````", "``````"]; - private static readonly Regex OPathRegex = - new( - @"^(?[:A-Za-z_](?>[\w\.\-:]*))(?:\[\s*(?[:A-Za-z_](?>[\w\.\-:]*))\s*=\s*(?:""(?(?:(?>[^""\\]*)|\\.)*)"")\s*\])?(?:\/|$)", - RegexOptions.Compiled); + [GeneratedRegex(@"^(?[:A-Za-z_](?>[\w\.\-:]*))(?:\[\s*(?[:A-Za-z_](?>[\w\.\-:]*))\s*=\s*(?:""(?(?:(?>[^""\\]*)|\\.)*)"")\s*\])?(?:\/|$)")] + private static partial Regex OPathRegex(); public static List ParseOPath(string OPathString) { @@ -33,7 +31,7 @@ public static List ParseOPath(string OPathString) var leftString = OPathString; while (leftString.Length > 0) { - var match = OPathRegex.Match(leftString); + var match = OPathRegex().Match(leftString); if (match.Length == 0) { throw new ArgumentException($"{OPathString} is not a valid OPath"); @@ -81,7 +79,7 @@ public static void AddOrUpdateFragmentEntity(this Dictionary(), + Properties = [], Metadata = metadata }; fragments.Add(uid, value); @@ -95,7 +93,7 @@ public static void AddOrUpdateFragmentProperty(this MarkdownFragment fragment, s { if (!fragment.Properties.TryGetValue(oPath, out var property)) { - fragment.Properties[oPath] = property = new MarkdownProperty { OPath = oPath}; + fragment.Properties[oPath] = property = new MarkdownProperty { OPath = oPath }; } if (string.IsNullOrEmpty(property.Content)) diff --git a/src/Docfx.Build.OverwriteDocuments/Rules/YamlCodeBlockRule.cs b/src/Docfx.Build.OverwriteDocuments/Rules/YamlCodeBlockRule.cs index 08f1c03e0c0..e8fef8289cf 100644 --- a/src/Docfx.Build.OverwriteDocuments/Rules/YamlCodeBlockRule.cs +++ b/src/Docfx.Build.OverwriteDocuments/Rules/YamlCodeBlockRule.cs @@ -10,7 +10,7 @@ public sealed class YamlCodeBlockRule : IOverwriteBlockRule { public string TokenName => "YamlCodeBlock"; - private static readonly List _allowedLanguages = new() { "yaml", "yml" }; + private static readonly List _allowedLanguages = ["yaml", "yml"]; public bool Parse(Block block, out string value) { diff --git a/src/Docfx.Build.RestApi/BuildRestApiDocument.cs b/src/Docfx.Build.RestApi/BuildRestApiDocument.cs index 479fa53a900..8e2b79feafb 100644 --- a/src/Docfx.Build.RestApi/BuildRestApiDocument.cs +++ b/src/Docfx.Build.RestApi/BuildRestApiDocument.cs @@ -15,7 +15,7 @@ namespace Docfx.Build.RestApi; [Export(nameof(RestApiDocumentProcessor), typeof(IDocumentBuildStep))] public class BuildRestApiDocument : BuildReferenceDocumentBase { - private static readonly HashSet MarkupKeys = new() { "description" }; + private static readonly HashSet MarkupKeys = ["description"]; public override string Name => nameof(BuildRestApiDocument); @@ -102,7 +102,7 @@ private static void MarkupRecursive(JToken jToken, IHostService host, FileModel { if (MarkupKeys.Contains(pair.Key) && pair.Value != null) { - if (pair.Value is JValue {Type: JTokenType.String} jValue) + if (pair.Value is JValue { Type: JTokenType.String } jValue) { jObject[pair.Key] = Markup(host, (string)jValue, model, filter); } diff --git a/src/Docfx.Build.RestApi/Swagger/InfoObject.cs b/src/Docfx.Build.RestApi/Swagger/InfoObject.cs index f599720bf85..5248b10b8e0 100644 --- a/src/Docfx.Build.RestApi/Swagger/InfoObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/InfoObject.cs @@ -32,5 +32,5 @@ public class InfoObject [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary PatternedObjects { get; set; } = new(); + public Dictionary PatternedObjects { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerArray.cs b/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerArray.cs index 6219f6b225d..087513a2e3c 100644 --- a/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerArray.cs +++ b/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerArray.cs @@ -7,7 +7,7 @@ internal class SwaggerArray : SwaggerObjectBase { public override SwaggerObjectType ObjectType => SwaggerObjectType.Array; - public List Array { get; set; } = new(); + public List Array { get; set; } = []; public override SwaggerObjectBase Clone() { diff --git a/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerObject.cs b/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerObject.cs index 397971ea2ce..58fabf90f16 100644 --- a/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/Internals/SwaggerObject.cs @@ -7,7 +7,7 @@ internal class SwaggerObject : SwaggerObjectBase { public override SwaggerObjectType ObjectType => SwaggerObjectType.Object; - public Dictionary Dictionary { get; set; } = new(); + public Dictionary Dictionary { get; set; } = []; public override SwaggerObjectBase Clone() { diff --git a/src/Docfx.Build.RestApi/Swagger/OperationObject.cs b/src/Docfx.Build.RestApi/Swagger/OperationObject.cs index 070d2bc56ca..060977a85ab 100644 --- a/src/Docfx.Build.RestApi/Swagger/OperationObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/OperationObject.cs @@ -49,5 +49,5 @@ public class OperationObject [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/Swagger/ParameterObject.cs b/src/Docfx.Build.RestApi/Swagger/ParameterObject.cs index b09e5759b01..3e547b8d9b7 100644 --- a/src/Docfx.Build.RestApi/Swagger/ParameterObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/ParameterObject.cs @@ -23,5 +23,5 @@ public class ParameterObject [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/Swagger/PathItemObject.cs b/src/Docfx.Build.RestApi/Swagger/PathItemObject.cs index 6071499c396..d50da2c9583 100644 --- a/src/Docfx.Build.RestApi/Swagger/PathItemObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/PathItemObject.cs @@ -25,5 +25,5 @@ public class PathItemObject [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/Swagger/ResponseObject.cs b/src/Docfx.Build.RestApi/Swagger/ResponseObject.cs index fd098a1a225..a4affc6a5b9 100644 --- a/src/Docfx.Build.RestApi/Swagger/ResponseObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/ResponseObject.cs @@ -31,5 +31,5 @@ public class ResponseObject [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/Swagger/SwaggerModel.cs b/src/Docfx.Build.RestApi/Swagger/SwaggerModel.cs index fa68585d5a8..f4359c2829c 100644 --- a/src/Docfx.Build.RestApi/Swagger/SwaggerModel.cs +++ b/src/Docfx.Build.RestApi/Swagger/SwaggerModel.cs @@ -95,5 +95,5 @@ public class SwaggerModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/Swagger/TagItemObject.cs b/src/Docfx.Build.RestApi/Swagger/TagItemObject.cs index f632850f081..ba48519bc88 100644 --- a/src/Docfx.Build.RestApi/Swagger/TagItemObject.cs +++ b/src/Docfx.Build.RestApi/Swagger/TagItemObject.cs @@ -37,5 +37,5 @@ public class TagItemObject [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.RestApi/SwaggerModelConverter.cs b/src/Docfx.Build.RestApi/SwaggerModelConverter.cs index f83a79c45bb..9a83e692a9b 100644 --- a/src/Docfx.Build.RestApi/SwaggerModelConverter.cs +++ b/src/Docfx.Build.RestApi/SwaggerModelConverter.cs @@ -12,7 +12,7 @@ namespace Docfx.Build.RestApi; -public static class SwaggerModelConverter +public static partial class SwaggerModelConverter { public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger) { @@ -25,9 +25,9 @@ public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger) Metadata = swagger.Metadata, Description = swagger.Description, Summary = swagger.Summary, - Children = new List(), + Children = [], Raw = swagger.Raw, - Tags = new List() + Tags = [] }; if (swagger.Tags != null) { @@ -106,7 +106,9 @@ public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger) #region Private methods - private static readonly Regex HtmlEncodeRegex = new(@"\W", RegexOptions.Compiled); + [GeneratedRegex(@"\W")] + private static partial Regex HtmlEncodeRegex(); + private const string TagText = "tag"; private static readonly string[] OperationNames = ["get", "put", "post", "delete", "options", "head", "patch"]; @@ -118,7 +120,7 @@ public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger) private static string GetHtmlId(string id) { if (string.IsNullOrEmpty(id)) return null; - return HtmlEncodeRegex.Replace(id, "_"); + return HtmlEncodeRegex().Replace(id, "_"); } private static string GetUid(SwaggerModel swagger) @@ -194,6 +196,5 @@ private static string GetMetadataStringValue(ParameterObject parameter, string m } return null; } - #endregion } diff --git a/src/Docfx.Build.RestApi/ValidateRestApiDocumentMetadata.cs b/src/Docfx.Build.RestApi/ValidateRestApiDocumentMetadata.cs index 8494910a04a..f082944c26d 100644 --- a/src/Docfx.Build.RestApi/ValidateRestApiDocumentMetadata.cs +++ b/src/Docfx.Build.RestApi/ValidateRestApiDocumentMetadata.cs @@ -29,10 +29,9 @@ public override void Build(FileModel model, IHostService host) case DocumentType.Overwrite: foreach (var item in (List)model.Content) { - host.ValidateInputMetadata( - model.OriginalFileAndType.File, - // use RestApiChildItemViewModel because it contains all properties for REST. - item.ConvertTo().Metadata.ToImmutableDictionary()); + // use RestApiChildItemViewModel because it contains all properties for REST + var metadata = item.ConvertTo().Metadata.ToImmutableDictionary(); + host.ValidateInputMetadata(model.OriginalFileAndType.File, metadata); } break; default: diff --git a/src/Docfx.Build.SchemaDriven/Models/DocumentSchema.cs b/src/Docfx.Build.SchemaDriven/Models/DocumentSchema.cs index 3dfa1ad58c3..6a9422ed41b 100644 --- a/src/Docfx.Build.SchemaDriven/Models/DocumentSchema.cs +++ b/src/Docfx.Build.SchemaDriven/Models/DocumentSchema.cs @@ -142,7 +142,7 @@ BaseSchema ResolveRefCore(BaseSchema schema) private static bool CheckOverwriteAbility(BaseSchema schema) { - return CheckOverwriteAbilityCore(schema, new Dictionary()); + return CheckOverwriteAbilityCore(schema, []); } private static bool CheckOverwriteAbilityCore(BaseSchema schema, Dictionary cache) diff --git a/src/Docfx.Build.SchemaDriven/Models/JsonPointer.cs b/src/Docfx.Build.SchemaDriven/Models/JsonPointer.cs index 99bb7ddba2d..fca8be66e26 100644 --- a/src/Docfx.Build.SchemaDriven/Models/JsonPointer.cs +++ b/src/Docfx.Build.SchemaDriven/Models/JsonPointer.cs @@ -24,7 +24,7 @@ public JsonPointer(string raw) throw new InvalidJsonPointerException($"Invalid json pointer \"{raw}\""); } - _parts = _isRoot ? Array.Empty() : raw.Substring(1).Split(Splitter[0]); + _parts = _isRoot ? [] : raw.Substring(1).Split(Splitter[0]); _raw = raw; } @@ -32,7 +32,7 @@ public JsonPointer(string raw) public JsonPointer(string[] parts) { _isRoot = parts == null || parts.Length == 0; - _parts = parts ?? Array.Empty(); + _parts = parts ?? []; _raw = Splitter + string.Join(Splitter, parts); } @@ -49,7 +49,7 @@ public JsonPointer GetParentPointer() public static bool TryCreate(string raw, out JsonPointer pointer) { pointer = null; - if (raw is {Length: > 0} && raw[0] != '/') + if (raw is { Length: > 0 } && raw[0] != '/') { return false; } diff --git a/src/Docfx.Build.SchemaDriven/Processors/FileInterpreter.cs b/src/Docfx.Build.SchemaDriven/Processors/FileInterpreter.cs index d67f99742ed..5f34be6c817 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/FileInterpreter.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/FileInterpreter.cs @@ -19,7 +19,7 @@ public FileInterpreter(bool exportFileLink, bool updateValue) public bool CanInterpret(BaseSchema schema) { - return schema is {ContentType: ContentType.File}; + return schema is { ContentType: ContentType.File }; } public object Interpret(BaseSchema schema, object value, IProcessContext context, string path) diff --git a/src/Docfx.Build.SchemaDriven/Processors/FragmentsValidationInterpreter.cs b/src/Docfx.Build.SchemaDriven/Processors/FragmentsValidationInterpreter.cs index f1b356e04e7..2d0459555ec 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/FragmentsValidationInterpreter.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/FragmentsValidationInterpreter.cs @@ -42,7 +42,7 @@ public object Interpret(BaseSchema schema, object value, IProcessContext context $"Markdown property `{path.Trim('/')}` is not allowed inside a YAML code block", code: WarningCodes.Overwrite.InvalidMarkdownFragments); return value; - }; + } if (schema.MergeType == MergeType.Key) { diff --git a/src/Docfx.Build.SchemaDriven/Processors/Helper.cs b/src/Docfx.Build.SchemaDriven/Processors/Helper.cs index 400c17da3b5..6c0e3e3d2b5 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/Helper.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/Helper.cs @@ -21,7 +21,7 @@ public static void AddFileLinkSource(this Dictionary sources)) { - sources = new List(); + sources = []; fileLinkSources[file] = sources; } sources.Add(source); @@ -31,7 +31,7 @@ public static void SetOriginalContentFile(this IProcessContext context, string p { if (!context.PathProperties.TryGetValue(path, out var properties)) { - properties = context.PathProperties[path] = new Dictionary(); + properties = context.PathProperties[path] = []; } properties[ContentOriginalFileKeyName] = file; diff --git a/src/Docfx.Build.SchemaDriven/Processors/HrefInterpreter.cs b/src/Docfx.Build.SchemaDriven/Processors/HrefInterpreter.cs index afe370d804d..5cf6ad2c171 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/HrefInterpreter.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/HrefInterpreter.cs @@ -21,7 +21,7 @@ public HrefInterpreter(bool exportFileLink, bool updateValue, string siteHostNam public bool CanInterpret(BaseSchema schema) { - return schema is {ContentType: ContentType.Href}; + return schema is { ContentType: ContentType.Href }; } public object Interpret(BaseSchema schema, object value, IProcessContext context, string path) diff --git a/src/Docfx.Build.SchemaDriven/Processors/MarkdownInterpreter.cs b/src/Docfx.Build.SchemaDriven/Processors/MarkdownInterpreter.cs index 2ac605ee96e..8e21df466ac 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/MarkdownInterpreter.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/MarkdownInterpreter.cs @@ -9,7 +9,7 @@ public class MarkdownInterpreter : IInterpreter { public bool CanInterpret(BaseSchema schema) { - return schema is {ContentType: ContentType.Markdown}; + return schema is { ContentType: ContentType.Markdown }; } public object Interpret(BaseSchema schema, object value, IProcessContext context, string path) diff --git a/src/Docfx.Build.SchemaDriven/Processors/Merger.cs b/src/Docfx.Build.SchemaDriven/Processors/Merger.cs index 3b6dadf990f..7df1113330d 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/Merger.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/Merger.cs @@ -135,11 +135,22 @@ private static bool TestKey(object source, object overrides, BaseSchema schema) { return false; } - return schema?.Properties != null && schema.Properties.Any(p => p.Value.MergeType == MergeType.Key) && schema.Properties.Where(p => p.Value.MergeType == MergeType.Key).All(p => + + var properties = schema?.Properties; + if (properties == null) { - (source as IDictionary).TryGetValue(p.Key, out var s); - (overrides as IDictionary).TryGetValue(p.Key, out var o); - return object.Equals(s, o); - }); + return false; + } + + var sourceDictionary = (IDictionary)source; + var overridesDictionary = (IDictionary)overrides; + return properties.Any(p => p.Value.MergeType == MergeType.Key) && + properties.Where(p => p.Value.MergeType == MergeType.Key) + .All(p => + { + sourceDictionary.TryGetValue(p.Key, out var s); + overridesDictionary.TryGetValue(p.Key, out var o); + return object.Equals(s, o); + }); } } diff --git a/src/Docfx.Build.SchemaDriven/Processors/ProcessContext.cs b/src/Docfx.Build.SchemaDriven/Processors/ProcessContext.cs index 4fe3d6bc2fd..3d9054ede99 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/ProcessContext.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/ProcessContext.cs @@ -51,12 +51,12 @@ public ProcessContext(IHostService hs, FileModel fm, IDocumentBuildContext bc, M _model = fm; OriginalFileAndType = fm.OriginalFileAndType; FileAndType = fm.FileAndType; - Uids = new List(); - UidLinkSources = new Dictionary>(); - FileLinkSources = new Dictionary>(); - Dependency = new HashSet(); - XRefSpecs = new List(); - ExternalXRefSpecs = new List(); + Uids = []; + UidLinkSources = []; + FileLinkSources = []; + Dependency = []; + XRefSpecs = []; + ExternalXRefSpecs = []; Metadata = new Dictionary(); if (((IDictionary)fm.Properties).TryGetValue("PathProperties", out var properties)) { @@ -65,7 +65,7 @@ public ProcessContext(IHostService hs, FileModel fm, IDocumentBuildContext bc, M } else { - fm.Properties.PathProperties = PathProperties = new Dictionary>(); + fm.Properties.PathProperties = PathProperties = []; } Host = hs; diff --git a/src/Docfx.Build.SchemaDriven/Processors/XrefInterpreter.cs b/src/Docfx.Build.SchemaDriven/Processors/XrefInterpreter.cs index e4c0f1618f3..f2fe10dc811 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/XrefInterpreter.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/XrefInterpreter.cs @@ -19,7 +19,7 @@ public XrefInterpreter(bool aggregateXrefs, bool resolveXref) public bool CanInterpret(BaseSchema schema) { - return schema is {ContentType: ContentType.Xref}; + return schema is { ContentType: ContentType.Xref }; } public object Interpret(BaseSchema schema, object value, IProcessContext context, string path) @@ -61,7 +61,7 @@ private static void AddUidLinkSource(Dictionary> ui var file = source.Target; if (!uidLinkSources.TryGetValue(file, out List sources)) { - sources = new List(); + sources = []; uidLinkSources[file] = sources; } sources.Add(source); diff --git a/src/Docfx.Build.SchemaDriven/Processors/XrefPropertiesInterpreter.cs b/src/Docfx.Build.SchemaDriven/Processors/XrefPropertiesInterpreter.cs index a6df05fedd5..a101c6bb28f 100644 --- a/src/Docfx.Build.SchemaDriven/Processors/XrefPropertiesInterpreter.cs +++ b/src/Docfx.Build.SchemaDriven/Processors/XrefPropertiesInterpreter.cs @@ -62,7 +62,7 @@ public object Interpret(BaseSchema schema, object value, IProcessContext context Uid = uid }; - var parts = schema.XrefProperties ?? new List { "name", "fullName" }; + var parts = schema.XrefProperties ?? ["name", "fullName"]; var root = context.GetModel(); foreach (var part in parts.Distinct()) { diff --git a/src/Docfx.Build.SchemaDriven/ValidateFragmentsHandler.cs b/src/Docfx.Build.SchemaDriven/ValidateFragmentsHandler.cs index 4d4aa003a70..0a8ff8d107b 100644 --- a/src/Docfx.Build.SchemaDriven/ValidateFragmentsHandler.cs +++ b/src/Docfx.Build.SchemaDriven/ValidateFragmentsHandler.cs @@ -10,7 +10,7 @@ namespace Docfx.Build.SchemaDriven; public class ValidateFragmentsHandler : ISchemaFragmentsHandler { - private readonly Dictionary _isMissingUidsLogged = new(); + private readonly Dictionary _isMissingUidsLogged = []; public void HandleUid(string uidKey, YamlMappingNode node, Dictionary fragments, BaseSchema schema, string oPathPrefix, string uid) { diff --git a/src/Docfx.Build.TagLevelRestApi/SplitRestApiToTagLevel.cs b/src/Docfx.Build.TagLevelRestApi/SplitRestApiToTagLevel.cs index dacd4b03c3a..021a9aabac4 100644 --- a/src/Docfx.Build.TagLevelRestApi/SplitRestApiToTagLevel.cs +++ b/src/Docfx.Build.TagLevelRestApi/SplitRestApiToTagLevel.cs @@ -82,7 +82,7 @@ private static Tuple, TreeItemRestructure> SplitModelToOperation // Only keep not tagged children in root model var groupedUids = splittedModels.SelectMany(m => m.Uids).Select(u => u.Name).ToList(); - content.Tags = new List(); + content.Tags = []; content.Children = content.Children.Where(child => !groupedUids.Contains(child.Uid)).ToList(); content.Metadata["_isSplittedByTag"] = true; model.Content = content; @@ -118,7 +118,7 @@ private static IEnumerable GenerateTagModels(RestApiRo Description = tag.Description, Documentation = tag.Documentation, Children = tagChildren, - Tags = new List(), + Tags = [], Metadata = MergeTagMetadata(root, tag) }; } @@ -131,7 +131,7 @@ private static IEnumerable GetChildrenByTag(RestApiRo var children = root.Children.Where(child => child.Tags != null && tagName == child.Tags.FirstOrDefault()); foreach (var child in children) { - child.Tags = new List(); + child.Tags = []; yield return child; } } diff --git a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiBuildOutput.cs b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiBuildOutput.cs index f5284e1a38d..58a24f7b476 100644 --- a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiBuildOutput.cs +++ b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiBuildOutput.cs @@ -175,5 +175,5 @@ public class ApiBuildOutput [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiExceptionInfoBuildOutput.cs b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiExceptionInfoBuildOutput.cs index d9963944c0f..f20e4133064 100644 --- a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiExceptionInfoBuildOutput.cs +++ b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiExceptionInfoBuildOutput.cs @@ -24,5 +24,5 @@ public class ApiExceptionInfoBuildOutput [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiInheritanceTreeBuildOutput.cs b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiInheritanceTreeBuildOutput.cs index 17666ce6e3f..eb063276c24 100644 --- a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiInheritanceTreeBuildOutput.cs +++ b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiInheritanceTreeBuildOutput.cs @@ -30,5 +30,5 @@ public class ApiInheritanceTreeBuildOutput [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiNames.cs b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiNames.cs index 687702098cc..eaf537642ba 100644 --- a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiNames.cs +++ b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiNames.cs @@ -45,5 +45,5 @@ public class ApiNames [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiParameterBuildOutput.cs b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiParameterBuildOutput.cs index f9e9419457b..56f95c95805 100644 --- a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiParameterBuildOutput.cs +++ b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiParameterBuildOutput.cs @@ -39,5 +39,5 @@ public class ApiParameterBuildOutput [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiSyntaxBuildOutput.cs b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiSyntaxBuildOutput.cs index 70490d78d8c..901b101b529 100644 --- a/src/Docfx.Build.UniversalReference/BuildOutputs/ApiSyntaxBuildOutput.cs +++ b/src/Docfx.Build.UniversalReference/BuildOutputs/ApiSyntaxBuildOutput.cs @@ -35,5 +35,5 @@ public class ApiSyntaxBuildOutput [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Build.UniversalReference/FillReferenceInformation.cs b/src/Docfx.Build.UniversalReference/FillReferenceInformation.cs index 3f0a238d371..f79670c0425 100644 --- a/src/Docfx.Build.UniversalReference/FillReferenceInformation.cs +++ b/src/Docfx.Build.UniversalReference/FillReferenceInformation.cs @@ -20,16 +20,14 @@ public class FillReferenceInformation : BaseDocumentBuildStep public override void Postbuild(ImmutableList models, IHostService host) { - if (models.Count > 0) + foreach (var model in models) { - foreach (var model in models) + if (model.Type != DocumentType.Article) { - if (model.Type != DocumentType.Article) - { - continue; - } - FillCore((PageViewModel)model.Content, host); + continue; } + + FillCore((PageViewModel)model.Content, host); } } diff --git a/src/Docfx.Build.UniversalReference/ModelConverter.cs b/src/Docfx.Build.UniversalReference/ModelConverter.cs index e0bbd94a4e8..9d09fc18c52 100644 --- a/src/Docfx.Build.UniversalReference/ModelConverter.cs +++ b/src/Docfx.Build.UniversalReference/ModelConverter.cs @@ -31,7 +31,7 @@ public static ApiBuildOutput ToApiBuildOutput(PageViewModel model) Dictionary references = null; if (model.References != null) { - references = new Dictionary(); + references = []; foreach (var reference in model.References .Where(r => !string.IsNullOrEmpty(r.Uid)) .Select(ToReferenceApiNames)) @@ -44,7 +44,7 @@ public static ApiBuildOutput ToApiBuildOutput(PageViewModel model) var childUids = model.Items[0].Children ?? Enumerable.Empty() .Concat(model.Items[0].ChildrenInDevLangs != null ? model.Items[0].ChildrenInDevLangs.SelectMany(kv => kv.Value) - : Enumerable.Empty()) + : []) .Distinct(); var children = new Dictionary(); if (model.References != null) @@ -388,7 +388,7 @@ public static List> ToApiListInDevLangs(T defaultValu } var result = new List>(); - values ??= new SortedList(); + values ??= []; foreach (var language in supportedLanguages) { result.Add(new ApiLanguageValuePair diff --git a/src/Docfx.Build.UniversalReference/UniversalReferenceDocumentProcessor.cs b/src/Docfx.Build.UniversalReference/UniversalReferenceDocumentProcessor.cs index 5b0ac2662bb..f8bfa207266 100644 --- a/src/Docfx.Build.UniversalReference/UniversalReferenceDocumentProcessor.cs +++ b/src/Docfx.Build.UniversalReference/UniversalReferenceDocumentProcessor.cs @@ -159,34 +159,25 @@ private static IEnumerable GetXRefInfo( Href = ((RelativePath)key).UrlEncode().ToString(), CommentId = item.CommentId, }; - if (item.Names.Count > 0) + foreach (var pair in item.Names) { - foreach (var pair in item.Names) - { - result["name." + pair.Key] = pair.Value; - } + result["name." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.FullName)) { result["fullName"] = item.FullName; } - if (item.FullNames.Count > 0) + foreach (var pair in item.FullNames) { - foreach (var pair in item.FullNames) - { - result["fullName." + pair.Key] = pair.Value; - } + result["fullName." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.NameWithType)) { result["nameWithType"] = item.NameWithType; } - if (item.NamesWithType.Count > 0) + foreach (var pair in item.NamesWithType) { - foreach (var pair in item.NamesWithType) - { - result["nameWithType." + pair.Key] = pair.Value; - } + result["nameWithType." + pair.Key] = pair.Value; } yield return result; @@ -217,34 +208,25 @@ private static XRefSpec GetXRefSpecFromReference(ReferenceViewModel item) Href = item.Href, CommentId = item.CommentId, }; - if (item.NameInDevLangs.Count > 0) + foreach (var pair in item.NameInDevLangs) { - foreach (var pair in item.NameInDevLangs) - { - result["name." + pair.Key] = pair.Value; - } + result["name." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.FullName)) { result["fullName"] = item.FullName; } - if (item.FullNameInDevLangs.Count > 0) + foreach (var pair in item.FullNameInDevLangs) { - foreach (var pair in item.FullNameInDevLangs) - { - result["fullName." + pair.Key] = pair.Value; - } + result["fullName." + pair.Key] = pair.Value; } if (!string.IsNullOrEmpty(item.NameWithType)) { result["nameWithType"] = item.NameWithType; } - if (item.NameWithTypeInDevLangs.Count > 0) + foreach (var pair in item.NameWithTypeInDevLangs) { - foreach (var pair in item.NameWithTypeInDevLangs) - { - result["nameWithType." + pair.Key] = pair.Value; - } + result["nameWithType." + pair.Key] = pair.Value; } if (item.Additional != null) { diff --git a/src/Docfx.Build/ApiPage/ApiPageMarkdownTemplate.cs b/src/Docfx.Build/ApiPage/ApiPageMarkdownTemplate.cs index ba38cd3e36c..6972f574a94 100644 --- a/src/Docfx.Build/ApiPage/ApiPageMarkdownTemplate.cs +++ b/src/Docfx.Build/ApiPage/ApiPageMarkdownTemplate.cs @@ -13,7 +13,7 @@ public static string Render(ApiPage page) { return string.Concat(page.body.Select(Block)); - FormattableString? Block(Block block) => block.Value switch + FormattableString Block(Block block) => block.Value switch { Markdown markdown => Markdown(markdown), Heading heading => Heading(heading), @@ -25,9 +25,9 @@ public static string Render(ApiPage page) Parameters parameters => Parameters(parameters), }; - FormattableString? Markdown(Markdown markdown) => $"{markdown.markdown}\n\n"; + FormattableString Markdown(Markdown markdown) => $"{markdown.markdown}\n\n"; - FormattableString? Heading(Heading heading) => heading.Value switch + FormattableString Heading(Heading heading) => heading.Value switch { H1 h1 => ToHeading(1, h1.h1, h1.id), H2 h2 => ToHeading(2, h2.h2, h2.id), @@ -37,7 +37,7 @@ public static string Render(ApiPage page) H6 h6 => ToHeading(6, h6.h6, h6.id), }; - FormattableString? Api(Api api) => api.Value switch + FormattableString Api(Api api) => api.Value switch { Api1 api1 => ToHeading(1, api1.api1, api1.id), Api2 api2 => ToHeading(2, api2.api2, api2.id), @@ -45,19 +45,19 @@ public static string Render(ApiPage page) Api4 api4 => ToHeading(4, api4.api4, api4.id), }; - FormattableString? ToHeading(int level, string title, string? id = null) => + FormattableString ToHeading(int level, string title, string? id = null) => $"{new string('#', level)}{(string.IsNullOrEmpty(id) ? null : $" ")} {Escape(title)}\n\n"; - FormattableString? Facts(Facts facts) => + FormattableString Facts(Facts facts) => $"{string.Concat(facts.facts.Select(fact => $"{Escape(fact.name)}: {Inline(fact.value)} \n"))}\n"; - FormattableString? List(List list) => + FormattableString List(List list) => $"{string.Join(", \n", list.list.Select(Inline))}\n\n"; - FormattableString? Inheritance(Inheritance inheritance) => + FormattableString Inheritance(Inheritance inheritance) => $"{string.Join(" \u2190 \n", inheritance.inheritance.Select(Inline))}\n\n"; - FormattableString? Code(Code code) => + FormattableString Code(Code code) => $""" ```{code.languageId ?? page.languageId} {code.code} @@ -66,7 +66,7 @@ public static string Render(ApiPage page) """; - FormattableString? Parameters(Parameters parameters) => + FormattableString Parameters(Parameters parameters) => $"{string.Concat(parameters.parameters.Select(Parameter))}"; FormattableString? Parameter(Parameter parameter) => diff --git a/src/Docfx.Build/CompilePhaseHandler.cs b/src/Docfx.Build/CompilePhaseHandler.cs index 71da01dbaf2..e766f87abb9 100644 --- a/src/Docfx.Build/CompilePhaseHandler.cs +++ b/src/Docfx.Build/CompilePhaseHandler.cs @@ -10,7 +10,7 @@ namespace Docfx.Build.Engine; internal class CompilePhaseHandler { - private readonly List _restructions = new(); + private readonly List _restructions = []; public DocumentBuildContext Context { get; } diff --git a/src/Docfx.Build/DocumentBuildContext.cs b/src/Docfx.Build/DocumentBuildContext.cs index 9f8e0ac58f0..f38bedb442d 100644 --- a/src/Docfx.Build/DocumentBuildContext.cs +++ b/src/Docfx.Build/DocumentBuildContext.cs @@ -126,7 +126,7 @@ from u in xrefMaps public ConcurrentDictionary> TocMap { get; } = new(FilePathComparer.OSPlatformSensitiveStringComparer); - public HashSet XRef { get; } = new(); + public HashSet XRef { get; } = []; public string RootTocPath { get; } @@ -136,7 +136,7 @@ from u in xrefMaps public CancellationToken CancellationToken { get; } = CancellationToken.None; - internal ConcurrentBag ManifestItems { get; } = new(); + internal ConcurrentBag ManifestItems { get; } = []; private ConcurrentDictionary ExternalXRefSpec { get; } = new(); diff --git a/src/Docfx.Build/DocumentBuilder.cs b/src/Docfx.Build/DocumentBuilder.cs index 6b9c3f72813..33e141fc275 100644 --- a/src/Docfx.Build/DocumentBuilder.cs +++ b/src/Docfx.Build/DocumentBuilder.cs @@ -9,7 +9,6 @@ using Docfx.Common; using Docfx.MarkdigEngine; using Docfx.Plugins; -using Newtonsoft.Json; namespace Docfx.Build.Engine; @@ -27,7 +26,7 @@ public class DocumentBuilder : IDisposable public DocumentBuilder(IEnumerable assemblies, ImmutableArray postProcessorNames) { Logger.LogVerbose("Loading plug-ins and post-processors..."); - var assemblyList = assemblies?.ToList() ?? new List(); + var assemblyList = assemblies?.ToList() ?? []; assemblyList.Add(typeof(DocumentBuilder).Assembly); _container = CompositionContainer.GetContainer(assemblyList); _container.SatisfyImports(this); diff --git a/src/Docfx.Build/FileCollection.cs b/src/Docfx.Build/FileCollection.cs index 48b557d0ee3..d330383a373 100644 --- a/src/Docfx.Build/FileCollection.cs +++ b/src/Docfx.Build/FileCollection.cs @@ -8,7 +8,7 @@ namespace Docfx.Build.Engine; public class FileCollection { - private readonly List _files = new(); + private readonly List _files = []; public int Count => _files.Count; diff --git a/src/Docfx.Build/HostService.cs b/src/Docfx.Build/HostService.cs index f71caf153f9..409baa2dd11 100644 --- a/src/Docfx.Build/HostService.cs +++ b/src/Docfx.Build/HostService.cs @@ -12,7 +12,7 @@ namespace Docfx.Build.Engine; [Export(typeof(IHostService))] class HostService : IHostService { - private Dictionary> _uidIndex = new(); + private Dictionary> _uidIndex = []; public TemplateProcessor Template { get; set; } @@ -65,7 +65,7 @@ public ImmutableList LookupByUid(string uid) { return result.ToImmutableList(); } - return ImmutableList.Empty; + return []; } public MarkupResult Markup(string markdown, FileAndType ft) diff --git a/src/Docfx.Build/LinkPhaseHandler.cs b/src/Docfx.Build/LinkPhaseHandler.cs index 5957e92252d..519c5746b73 100644 --- a/src/Docfx.Build/LinkPhaseHandler.cs +++ b/src/Docfx.Build/LinkPhaseHandler.cs @@ -35,7 +35,7 @@ public void Handle(List hostServices, int maxParallelism) private void Save(List hostServices, int maxParallelism) { - _manifestWithContext = new List(); + _manifestWithContext = []; foreach (var hostService in hostServices) { _manifestWithContext.AddRange(ExportManifest(hostService)); diff --git a/src/Docfx.Build/ManifestProcessor.cs b/src/Docfx.Build/ManifestProcessor.cs index e135b74a317..37e60352b6f 100644 --- a/src/Docfx.Build/ManifestProcessor.cs +++ b/src/Docfx.Build/ManifestProcessor.cs @@ -29,7 +29,7 @@ public ManifestProcessor(List manifestWithContext, Docu // E.g. we can set TOC model to be globally shared by every data model // Make sure it is single thread _globalMetadata = _templateProcessor.Tokens?.ToDictionary(pair => pair.Key, pair => (object)pair.Value) - ?? new Dictionary(); + ?? []; } public void Process() diff --git a/src/Docfx.Build/MarkupResultUtility.cs b/src/Docfx.Build/MarkupResultUtility.cs index 53a642c18cb..754c58e4860 100644 --- a/src/Docfx.Build/MarkupResultUtility.cs +++ b/src/Docfx.Build/MarkupResultUtility.cs @@ -109,7 +109,7 @@ where string.Equals(attr.Name, "src", StringComparison.OrdinalIgnoreCase) || if (!fileLinkSources.TryGetValue(file, out List sources)) { - sources = new List(); + sources = []; fileLinkSources[file] = sources; } sources.Add(new LinkSourceInfo diff --git a/src/Docfx.Build/PostProcessors/ExtractSearchIndex.cs b/src/Docfx.Build/PostProcessors/ExtractSearchIndex.cs index 1882c91b598..ff8a7f9470d 100644 --- a/src/Docfx.Build/PostProcessors/ExtractSearchIndex.cs +++ b/src/Docfx.Build/PostProcessors/ExtractSearchIndex.cs @@ -9,15 +9,17 @@ using Docfx.Common; using Docfx.Plugins; using HtmlAgilityPack; -using Newtonsoft.Json; namespace Docfx.Build.Engine; [Export(nameof(ExtractSearchIndex), typeof(IPostProcessor))] -class ExtractSearchIndex : IPostProcessor +partial class ExtractSearchIndex : IPostProcessor { - private static readonly Regex s_regexWhiteSpace = new(@"\s+", RegexOptions.Compiled); + [GeneratedRegex(@"\s+")] + private static partial Regex s_regexWhiteSpace(); + private static readonly Regex s_regexCase = new(@"[a-z0-9]+|[A-Z0-9]+[a-z0-9]*|[0-9]+", RegexOptions.Compiled); + private static readonly HashSet s_htmlInlineTags = new(StringComparer.OrdinalIgnoreCase) { "a", "area", "del", "ins", "link", "map", "meta", "abbr", "audio", "b", "bdo", "button", "canvas", "cite", "code", "command", "data", @@ -173,7 +175,7 @@ private static string NormalizeContent(string str) return string.Empty; } str = WebUtility.HtmlDecode(str); - return s_regexWhiteSpace.Replace(str, " ").Trim(); + return s_regexWhiteSpace().Replace(str, " ").Trim(); } private static string[] GetStems(string str) diff --git a/src/Docfx.Build/PostProcessors/HtmlPostProcessor.cs b/src/Docfx.Build/PostProcessors/HtmlPostProcessor.cs index a052eaed954..ad06f41dc91 100644 --- a/src/Docfx.Build/PostProcessors/HtmlPostProcessor.cs +++ b/src/Docfx.Build/PostProcessors/HtmlPostProcessor.cs @@ -15,7 +15,7 @@ sealed class HtmlPostProcessor : IPostProcessor { private static readonly UTF8Encoding Utf8EncodingWithoutBom = new(false); - public List Handlers { get; } = new(); + public List Handlers { get; } = []; private bool _handlerInitialized; diff --git a/src/Docfx.Build/PostProcessors/ValidateBookmark.cs b/src/Docfx.Build/PostProcessors/ValidateBookmark.cs index 04199ecbe4a..d3e4d46aabb 100644 --- a/src/Docfx.Build/PostProcessors/ValidateBookmark.cs +++ b/src/Docfx.Build/PostProcessors/ValidateBookmark.cs @@ -12,7 +12,7 @@ namespace Docfx.Build.Engine; sealed class ValidateBookmark : HtmlDocumentHandler { private static readonly string XPathTemplate = "//*/@{0}"; - private static readonly HashSet WhiteList = new() { "top" }; + private static readonly HashSet WhiteList = ["top"]; /// /// bookmarks mapping from output file -> bookmarks /// diff --git a/src/Docfx.Build/ResourceFileReaders/LocalFileResourceReader.cs b/src/Docfx.Build/ResourceFileReaders/LocalFileResourceReader.cs index 9b38e384863..21a7f8b44c4 100644 --- a/src/Docfx.Build/ResourceFileReaders/LocalFileResourceReader.cs +++ b/src/Docfx.Build/ResourceFileReaders/LocalFileResourceReader.cs @@ -48,7 +48,7 @@ private IEnumerable GetFiles(string directory, string searchPattern, int { if (searchLevel < 1) { - return Enumerable.Empty(); + return []; } var files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly); var dirs = Directory.GetDirectories(directory); diff --git a/src/Docfx.Build/SingleDocumentBuilder.cs b/src/Docfx.Build/SingleDocumentBuilder.cs index f1cf5ee4aa5..09c7149b840 100644 --- a/src/Docfx.Build/SingleDocumentBuilder.cs +++ b/src/Docfx.Build/SingleDocumentBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; -using System.Threading; using Docfx.Common; using Docfx.Plugins; @@ -31,8 +30,8 @@ public static ImmutableList Build( processor, parameters.Files.EnumerateFiles()); - new CompilePhaseHandler(null).Handle(new List { hostService }, parameters.MaxParallelism); - new LinkPhaseHandler(null, null).Handle(new List { hostService }, parameters.MaxParallelism); + new CompilePhaseHandler(null).Handle([hostService], parameters.MaxParallelism); + new LinkPhaseHandler(null, null).Handle([hostService], parameters.MaxParallelism); return hostService.Models; } @@ -75,13 +74,13 @@ public Manifest Build(DocumentBuildParameters parameters, IMarkdownService markd Xrefmap = ExportXRefMap(parameters, context), SourceBasePath = StringExtension.ToNormalizedPath(EnvironmentContext.BaseDirectory), }; - manifest.Groups = new List - { + manifest.Groups = + [ new(parameters.GroupInfo) { XRefmap = (string)manifest.Xrefmap } - }; + ]; return manifest; } @@ -103,7 +102,7 @@ from p in (from processor in processors where priority != ProcessingPriority.NotSupported group processor by priority into ps orderby ps.Key descending - select ps.ToList()).FirstOrDefault() ?? new List { null } + select ps.ToList()).FirstOrDefault() ?? [null] group file by p).ToList(); var toHandleItems = files.Where(s => s.Key != null); diff --git a/src/Docfx.Build/TableOfContents/BuildTocDocument.cs b/src/Docfx.Build/TableOfContents/BuildTocDocument.cs index d2c7b63318f..b395e758cd0 100644 --- a/src/Docfx.Build/TableOfContents/BuildTocDocument.cs +++ b/src/Docfx.Build/TableOfContents/BuildTocDocument.cs @@ -84,7 +84,7 @@ void UpdateDependencies(HashSet linkTos, Dictionary> dict, string path, LinkSourceInfo source) - => dict[path] = dict.TryGetValue(path, out var sources) ? sources.Add(source) : ImmutableList.Create(source); + => dict[path] = dict.TryGetValue(path, out var sources) ? sources.Add(source) : [source]; private static LinkSourceInfo GetLinkSourceInfo(string path, string anchor, string source, string includedFrom) { diff --git a/src/Docfx.Build/TableOfContents/MarkdownTocReader.cs b/src/Docfx.Build/TableOfContents/MarkdownTocReader.cs index 0f91c0b7acd..db4a3728e6c 100644 --- a/src/Docfx.Build/TableOfContents/MarkdownTocReader.cs +++ b/src/Docfx.Build/TableOfContents/MarkdownTocReader.cs @@ -8,7 +8,7 @@ namespace Docfx.Build.TableOfContents; -public static class MarkdownTocReader +public static partial class MarkdownTocReader { private const string ContinuableCharacters = ".,;:!?~"; private const string StopCharacters = @"\s\""\'<>"; @@ -68,7 +68,7 @@ internal sealed class InitialState : ParseState public InitialState(string filePath) { Parents = new Stack(); - Root = new(); + Root = []; FilePath = filePath; } public override int Level => 0; @@ -144,7 +144,7 @@ protected ParseState ApplyCore(ParseState state, int level, string text, string if (state.Parents.Count > 0) { var parent = state.Parents.Peek(); - parent.Items ??= new(); + parent.Items ??= []; parent.Items.Add(item); } else @@ -166,20 +166,22 @@ protected ParseState ApplyCore(ParseState state, int level, string text, string /// 2. # [tocTitle](@uid) /// 3. # [tocTitle](xref:uid) /// - internal sealed class TopicTocParseRule : ParseRule + internal sealed partial class TopicTocParseRule : ParseRule { - private static readonly Regex UidRegex = new(@"^\s*(?:xref:|@)(\s*?\S+?[\s\S]*?)\s*$", RegexOptions.Compiled); - public static readonly Regex TocRegex = - new(@"^(?#+)(( |\t)*)\[(?.+)\]\((?(?!http[s]?://).*?)(\)| ""(?.*)""\))(?:( |\t)+#*)?( |\t)*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex(@"^\s*(?:xref:|@)(\s*?\S+?[\s\S]*?)\s*$")] + private static partial Regex UidRegex(); - public override Match Match(string text) => TocRegex.Match(text); + [GeneratedRegex(@"^(?#+)(( |\t)*)\[(?.+)\]\((?(?!http[s]?://).*?)(\)| ""(?.*)""\))(?:( |\t)+#*)?( |\t)*(\n|$)")] + private static partial Regex TocRegex(); + + public override Match Match(string text) => TocRegex().Match(text); public override ParseState Apply(ParseState state, Match match) { var tocLink = match.Groups["tocLink"].Value; var tocTitle = match.Groups["tocTitle"].Value; var headerLevel = match.Groups["headerLevel"].Value.Length; - var uidMatch = UidRegex.Match(tocLink); + var uidMatch = UidRegex().Match(tocLink); string tocDisplayTitle = null; var displayGrp = match.Groups["displayText"]; @@ -202,19 +204,20 @@ public override ParseState Apply(ParseState state, Match match) /// 1. /// 2. /// - internal sealed class TopicXrefAutoLinkTocParseRule : ParseRule + internal sealed partial class TopicXrefAutoLinkTocParseRule : ParseRule { - public static readonly Regex XrefAutoLinkTocRegex = - new($@"^(#+)(?: |\t)*{XrefAutoLinkRegexString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled); - public static readonly Regex XrefAutoLinkWithQuoteTocRegex = - new($@"^(#+)(?: |\t)*{XrefAutoLinkRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex($@"^(#+)(?: |\t)*{XrefAutoLinkRegexString}( |\t)*#*( |\t)*(\n|$)")] + private static partial Regex XrefAutoLinkTocRegex(); + + [GeneratedRegex($@"^(#+)(?: |\t)*{XrefAutoLinkRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)")] + private static partial Regex XrefAutoLinkWithQuoteTocRegex(); public override Match Match(string text) { - var match = XrefAutoLinkWithQuoteTocRegex.Match(text); + var match = XrefAutoLinkWithQuoteTocRegex().Match(text); if (match.Length == 0) { - match = XrefAutoLinkTocRegex.Match(text); + match = XrefAutoLinkTocRegex().Match(text); } return match; @@ -226,19 +229,20 @@ public override ParseState Apply(ParseState state, Match match) } } - internal sealed class TopicXrefShortcutTocParseRule : ParseRule + internal sealed partial class TopicXrefShortcutTocParseRule : ParseRule { - public static readonly Regex XrefShortcutTocRegex = - new($@"^(#+)(?: |\t)*{XrefShortcutRegexString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled); - public static readonly Regex XrefShortcutTocWithQuoteTocRegex = - new($@"^(#+)(?: |\t)*{XrefShortcutRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex($@"^(#+)(?: |\t)*{XrefShortcutRegexString}( |\t)*#*( |\t)*(\n|$)")] + private static partial Regex XrefShortcutTocRegex(); + + [GeneratedRegex($@"^(#+)(?: |\t)*{XrefShortcutRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)")] + private static partial Regex XrefShortcutTocWithQuoteTocRegex(); public override Match Match(string text) { - var match = XrefShortcutTocWithQuoteTocRegex.Match(text); + var match = XrefShortcutTocWithQuoteTocRegex().Match(text); if (match.Length == 0) { - match = XrefShortcutTocRegex.Match(text); + match = XrefShortcutTocRegex().Match(text); } return match; @@ -250,12 +254,12 @@ public override ParseState Apply(ParseState state, Match match) } } - internal sealed class ExternalLinkTocParseRule : ParseRule + internal sealed partial class ExternalLinkTocParseRule : ParseRule { - public static readonly Regex TocRegex = - new(@"^(?#+)(( |\t)*)\[(?.+?)\]\((?(http[s]?://).*?)\)(?:( |\t)+#*)?( |\t)*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex(@"^(?#+)(( |\t)*)\[(?.+?)\]\((?(http[s]?://).*?)\)(?:( |\t)+#*)?( |\t)*(\n|$)")] + private static partial Regex TocRegex(); - public override Match Match(string text) => TocRegex.Match(text); + public override Match Match(string text) => TocRegex().Match(text); public override ParseState Apply(ParseState state, Match match) { @@ -263,12 +267,12 @@ public override ParseState Apply(ParseState state, Match match) } } - internal sealed class ContainerParseRule : ParseRule + internal sealed partial class ContainerParseRule : ParseRule { - public static readonly Regex ContainerRegex = - new(@"^(?#+)(( |\t)*)(?.+?)(?:( |\t)+#*)?( |\t)*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex(@"^(?#+)(( |\t)*)(?.+?)(?:( |\t)+#*)?( |\t)*(\n|$)")] + private static partial Regex ContainerRegex(); - public override Match Match(string text) => ContainerRegex.Match(text); + public override Match Match(string text) => ContainerRegex().Match(text); public override ParseState Apply(ParseState state, Match match) { @@ -276,22 +280,22 @@ public override ParseState Apply(ParseState state, Match match) } } - internal sealed class CommentParseRule : ParseRule + internal sealed partial class CommentParseRule : ParseRule { - public static readonly Regex CommentRegex = - new(@"^\s*\s*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex(@"^\s*\s*(\n|$)")] + private static partial Regex CommentRegex(); - public override Match Match(string text) => CommentRegex.Match(text); + public override Match Match(string text) => CommentRegex().Match(text); public override ParseState Apply(ParseState state, Match match) => state; } - internal sealed class WhitespaceParseRule : ParseRule + internal sealed partial class WhitespaceParseRule : ParseRule { - public static readonly Regex WhitespaceRegex = - new(@"^\s*(\n|$)", RegexOptions.Compiled); + [GeneratedRegex(@"^\s*(\n|$)")] + private static partial Regex WhitespaceRegex(); - public override Match Match(string text) => WhitespaceRegex.Match(text); + public override Match Match(string text) => WhitespaceRegex().Match(text); public override ParseState Apply(ParseState state, Match match) => state; } diff --git a/src/Docfx.Build/TableOfContents/TocDocumentProcessor.cs b/src/Docfx.Build/TableOfContents/TocDocumentProcessor.cs index 79172edce58..cc8d371c1d0 100644 --- a/src/Docfx.Build/TableOfContents/TocDocumentProcessor.cs +++ b/src/Docfx.Build/TableOfContents/TocDocumentProcessor.cs @@ -91,7 +91,7 @@ private void UpdateTocItemHref(TocItemViewModel toc, FileModel model, IDocumentB toc.OriginalTopicHref = null; includedFrom = toc.IncludedFrom ?? includedFrom; - if (toc.Items is {Count: > 0}) + if (toc.Items is { Count: > 0 }) { foreach (var item in toc.Items) { diff --git a/src/Docfx.Build/TableOfContents/TocResolver.cs b/src/Docfx.Build/TableOfContents/TocResolver.cs index 6ea34f31a3b..9c2f43e4944 100644 --- a/src/Docfx.Build/TableOfContents/TocResolver.cs +++ b/src/Docfx.Build/TableOfContents/TocResolver.cs @@ -11,7 +11,7 @@ namespace Docfx.Build.TableOfContents; class TocResolver { private readonly Dictionary _collection; - private readonly Dictionary _notInProjectTocCache = new(); + private readonly Dictionary _notInProjectTocCache = []; public TocResolver(Dictionary collection) { @@ -122,7 +122,7 @@ private TocItemInfo ResolveItemCore(TocItemInfo wrapper, Stack stac { case HrefType.AbsolutePath: case HrefType.RelativeFile: - if (item.Items is {Count: > 0}) + if (item.Items is { Count: > 0 }) { item.Items = new List(from i in item.Items select ResolveItem(new TocItemInfo(file, i), stack) into r diff --git a/src/Docfx.Build/TableOfContents/TocRestructureUtility.cs b/src/Docfx.Build/TableOfContents/TocRestructureUtility.cs index ead7255750e..464b9ea8f67 100644 --- a/src/Docfx.Build/TableOfContents/TocRestructureUtility.cs +++ b/src/Docfx.Build/TableOfContents/TocRestructureUtility.cs @@ -15,7 +15,7 @@ public static void Restructure(TocItemViewModel toc, IList { return; } - RestructureCore(toc, new(), restructures); + RestructureCore(toc, [], restructures); } private static void RestructureCore(TocItemViewModel item, List items, IList restructures) @@ -28,7 +28,7 @@ private static void RestructureCore(TocItemViewModel item, List 0}) + if (item.Items is { Count: > 0 }) { var parentItems = new List(item.Items); foreach (var i in item.Items) @@ -91,7 +91,7 @@ private static void RestructureItem(TocItemViewModel item, List GetTemplateDirectories(IEnumerable names) public void ProcessTheme(string outputDirectory, bool overwrite) { - if (_themes is {Count: > 0}) + if (_themes is { Count: > 0 }) { TryExportResourceFiles(_themes, outputDirectory, overwrite); Logger.LogInfo($"Theme(s) {_themes.ToDelimitedString()} applied."); @@ -124,7 +124,7 @@ private static void Copy(Action streamHandler, string filePath, bool ove try { var subfolder = Path.GetDirectoryName(filePath); - if (!string.IsNullOrEmpty(subfolder) && !Directory.Exists(subfolder)) + if (!string.IsNullOrEmpty(subfolder)) { Directory.CreateDirectory(subfolder); } diff --git a/src/Docfx.Build/TemplateProcessors/TemplateModelTransformer.cs b/src/Docfx.Build/TemplateProcessors/TemplateModelTransformer.cs index 57483f41930..59050dce421 100644 --- a/src/Docfx.Build/TemplateProcessors/TemplateModelTransformer.cs +++ b/src/Docfx.Build/TemplateProcessors/TemplateModelTransformer.cs @@ -5,7 +5,6 @@ using Docfx.Common; using Docfx.Plugins; using HtmlAgilityPack; -using Newtonsoft.Json; namespace Docfx.Build.Engine; @@ -265,7 +264,7 @@ private static string ExportModel(object model, string modelFileRelativePath, Ex private void TransformDocument(string result, string extension, IDocumentBuildContext context, string destFilePath, ManifestItem manifestItem, out List unresolvedXRefs) { - unresolvedXRefs = new List(); + unresolvedXRefs = []; using (var stream = EnvironmentContext.FileAbstractLayer.Create(destFilePath)) { using var sw = new StreamWriter(stream); @@ -293,7 +292,7 @@ private void TransformHtml(IDocumentBuildContext context, string html, string so HtmlDocument document = new(); document.LoadHtml(html); - unresolvedXRefs = new List(); + unresolvedXRefs = []; TransformXrefInHtml(context, sourceFilePath, destFilePath, document.DocumentNode, unresolvedXRefs); TransformLinkInHtml(context, sourceFilePath, destFilePath, document.DocumentNode); diff --git a/src/Docfx.Build/TemplateProcessors/ViewRenderers/MustacheTemplateRenderer.cs b/src/Docfx.Build/TemplateProcessors/ViewRenderers/MustacheTemplateRenderer.cs index 2d70a24fcde..758fe10a602 100644 --- a/src/Docfx.Build/TemplateProcessors/ViewRenderers/MustacheTemplateRenderer.cs +++ b/src/Docfx.Build/TemplateProcessors/ViewRenderers/MustacheTemplateRenderer.cs @@ -7,13 +7,18 @@ namespace Docfx.Build.Engine; -internal class MustacheTemplateRenderer : ITemplateRenderer +internal partial class MustacheTemplateRenderer : ITemplateRenderer { public const string Extension = ".tmpl"; - private static readonly Regex IncludeRegex = new(@"{{\s*!\s*include\s*\(:?(:?['""]?)\s*(?(.+?))\1\s*\)\s*}}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex MasterPageRegex = new(@"{{\s*!\s*master\s*\(:?(:?['""]?)\s*(?(.+?))\1\s*\)\s*}}\s*\n?", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex MasterPageBodyRegex = new(@"{{\s*!\s*body\s*}}\s*\n?", RegexOptions.Compiled | RegexOptions.IgnoreCase); + [GeneratedRegex(@"{{\s*!\s*include\s*\(:?(:?['""]?)\s*(?(.+?))\1\s*\)\s*}}", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-AU")] + private static partial Regex IncludeRegex(); + + [GeneratedRegex(@"{{\s*!\s*master\s*\(:?(:?['""]?)\s*(?(.+?))\1\s*\)\s*}}\s*\n?", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-AU")] + private static partial Regex MasterPageRegex(); + + [GeneratedRegex(@"{{\s*!\s*body\s*}}\s*\n?", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-AU")] + private static partial Regex MasterPageBodyRegex(); private readonly ResourceFileReader _reader; private readonly IStubbleRenderer _renderer; @@ -37,7 +42,7 @@ public MustacheTemplateRenderer(ResourceFileReader reader, ResourceInfo info, st }) .Build(); - var processedTemplate = ParseTemplateHelper.ExpandMasterPage(reader, info, MasterPageRegex, MasterPageBodyRegex); + var processedTemplate = ParseTemplateHelper.ExpandMasterPage(reader, info, MasterPageRegex(), MasterPageBodyRegex()); _template = processedTemplate; @@ -63,7 +68,7 @@ public string Render(object model) /// private IEnumerable ExtractDependencyResourceNames(string template) { - foreach (Match match in IncludeRegex.Matches(template)) + foreach (Match match in IncludeRegex().Matches(template)) { var filePath = match.Groups["file"].Value; foreach (var name in ParseTemplateHelper.GetResourceName(filePath, Path, _reader)) diff --git a/src/Docfx.Build/TemplateProcessors/ViewRenderers/ParseTemplateHelper.cs b/src/Docfx.Build/TemplateProcessors/ViewRenderers/ParseTemplateHelper.cs index a8585fef5a6..48330028fdd 100644 --- a/src/Docfx.Build/TemplateProcessors/ViewRenderers/ParseTemplateHelper.cs +++ b/src/Docfx.Build/TemplateProcessors/ViewRenderers/ParseTemplateHelper.cs @@ -7,9 +7,10 @@ namespace Docfx.Build.Engine; -internal static class ParseTemplateHelper +internal static partial class ParseTemplateHelper { - private static readonly Regex IsRegexPatternRegex = new(@"^\s*/(.*)/\s*$", RegexOptions.Compiled); + [GeneratedRegex(@"^\s*/(.*)/\s*$")] + private static partial Regex IsRegexPatternRegex(); public static string ExpandMasterPage(ResourceFileReader reader, ResourceInfo info, Regex masterRegex, Regex bodyRegex) { @@ -72,7 +73,7 @@ public static IEnumerable GetResourceName(string file, string templateNa file = file.Substring(2); } - var regexPatternMatch = IsRegexPatternRegex.Match(file); + var regexPatternMatch = IsRegexPatternRegex().Match(file); if (regexPatternMatch.Groups.Count > 1) { file = regexPatternMatch.Groups[1].Value; diff --git a/src/Docfx.Build/XRefMaps/XRefArchive.cs b/src/Docfx.Build/XRefMaps/XRefArchive.cs index 893dbae35aa..b63ad979c3c 100644 --- a/src/Docfx.Build/XRefMaps/XRefArchive.cs +++ b/src/Docfx.Build/XRefMaps/XRefArchive.cs @@ -71,7 +71,7 @@ public static XRefArchive Open(string file, XRefArchiveMode mode) } fs = File.Create(file); archive = new ZipArchive(fs, ZipArchiveMode.Update); - entries = new List(); + entries = []; break; default: throw new ArgumentOutOfRangeException(nameof(mode)); @@ -299,7 +299,7 @@ public void Dispose() bool IXRefContainer.IsEmbeddedRedirections => true; - IEnumerable IXRefContainer.GetRedirections() => Enumerable.Empty(); + IEnumerable IXRefContainer.GetRedirections() => []; public IXRefContainerReader GetReader() { diff --git a/src/Docfx.Build/XRefMaps/XRefArchiveBuilder.cs b/src/Docfx.Build/XRefMaps/XRefArchiveBuilder.cs index 61d2f99d36e..354e90d6fcc 100644 --- a/src/Docfx.Build/XRefMaps/XRefArchiveBuilder.cs +++ b/src/Docfx.Build/XRefMaps/XRefArchiveBuilder.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Threading; using Docfx.Common; namespace Docfx.Build.Engine; @@ -53,7 +52,7 @@ private async Task DownloadCoreAsync(Uri uri, XRefArchive xa, Cancellati // Sort is not needed if `map.Sorted == true`. // But there are some xrefmap files that is not propery sorted by using InvariantCulture. // (e.g. Unity xrefmap that maintained by community) - if (map.References is {Count: > 0}) + if (map.References is { Count: > 0 }) { map.References.Sort(XRefSpecUidComparer.Instance); map.Sorted = true; diff --git a/src/Docfx.Build/XRefMaps/XRefCollection.cs b/src/Docfx.Build/XRefMaps/XRefCollection.cs index 357a313bb99..b1c3eabf1df 100644 --- a/src/Docfx.Build/XRefMaps/XRefCollection.cs +++ b/src/Docfx.Build/XRefMaps/XRefCollection.cs @@ -29,8 +29,8 @@ public Task GetReaderAsync(string baseFolder, IReadOnlyLis private sealed class ReaderCreator { private readonly ImmutableList _uris; - private readonly HashSet _set = new(); - private readonly Dictionary, Uri> _processing = new(); + private readonly HashSet _set = []; + private readonly Dictionary, Uri> _processing = []; private readonly XRefMapDownloader _downloader; public ReaderCreator(ImmutableList uris, int maxParallelism, string baseFolder, IReadOnlyList fallbackFolders) diff --git a/src/Docfx.Build/XRefMaps/XRefMap.cs b/src/Docfx.Build/XRefMaps/XRefMap.cs index f376109837a..1699465440f 100644 --- a/src/Docfx.Build/XRefMaps/XRefMap.cs +++ b/src/Docfx.Build/XRefMaps/XRefMap.cs @@ -61,7 +61,7 @@ public class XRefMap : IXRefContainer [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Others { get; set; } = new(); + public Dictionary Others { get; set; } = []; public void Sort() { diff --git a/src/Docfx.Build/XRefMaps/XRefMapDownloader.cs b/src/Docfx.Build/XRefMaps/XRefMapDownloader.cs index 5a83901afd8..340df7e7729 100644 --- a/src/Docfx.Build/XRefMaps/XRefMapDownloader.cs +++ b/src/Docfx.Build/XRefMaps/XRefMapDownloader.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Diagnostics; using System.IO.Compression; using System.Net; using Docfx.Common; @@ -134,7 +132,7 @@ private static async ValueTask ReadLocalFileAsync(string filePat { using var reader = new StreamReader(stream); return YamlUtility.Deserialize(reader); - }; + } } } @@ -147,8 +145,7 @@ private static async ValueTask ReadLocalFileAsync(string filePat case ".yml": default: { - using var sr = File.OpenText(filePath); - return YamlUtility.Deserialize(sr); + return YamlUtility.Deserialize(filePath); } } } diff --git a/src/Docfx.Common/CompositeDictionary.cs b/src/Docfx.Common/CompositeDictionary.cs index 5415854b216..01b967a6561 100644 --- a/src/Docfx.Common/CompositeDictionary.cs +++ b/src/Docfx.Common/CompositeDictionary.cs @@ -192,7 +192,7 @@ private sealed class Entry public sealed class Builder { - private readonly List _entries = new(); + private readonly List _entries = []; internal Builder() { } diff --git a/src/Docfx.Common/FileAbstractLayer/EmptyFileReader.cs b/src/Docfx.Common/FileAbstractLayer/EmptyFileReader.cs index 07540ab2245..fe54c58038c 100644 --- a/src/Docfx.Common/FileAbstractLayer/EmptyFileReader.cs +++ b/src/Docfx.Common/FileAbstractLayer/EmptyFileReader.cs @@ -13,7 +13,7 @@ private EmptyFileReader() public PathMapping? FindFile(RelativePath file) => null; - public IEnumerable EnumerateFiles() => Enumerable.Empty(); + public IEnumerable EnumerateFiles() => []; public string GetExpectedPhysicalPath(RelativePath file) => null; } diff --git a/src/Docfx.Common/FileAbstractLayer/FileWriterBase.cs b/src/Docfx.Common/FileAbstractLayer/FileWriterBase.cs index 48ec883686a..f68ccb4567a 100644 --- a/src/Docfx.Common/FileAbstractLayer/FileWriterBase.cs +++ b/src/Docfx.Common/FileAbstractLayer/FileWriterBase.cs @@ -28,9 +28,7 @@ protected internal static void EnsureFolder(string folder) { return; } - if (!Directory.Exists(folder)) - { - Directory.CreateDirectory(folder); - } + + Directory.CreateDirectory(folder); } } diff --git a/src/Docfx.Common/FileMapping.cs b/src/Docfx.Common/FileMapping.cs index 451e2288289..9b89ecf8a7a 100644 --- a/src/Docfx.Common/FileMapping.cs +++ b/src/Docfx.Common/FileMapping.cs @@ -28,7 +28,7 @@ namespace Docfx; [System.Text.Json.Serialization.JsonConverter(typeof(FileMappingConverter.SystemTextJsonConverter))] public class FileMapping { - private readonly List _items = new(); + private readonly List _items = []; /// /// Flags to distinguish items are expanded or not. diff --git a/src/Docfx.Common/Git/GitUtility.cs b/src/Docfx.Common/Git/GitUtility.cs index dd3368e15ef..1901dab8e2e 100644 --- a/src/Docfx.Common/Git/GitUtility.cs +++ b/src/Docfx.Common/Git/GitUtility.cs @@ -48,7 +48,7 @@ record Repo(string path, string url, string branch); }; } - public static string? RawContentUrlToContentUrl(string rawUrl) + public static string RawContentUrlToContentUrl(string rawUrl) { // GitHub var url = GitHubUserContentRegex().Replace(rawUrl, string.IsNullOrEmpty(s_branch) ? "https://github.com/$1/$2/blob/$3/$4" : $"https://github.com/$1/$2/blob/{s_branch}/$4"); diff --git a/src/Docfx.Common/Json/FileMappingConverter.SystemTextJson.cs b/src/Docfx.Common/Json/FileMappingConverter.SystemTextJson.cs index 286cded2d1e..fb7da65e757 100644 --- a/src/Docfx.Common/Json/FileMappingConverter.SystemTextJson.cs +++ b/src/Docfx.Common/Json/FileMappingConverter.SystemTextJson.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; @@ -13,7 +12,7 @@ internal partial class FileMappingConverter { internal class SystemTextJsonConverter : JsonConverter { - public override FileMapping? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override FileMapping Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { diff --git a/src/Docfx.Common/Json/FileMappingConverter.cs b/src/Docfx.Common/Json/FileMappingConverter.cs index 65a4cd2dbe8..d0e9d03e734 100644 --- a/src/Docfx.Common/Json/FileMappingConverter.cs +++ b/src/Docfx.Common/Json/FileMappingConverter.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - namespace Docfx; internal partial class FileMappingConverter diff --git a/src/Docfx.Common/Json/JsonUtility.cs b/src/Docfx.Common/Json/JsonUtility.cs index b0c4d7ca1ac..de00f591944 100644 --- a/src/Docfx.Common/Json/JsonUtility.cs +++ b/src/Docfx.Common/Json/JsonUtility.cs @@ -1,13 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.IO; -using System.Reflection.PortableExecutable; -using System.Text.RegularExpressions; -using Docfx.Plugins; using Newtonsoft.Json; -using YamlDotNet.Serialization; namespace Docfx.Common; diff --git a/src/Docfx.Common/Json/NewtonsoftJson/ConvertToObjectHelper.cs b/src/Docfx.Common/Json/NewtonsoftJson/ConvertToObjectHelper.cs index 7e05c239676..6605967af4a 100644 --- a/src/Docfx.Common/Json/NewtonsoftJson/ConvertToObjectHelper.cs +++ b/src/Docfx.Common/Json/NewtonsoftJson/ConvertToObjectHelper.cs @@ -76,12 +76,12 @@ public static object ConvertStrongTypeToJObject(object raw) public static object ConvertExpandoObjectToObject(object raw) { - return ConvertExpandoObjectToObjectCore(raw, new Dictionary()); + return ConvertExpandoObjectToObjectCore(raw, []); } public static object ConvertToDynamic(object obj) { - return ConvertToDynamicCore(obj, new Dictionary()); + return ConvertToDynamicCore(obj, []); } private static object ConvertExpandoObjectToObjectCore(object obj, Dictionary cache) diff --git a/src/Docfx.Common/Json/System.Text.Json/SystemTextJsonUtility.cs b/src/Docfx.Common/Json/System.Text.Json/SystemTextJsonUtility.cs index e16fa005d79..1b3fd2d2aaa 100644 --- a/src/Docfx.Common/Json/System.Text.Json/SystemTextJsonUtility.cs +++ b/src/Docfx.Common/Json/System.Text.Json/SystemTextJsonUtility.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.IO; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/src/Docfx.Common/Loggers/CompositeLogListener.cs b/src/Docfx.Common/Loggers/CompositeLogListener.cs index 680c0618568..d6ed964219c 100644 --- a/src/Docfx.Common/Loggers/CompositeLogListener.cs +++ b/src/Docfx.Common/Loggers/CompositeLogListener.cs @@ -6,7 +6,7 @@ namespace Docfx.Common; public class CompositeLogListener : ILoggerListener { private readonly object _sync = new(); - private readonly List _listeners = new(); + private readonly List _listeners = []; public CompositeLogListener() { diff --git a/src/Docfx.Common/Path/PathUtility.cs b/src/Docfx.Common/Path/PathUtility.cs index 08437417e0a..e4673633f12 100644 --- a/src/Docfx.Common/Path/PathUtility.cs +++ b/src/Docfx.Common/Path/PathUtility.cs @@ -5,9 +5,11 @@ namespace Docfx.Common; -public static class PathUtility +public static partial class PathUtility { - private static readonly Regex UriWithProtocol = new(@"^\w{2,}\:", RegexOptions.Compiled); + + [GeneratedRegex(@"^\w{2,}\:")] + private static partial Regex UriWithProtocol(); private static readonly char[] AdditionalInvalidChars = ":*".ToArray(); public static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars().Concat(AdditionalInvalidChars).ToArray(); @@ -98,7 +100,7 @@ public static bool IsRelativePath(string path) return false; } - if (UriWithProtocol.IsMatch(path)) + if (UriWithProtocol().IsMatch(path)) { return false; } diff --git a/src/Docfx.Common/Path/RelativePath.cs b/src/Docfx.Common/Path/RelativePath.cs index be23480f3a3..e1961551f48 100644 --- a/src/Docfx.Common/Path/RelativePath.cs +++ b/src/Docfx.Common/Path/RelativePath.cs @@ -54,7 +54,7 @@ public static RelativePath FromUrl(string path) public static bool IsRelativePath(string path) { // TODO : to merge with the PathUtility one - return path is {Length: > 0} && + return path is { Length: > 0 } && path[0] != '/' && path[0] != '\\' && path.IndexOfAny(PathUtility.InvalidPathChars) == -1; diff --git a/src/Docfx.Common/ResourcePools/ResourcePoolManager.cs b/src/Docfx.Common/ResourcePools/ResourcePoolManager.cs index 7c4a7ef68cf..d435b6a8cda 100644 --- a/src/Docfx.Common/ResourcePools/ResourcePoolManager.cs +++ b/src/Docfx.Common/ResourcePools/ResourcePoolManager.cs @@ -8,7 +8,7 @@ public class ResourcePoolManager where TResource : class { private readonly object _syncRoot = new(); - private readonly List _resources = new(); + private readonly List _resources = []; private readonly Stack _stack = new(); private readonly Func _creator; private readonly int _maxResourceCount; diff --git a/src/Docfx.DataContracts.Common/ExternalReferences/ExternalReferencePackageReader.cs b/src/Docfx.DataContracts.Common/ExternalReferences/ExternalReferencePackageReader.cs index d1e0f1ebdac..a5443e00417 100644 --- a/src/Docfx.DataContracts.Common/ExternalReferences/ExternalReferencePackageReader.cs +++ b/src/Docfx.DataContracts.Common/ExternalReferences/ExternalReferencePackageReader.cs @@ -74,7 +74,7 @@ private static Dictionary> GetUidEntryMap(ZipArchive zip) { if (!uidEntryMap.TryGetValue(entry.Uid, out List list)) { - list = new List(); + list = []; uidEntryMap[entry.Uid] = list; } list.Add(entry.FullName); diff --git a/src/Docfx.DataContracts.Common/ReferenceViewModel.cs b/src/Docfx.DataContracts.Common/ReferenceViewModel.cs index 7810640f850..96ca044f8de 100644 --- a/src/Docfx.DataContracts.Common/ReferenceViewModel.cs +++ b/src/Docfx.DataContracts.Common/ReferenceViewModel.cs @@ -50,7 +50,7 @@ public class ReferenceViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Name)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList NameInDevLangs { get; private set; } = new(); + public SortedList NameInDevLangs { get; private set; } = []; [YamlMember(Alias = Constants.PropertyName.NameWithType)] [JsonProperty(Constants.PropertyName.NameWithType)] @@ -60,7 +60,7 @@ public class ReferenceViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.NameWithType)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList NameWithTypeInDevLangs { get; private set; } = new(); + public SortedList NameWithTypeInDevLangs { get; private set; } = []; [YamlMember(Alias = Constants.PropertyName.FullName)] [JsonProperty(Constants.PropertyName.FullName)] @@ -70,17 +70,17 @@ public class ReferenceViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.FullName)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList FullNameInDevLangs { get; private set; } = new(); + public SortedList FullNameInDevLangs { get; private set; } = []; [ExtensibleMember(Constants.ExtensionMemberPrefix.Spec)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> Specs { get; private set; } = new(); + public SortedList> Specs { get; private set; } = []; [ExtensibleMember] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public Dictionary Additional { get; private set; } = new(); + public Dictionary Additional { get; private set; } = []; [EditorBrowsable(EditorBrowsableState.Never)] [YamlIgnore] diff --git a/src/Docfx.DataContracts.Common/TocItemViewModel.cs b/src/Docfx.DataContracts.Common/TocItemViewModel.cs index 81937c34265..3611d348b48 100644 --- a/src/Docfx.DataContracts.Common/TocItemViewModel.cs +++ b/src/Docfx.DataContracts.Common/TocItemViewModel.cs @@ -116,7 +116,7 @@ public class TocItemViewModel [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] [System.Text.Json.Serialization.JsonPropertyName("__metadata__")] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; [EditorBrowsable(EditorBrowsableState.Never)] [YamlIgnore] diff --git a/src/Docfx.DataContracts.RestApi/RestApiItemViewModelBase.cs b/src/Docfx.DataContracts.RestApi/RestApiItemViewModelBase.cs index 71ebce5c825..2b1900799e2 100644 --- a/src/Docfx.DataContracts.RestApi/RestApiItemViewModelBase.cs +++ b/src/Docfx.DataContracts.RestApi/RestApiItemViewModelBase.cs @@ -58,5 +58,5 @@ public class RestApiItemViewModelBase : IOverwriteDocumentViewModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.RestApi/RestApiParameterViewModel.cs b/src/Docfx.DataContracts.RestApi/RestApiParameterViewModel.cs index 2211bbc46fc..2407dad082a 100644 --- a/src/Docfx.DataContracts.RestApi/RestApiParameterViewModel.cs +++ b/src/Docfx.DataContracts.RestApi/RestApiParameterViewModel.cs @@ -25,5 +25,5 @@ public class RestApiParameterViewModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.RestApi/RestApiResponseViewModel.cs b/src/Docfx.DataContracts.RestApi/RestApiResponseViewModel.cs index a2fe4118d8e..b8823d01ef9 100644 --- a/src/Docfx.DataContracts.RestApi/RestApiResponseViewModel.cs +++ b/src/Docfx.DataContracts.RestApi/RestApiResponseViewModel.cs @@ -35,5 +35,5 @@ public class RestApiResponseViewModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.RestApi/RestApiTagViewModel.cs b/src/Docfx.DataContracts.RestApi/RestApiTagViewModel.cs index 5d095f314a6..b76ebe77298 100644 --- a/src/Docfx.DataContracts.RestApi/RestApiTagViewModel.cs +++ b/src/Docfx.DataContracts.RestApi/RestApiTagViewModel.cs @@ -48,5 +48,5 @@ public class RestApiTagViewModel : IOverwriteDocumentViewModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/ApiParameter.cs b/src/Docfx.DataContracts.UniversalReference/ApiParameter.cs index 2f367ac46ca..ec59c309591 100644 --- a/src/Docfx.DataContracts.UniversalReference/ApiParameter.cs +++ b/src/Docfx.DataContracts.UniversalReference/ApiParameter.cs @@ -48,5 +48,5 @@ public class ApiParameter [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/ArgumentInfo.cs b/src/Docfx.DataContracts.UniversalReference/ArgumentInfo.cs index 09f70d2c4b0..29389305a71 100644 --- a/src/Docfx.DataContracts.UniversalReference/ArgumentInfo.cs +++ b/src/Docfx.DataContracts.UniversalReference/ArgumentInfo.cs @@ -26,5 +26,5 @@ public class ArgumentInfo [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/AttributeInfo.cs b/src/Docfx.DataContracts.UniversalReference/AttributeInfo.cs index 073941c6215..faf7f48f60d 100644 --- a/src/Docfx.DataContracts.UniversalReference/AttributeInfo.cs +++ b/src/Docfx.DataContracts.UniversalReference/AttributeInfo.cs @@ -36,5 +36,5 @@ public class AttributeInfo [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/ExceptionInfo.cs b/src/Docfx.DataContracts.UniversalReference/ExceptionInfo.cs index c7fad174904..ca82920f156 100644 --- a/src/Docfx.DataContracts.UniversalReference/ExceptionInfo.cs +++ b/src/Docfx.DataContracts.UniversalReference/ExceptionInfo.cs @@ -29,5 +29,5 @@ public class ExceptionInfo [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/InheritanceTree.cs b/src/Docfx.DataContracts.UniversalReference/InheritanceTree.cs index 6d4cfc1fa15..467782f95af 100644 --- a/src/Docfx.DataContracts.UniversalReference/InheritanceTree.cs +++ b/src/Docfx.DataContracts.UniversalReference/InheritanceTree.cs @@ -32,5 +32,5 @@ public class InheritanceTree [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/ItemViewModel.cs b/src/Docfx.DataContracts.UniversalReference/ItemViewModel.cs index 7e81cbf246f..eb27364d38c 100644 --- a/src/Docfx.DataContracts.UniversalReference/ItemViewModel.cs +++ b/src/Docfx.DataContracts.UniversalReference/ItemViewModel.cs @@ -46,7 +46,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Parent)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList ParentInDevLangs { get; set; } = new(); + public SortedList ParentInDevLangs { get; set; } = []; [YamlMember(Alias = "package")] [JsonProperty("package")] @@ -57,7 +57,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember("package" + Constants.PrefixSeparator)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList PackageInDevLangs { get; set; } = new(); + public SortedList PackageInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.Children)] [MergeOption(MergeOption.Ignore)] // todo : merge more children @@ -69,7 +69,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Children)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> ChildrenInDevLangs { get; set; } = new(); + public SortedList> ChildrenInDevLangs { get; set; } = []; /// /// item's link URL @@ -93,7 +93,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Name)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList Names { get; set; } = new(); + public SortedList Names { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.NameWithType)] [JsonProperty(Constants.PropertyName.NameWithType)] @@ -103,7 +103,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.NameWithType)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList NamesWithType { get; set; } = new(); + public SortedList NamesWithType { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.FullName)] [JsonProperty(Constants.PropertyName.FullName)] @@ -113,7 +113,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.FullName)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList FullNames { get; set; } = new(); + public SortedList FullNames { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.Type)] [JsonProperty(Constants.PropertyName.Type)] @@ -131,7 +131,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Source)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList SourceInDevLangs { get; set; } = new(); + public SortedList SourceInDevLangs { get; set; } = []; /// /// item's documentation's source detail @@ -151,7 +151,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Assemblies)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> AssemblyNameListInDevLangs { get; set; } = new(); + public SortedList> AssemblyNameListInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.Namespace)] [JsonProperty(Constants.PropertyName.Namespace)] @@ -162,7 +162,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Namespace)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList NamespaceNameInDevLangs { get; set; } = new(); + public SortedList NamespaceNameInDevLangs { get; set; } = []; /// /// item's summary @@ -213,7 +213,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Overridden)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList OverriddenInDevLangs { get; set; } = new(); + public SortedList OverriddenInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.Overload)] [JsonProperty(Constants.PropertyName.Overload)] @@ -224,7 +224,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Overload)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList OverloadInDevLangs { get; set; } = new(); + public SortedList OverloadInDevLangs { get; set; } = []; [YamlMember(Alias = "exceptions")] [JsonProperty("exceptions")] @@ -234,7 +234,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Exceptions)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> ExceptionsInDevLangs { get; set; } = new(); + public SortedList> ExceptionsInDevLangs { get; set; } = []; [YamlMember(Alias = "seealso")] [JsonProperty("seealso")] @@ -278,12 +278,12 @@ public class ItemViewModel : IOverwriteDocumentViewModel [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] [UniqueIdentityReference] - public List InheritanceUidReference => GetInheritanceUidReference(Inheritance)?.ToList() ?? new List(); + public List InheritanceUidReference => GetInheritanceUidReference(Inheritance)?.ToList() ?? []; [ExtensibleMember(Constants.ExtensionMemberPrefix.Inheritance)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> InheritanceInDevLangs { get; set; } = new(); + public SortedList> InheritanceInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.DerivedClasses)] [MergeOption(MergeOption.Ignore)] @@ -295,7 +295,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.DerivedClasses)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> DerivedClassesInDevLangs { get; set; } = new(); + public SortedList> DerivedClassesInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.Implements)] [MergeOption(MergeOption.Ignore)] // todo : merge more children @@ -307,7 +307,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Implements)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> ImplementsInDevLangs { get; set; } = new(); + public SortedList> ImplementsInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.InheritedMembers)] [MergeOption(MergeOption.Ignore)] // todo : merge more children @@ -319,7 +319,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.InheritedMembers)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> InheritedMembersInDevLangs { get; set; } = new(); + public SortedList> InheritedMembersInDevLangs { get; set; } = []; [YamlMember(Alias = Constants.PropertyName.ExtensionMethods)] [MergeOption(MergeOption.Ignore)] // todo : merge more children @@ -331,7 +331,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.ExtensionMethods)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> ExtensionMethodsInDevLangs { get; set; } = new(); + public SortedList> ExtensionMethodsInDevLangs { get; set; } = []; /// /// item's conceptual @@ -352,13 +352,13 @@ public class ItemViewModel : IOverwriteDocumentViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Platform)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList> PlatformInDevLangs { get; set; } = new(); + public SortedList> PlatformInDevLangs { get; set; } = []; [ExtensibleMember] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] [System.Text.Json.Serialization.JsonPropertyName("__metadata__")] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; [EditorBrowsable(EditorBrowsableState.Never)] [YamlIgnore] diff --git a/src/Docfx.DataContracts.UniversalReference/LinkInfo.cs b/src/Docfx.DataContracts.UniversalReference/LinkInfo.cs index 7a18c78acfb..a5ad351e19a 100644 --- a/src/Docfx.DataContracts.UniversalReference/LinkInfo.cs +++ b/src/Docfx.DataContracts.UniversalReference/LinkInfo.cs @@ -39,7 +39,7 @@ public class LinkInfo [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } public enum LinkType diff --git a/src/Docfx.DataContracts.UniversalReference/NamedArgumentInfo.cs b/src/Docfx.DataContracts.UniversalReference/NamedArgumentInfo.cs index 112111323d2..ae2f0b8eed2 100644 --- a/src/Docfx.DataContracts.UniversalReference/NamedArgumentInfo.cs +++ b/src/Docfx.DataContracts.UniversalReference/NamedArgumentInfo.cs @@ -31,5 +31,5 @@ public class NamedArgumentInfo [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/PageViewModel.cs b/src/Docfx.DataContracts.UniversalReference/PageViewModel.cs index dbe7b09c8d1..efb67ce29c6 100644 --- a/src/Docfx.DataContracts.UniversalReference/PageViewModel.cs +++ b/src/Docfx.DataContracts.UniversalReference/PageViewModel.cs @@ -15,14 +15,14 @@ public class PageViewModel [YamlMember(Alias = "items")] [JsonProperty("items")] [JsonPropertyName("items")] - public List Items { get; set; } = new(); + public List Items { get; set; } = []; [YamlMember(Alias = "references")] [JsonProperty("references")] [JsonPropertyName("references")] [UniqueIdentityReferenceIgnore] [MarkdownContentIgnore] - public List References { get; set; } = new(); + public List References { get; set; } = []; [YamlMember(Alias = "shouldSkipMarkup")] [JsonProperty("shouldSkipMarkup")] @@ -32,5 +32,5 @@ public class PageViewModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.DataContracts.UniversalReference/SyntaxDetailViewModel.cs b/src/Docfx.DataContracts.UniversalReference/SyntaxDetailViewModel.cs index 34c11f2770b..6ddde79102f 100644 --- a/src/Docfx.DataContracts.UniversalReference/SyntaxDetailViewModel.cs +++ b/src/Docfx.DataContracts.UniversalReference/SyntaxDetailViewModel.cs @@ -47,13 +47,13 @@ public class SyntaxDetailViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Return)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList ReturnInDevLangs { get; set; } = new(); + public SortedList ReturnInDevLangs { get; set; } = []; [ExtensibleMember] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] [System.Text.Json.Serialization.JsonPropertyName("__metadata__")] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; [EditorBrowsable(EditorBrowsableState.Never)] [YamlIgnore] diff --git a/src/Docfx.Dotnet/Docfx.Dotnet.csproj b/src/Docfx.Dotnet/Docfx.Dotnet.csproj index 9dbc6ec171a..d28ca0fb4ae 100644 --- a/src/Docfx.Dotnet/Docfx.Dotnet.csproj +++ b/src/Docfx.Dotnet/Docfx.Dotnet.csproj @@ -16,10 +16,6 @@ - - - - @@ -32,7 +28,6 @@ - diff --git a/src/Docfx.Dotnet/DotnetApiCatalog.ApiPage.cs b/src/Docfx.Dotnet/DotnetApiCatalog.ApiPage.cs index 7540da20dc2..bf5e65f2c45 100644 --- a/src/Docfx.Dotnet/DotnetApiCatalog.ApiPage.cs +++ b/src/Docfx.Dotnet/DotnetApiCatalog.ApiPage.cs @@ -10,7 +10,6 @@ using Docfx.Plugins; using HtmlAgilityPack; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Shared.Extensions; using OneOf; #nullable enable @@ -86,7 +85,7 @@ _ when SymbolHelper.IsConstructor(method) => "Constructor", _ when SymbolHelper.IsOperator(method) => "Operator", _ when SymbolHelper.IsMember(method) => "Method", _ => throw new NotSupportedException($"Unknown method type {method.MethodKind}"), - }); ; + }); foreach (var (s, c) in symbols) Method((IMethodSymbol)s, c, 2); break; @@ -731,7 +730,7 @@ Span Link(string text, string? url) return string.IsNullOrEmpty(url) ? text : new LinkSpan { text = text, url = url }; } - XmlComment? Comment(ISymbol symbol, Compilation compilation) + XmlComment Comment(ISymbol symbol, Compilation compilation) { // Cache XML comment to avoid duplicated parsing and warnings return commentCache.GetOrAdd(symbol, symbol => diff --git a/src/Docfx.Dotnet/DotnetApiCatalog.Compile.cs b/src/Docfx.Dotnet/DotnetApiCatalog.Compile.cs index 480849fcfcb..e94c3a1a01a 100644 --- a/src/Docfx.Dotnet/DotnetApiCatalog.Compile.cs +++ b/src/Docfx.Dotnet/DotnetApiCatalog.Compile.cs @@ -20,9 +20,9 @@ partial class DotnetApiCatalog { var files = config.Files?.Select(s => new FileInformation(s)) .GroupBy(f => f.Type) - .ToDictionary(s => s.Key, s => s.Distinct().ToList()) ?? new(); + .ToDictionary(s => s.Key, s => s.Distinct().ToList()) ?? []; - var msbuildProperties = config.MSBuildProperties ?? new Dictionary(); + var msbuildProperties = config.MSBuildProperties ?? []; msbuildProperties.TryAdd("Configuration", "Release"); // NOTE: @@ -122,7 +122,7 @@ await LoadCompilationFromProject(project.AbsolutePath) is { } compilation) if (hasCompilationError) { - return new(); + return []; } if (assemblies.Count <= 0) diff --git a/src/Docfx.Dotnet/DotnetApiCatalog.ManagedReference.cs b/src/Docfx.Dotnet/DotnetApiCatalog.ManagedReference.cs index 3612add070e..001182f02b3 100644 --- a/src/Docfx.Dotnet/DotnetApiCatalog.ManagedReference.cs +++ b/src/Docfx.Dotnet/DotnetApiCatalog.ManagedReference.cs @@ -66,7 +66,7 @@ void ResolveAndExportYamlMetadata( YamlUtility.Serialize(tocFilePath, tocViewModel, YamlMime.TableOfContent); outputFileNames.Add(tocFilePath, 1); - ApiReferenceViewModel indexer = new(); + ApiReferenceViewModel indexer = []; // generate each item's yaml var members = model.Members; @@ -142,7 +142,7 @@ bool MergeNode(MetadataItem node) { if (node.Type is MemberType.Assembly) { - foreach (var item in node.Items ?? new()) + foreach (var item in node.Items ?? []) { MergeNode(item); } @@ -152,7 +152,7 @@ bool MergeNode(MetadataItem node) if (!result.TryGetValue(node.Name, out var existingNode)) { result.Add(node.Name, node); - foreach (var item in node.Items ?? new()) + foreach (var item in node.Items ?? []) { MergeNode(item); } @@ -161,11 +161,11 @@ bool MergeNode(MetadataItem node) if (node.Type is MemberType.Namespace or MemberType.Class) { - foreach (var item in node.Items ?? new()) + foreach (var item in node.Items ?? []) { if (MergeNode(item)) { - existingNode.Items ??= new(); + existingNode.Items ??= []; existingNode.Items.Add(item); } } diff --git a/src/Docfx.Dotnet/DotnetApiCatalog.Toc.cs b/src/Docfx.Dotnet/DotnetApiCatalog.Toc.cs index 788da38ef94..d148421e458 100644 --- a/src/Docfx.Dotnet/DotnetApiCatalog.Toc.cs +++ b/src/Docfx.Dotnet/DotnetApiCatalog.Toc.cs @@ -37,7 +37,7 @@ class TocNode internal TocNodeType type; internal string? id; internal bool containsLeafNodes; - internal List<(ISymbol symbol, Compilation compilation)> symbols = new(); + internal List<(ISymbol symbol, Compilation compilation)> symbols = []; } private static List CreateToc(List<(IAssemblySymbol symbol, Compilation compilation)> assemblies, ExtractMetadataConfig config, DotnetApiOptions options) @@ -61,7 +61,7 @@ IEnumerable CreateToc(ISymbol symbol, Compilation compilation) switch (symbol) { - case INamespaceSymbol {IsGlobalNamespace: true} ns: + case INamespaceSymbol { IsGlobalNamespace: true } ns: foreach (var child in ns.GetNamespaceMembers()) foreach (var item in CreateToc(child, compilation)) yield return item; @@ -104,7 +104,7 @@ IEnumerable CreateNamespaceToc(INamespaceSymbol ns) var existingNodeHasNoLeafNode = idExists && !node.containsLeafNodes; - node.items ??= new(); + node.items ??= []; node.symbols.Add((symbol, compilation)); foreach (var child in ns.GetNamespaceMembers()) @@ -164,7 +164,7 @@ IEnumerable CreateNamedTypeToc(INamedTypeSymbol type) if (config.MemberLayout is MemberLayout.SeparatePages && type.TypeKind is TypeKind.Class or TypeKind.Interface or TypeKind.Struct) { - node.items ??= new(); + node.items ??= []; foreach (var member in type.GetMembers()) node.items.AddRange(CreateToc(member, compilation)); } @@ -248,7 +248,7 @@ void InsertCategory(TocNodeType type, string name) case CategoryLayout.Nested: { // Skip when parent node is category node. - if (parentTocNode is {type: TocNodeType.None}) + if (parentTocNode is { type: TocNodeType.None }) return; // If items contains specified type node. Create new TocNode for category. and move related node to child node. diff --git a/src/Docfx.Dotnet/ExtensionMethods/ISymbolExtensions.cs b/src/Docfx.Dotnet/ExtensionMethods/ISymbolExtensions.cs new file mode 100644 index 00000000000..5a91077fa80 --- /dev/null +++ b/src/Docfx.Dotnet/ExtensionMethods/ISymbolExtensions.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; +using System.Globalization; +using System.Reflection; +using System.Reflection.Emit; +using Microsoft.CodeAnalysis; + +#nullable enable + +namespace Docfx.Dotnet; + +internal static class ISymbolExtensions +{ + public static ImmutableArray GetParameters(this ISymbol? symbol) + { + return symbol switch + { + IMethodSymbol m => m.Parameters, + IPropertySymbol nt => nt.Parameters, + _ => [], + }; + } + + public static ImmutableArray GetTypeParameters(this ISymbol? symbol) + { + return symbol switch + { + IMethodSymbol m => m.TypeParameters, + INamedTypeSymbol nt => nt.TypeParameters, + _ => [], + }; + } + + public static DocumentationComment GetDocumentationComment(this ISymbol symbol, Compilation compilation, CultureInfo? preferredCulture = null, bool expandIncludes = false, bool expandInheritdoc = false, CancellationToken cancellationToken = default) + { + // Gets FullXmlFragment by calling `symbol.DocumentationComment(...).FullXmlFragment` + string fullXmlFragment = Helpers.GetFullXmlFragment(symbol, compilation, preferredCulture, expandIncludes, expandInheritdoc, cancellationToken); + + return new DocumentationComment + { + FullXmlFragment = fullXmlFragment, + }; + } + + internal class DocumentationComment + { + public required string FullXmlFragment { get; init; } + } + + private static class Helpers + { + /// + /// Gets result of `symbol.GetDocumentationComment(args).FullXmlFragment` + /// + public static string GetFullXmlFragment(ISymbol symbol, Compilation compilation, CultureInfo? preferredCulture = null, bool expandIncludes = false, bool expandInheritdoc = false, CancellationToken cancellationToken = default) + => CachedDelegate(symbol, compilation, preferredCulture, expandIncludes, expandInheritdoc, cancellationToken); + + static Helpers() + { + CachedDelegate = GetDelegate(); + } + + private delegate string GetFullXmlFragmentDelegate(ISymbol symbol, Compilation compilation, CultureInfo? preferredCulture, bool expandIncludes, bool expandInheritdoc, CancellationToken cancellationToken); + private static readonly GetFullXmlFragmentDelegate CachedDelegate; + + private static GetFullXmlFragmentDelegate GetDelegate() + { + // Gets Microsoft.CodeAnalysis.Workspaces assembly + var workspaceAssembly = typeof(Workspace).Assembly; + + // Gets MethodInfo for GetDocumentationComment + var type = workspaceAssembly.GetType("Microsoft.CodeAnalysis.Shared.Extensions.ISymbolExtensions", throwOnError: true)!; + var methodInfo = type.GetMethod("GetDocumentationComment", BindingFlags.Public | BindingFlags.Static); + + // Gets PropertyInfo for DocumentationComment. + var docCommentType = workspaceAssembly.GetType("Microsoft.CodeAnalysis.Shared.Utilities.DocumentationComment", throwOnError: true)!; + var propertyInfo = docCommentType.GetProperty("FullXmlFragment", BindingFlags.Instance | BindingFlags.Public)!; + + // Reflection may fail when updating the Microsoft.CodeAnalysis.Workspaces.Common package.. + if (methodInfo == null || propertyInfo == null) + throw new InvalidOperationException("Failed to get required MethodInfo/PropertyInfo via reflection."); + + var dm = new DynamicMethod(string.Empty, returnType: typeof(string), parameterTypes: [ + typeof(ISymbol), + typeof(Compilation), + typeof(CultureInfo), // preferredCulture + typeof(bool), // expandIncludes + typeof(bool), // expandInheritdoc + typeof(CancellationToken), + ]); + + ILGenerator il = dm.GetILGenerator(); + + // call Microsoft.CodeAnalysis.Shared.Extensions.ISymbolExtensions::GetDocumentationComment(args) + il.Emit(OpCodes.Ldarg_0); // symbol + il.Emit(OpCodes.Ldarg_1); // compilation + il.Emit(OpCodes.Ldarg_2); // preferredCulture + il.Emit(OpCodes.Ldarg_3); // expandIncludes + il.Emit(OpCodes.Ldarg_S, 4); // expandInheritdoc + il.Emit(OpCodes.Ldarg_S, 5); // cancellationToken + il.EmitCall(OpCodes.Call, methodInfo, null); + + // callvirt DocumentationComment::get_FullXmlFragment() + il.EmitCall(OpCodes.Callvirt, propertyInfo.GetMethod!, null); + + // return FullXmlFragment + il.Emit(OpCodes.Ret); + + return dm.CreateDelegate(); + } + } +} diff --git a/src/Docfx.Dotnet/Filters/AttributeFilterInfo.cs b/src/Docfx.Dotnet/Filters/AttributeFilterInfo.cs index 63b3ddb6737..20aef537058 100644 --- a/src/Docfx.Dotnet/Filters/AttributeFilterInfo.cs +++ b/src/Docfx.Dotnet/Filters/AttributeFilterInfo.cs @@ -14,7 +14,7 @@ internal class AttributeFilterInfo public List ConstructorArguments { get; set; } [YamlMember(Alias = "ctorNamedArguments")] - public Dictionary ConstructorNamedArguments { get; set; } = new(); + public Dictionary ConstructorNamedArguments { get; set; } = []; public bool ContainedIn(SymbolFilterData symbol) { diff --git a/src/Docfx.Dotnet/Filters/ConfigFilterRule.cs b/src/Docfx.Dotnet/Filters/ConfigFilterRule.cs index e07f033e7ef..0e12bc07c39 100644 --- a/src/Docfx.Dotnet/Filters/ConfigFilterRule.cs +++ b/src/Docfx.Dotnet/Filters/ConfigFilterRule.cs @@ -10,10 +10,10 @@ namespace Docfx.Dotnet; internal class ConfigFilterRule { [YamlMember(Alias = "apiRules")] - public List ApiRules { get; set; } = new(); + public List ApiRules { get; set; } = []; [YamlMember(Alias = "attributeRules")] - public List AttributeRules { get; set; } = new(); + public List AttributeRules { get; set; } = []; public bool CanVisitApi(SymbolFilterData symbol) { diff --git a/src/Docfx.Dotnet/Filters/ConfigFilterRuleItemUnion.cs b/src/Docfx.Dotnet/Filters/ConfigFilterRuleItemUnion.cs index acb2cc10a92..27b4df73f1b 100644 --- a/src/Docfx.Dotnet/Filters/ConfigFilterRuleItemUnion.cs +++ b/src/Docfx.Dotnet/Filters/ConfigFilterRuleItemUnion.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Text.Json.Serialization; using YamlDotNet.Serialization; namespace Docfx.Dotnet; diff --git a/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs b/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs index 406d47e1aaa..5ac4b6b9b68 100644 --- a/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs +++ b/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs @@ -72,7 +72,7 @@ public class ItemViewModel : IOverwriteDocumentViewModel, IItemWithMetadata [ExtensibleMember(Constants.ExtensionMemberPrefix.Name)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList Names { get; set; } = new(); + public SortedList Names { get; set; } = []; [YamlIgnore] [Newtonsoft.Json.JsonIgnore] @@ -128,7 +128,7 @@ public string NameForVB [ExtensibleMember(Constants.ExtensionMemberPrefix.NameWithType)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList NamesWithType { get; set; } = new(); + public SortedList NamesWithType { get; set; } = []; [YamlIgnore] [Newtonsoft.Json.JsonIgnore] @@ -184,7 +184,7 @@ public string NameWithTypeForVB [ExtensibleMember(Constants.ExtensionMemberPrefix.FullName)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList FullNames { get; set; } = new(); + public SortedList FullNames { get; set; } = []; [YamlIgnore] [Newtonsoft.Json.JsonIgnore] @@ -373,7 +373,7 @@ public string FullNameForVB [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] [System.Text.Json.Serialization.JsonPropertyName("__metadata__")] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; [EditorBrowsable(EditorBrowsableState.Never)] [YamlIgnore] diff --git a/src/Docfx.Dotnet/ManagedReference/Models/PageViewModel.cs b/src/Docfx.Dotnet/ManagedReference/Models/PageViewModel.cs index dfe564a80da..a872eacb0de 100644 --- a/src/Docfx.Dotnet/ManagedReference/Models/PageViewModel.cs +++ b/src/Docfx.Dotnet/ManagedReference/Models/PageViewModel.cs @@ -14,14 +14,14 @@ public class PageViewModel [YamlMember(Alias = "items")] [JsonProperty("items")] [JsonPropertyName("items")] - public List Items { get; set; } = new(); + public List Items { get; set; } = []; [YamlMember(Alias = "references")] [JsonProperty("references")] [JsonPropertyName("references")] [UniqueIdentityReferenceIgnore] [MarkdownContentIgnore] - public List References { get; set; } = new(); + public List References { get; set; } = []; [YamlMember(Alias = "shouldSkipMarkup")] [JsonProperty("shouldSkipMarkup")] @@ -36,5 +36,5 @@ public class PageViewModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs b/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs index 8aa49b39a22..57d78edeb93 100644 --- a/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs +++ b/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs @@ -22,7 +22,7 @@ public class SyntaxDetailViewModel [ExtensibleMember(Constants.ExtensionMemberPrefix.Content)] [Newtonsoft.Json.JsonIgnore] [System.Text.Json.Serialization.JsonIgnore] - public SortedList Contents { get; set; } = new(); + public SortedList Contents { get; set; } = []; [YamlIgnore] [Newtonsoft.Json.JsonIgnore] diff --git a/src/Docfx.Dotnet/ManagedReference/Resolvers/NormalizeSyntax.cs b/src/Docfx.Dotnet/ManagedReference/Resolvers/NormalizeSyntax.cs index 61794226839..3c2a0f5948c 100644 --- a/src/Docfx.Dotnet/ManagedReference/Resolvers/NormalizeSyntax.cs +++ b/src/Docfx.Dotnet/ManagedReference/Resolvers/NormalizeSyntax.cs @@ -17,7 +17,7 @@ public void Run(MetadataModel yaml, ResolverContext context) (member, parent) => { // get all the possible places where link is possible - if (member.Syntax is {Content: not null}) + if (member.Syntax is { Content: not null }) { SyntaxLanguage[] keys = new SyntaxLanguage[member.Syntax.Content.Count]; member.Syntax.Content.Keys.CopyTo(keys, 0); diff --git a/src/Docfx.Dotnet/ManagedReference/Resolvers/ResolveReference.cs b/src/Docfx.Dotnet/ManagedReference/Resolvers/ResolveReference.cs index 1b59b26ee8c..f946b36b8df 100644 --- a/src/Docfx.Dotnet/ManagedReference/Resolvers/ResolveReference.cs +++ b/src/Docfx.Dotnet/ManagedReference/Resolvers/ResolveReference.cs @@ -20,14 +20,14 @@ public void Run(MetadataModel yaml, ResolverContext context) if (current.Type.IsPageLevel()) { page = current; - current.References = new Dictionary(); + current.References = []; } else { page = parent; current.References = null; } - if (documentReferences is {Count: > 0}) + if (documentReferences is { Count: > 0 }) { foreach (var key in documentReferences.Keys) { diff --git a/src/Docfx.Dotnet/ManagedReference/Resolvers/SetDerivedClass.cs b/src/Docfx.Dotnet/ManagedReference/Resolvers/SetDerivedClass.cs index c812f1a6e0d..cb23287b342 100644 --- a/src/Docfx.Dotnet/ManagedReference/Resolvers/SetDerivedClass.cs +++ b/src/Docfx.Dotnet/ManagedReference/Resolvers/SetDerivedClass.cs @@ -7,11 +7,11 @@ namespace Docfx.Dotnet; internal class SetDerivedClass : IResolverPipeline { - private readonly Dictionary> _derivedClassMapping = new(); + private readonly Dictionary> _derivedClassMapping = []; public void Run(MetadataModel yaml, ResolverContext context) { - if (yaml.Members is {Count: > 0}) + if (yaml.Members is { Count: > 0 }) { UpdateDerivedClassMapping(yaml.Members, context.References); AppendDerivedClass(yaml.Members); @@ -23,7 +23,7 @@ private void UpdateDerivedClassMapping(List items, Dictionary()) { var inheritance = item.Inheritance; - if (inheritance is {Count: > 0}) + if (inheritance is { Count: > 0 }) { var superClass = inheritance[inheritance.Count - 1]; @@ -41,7 +41,7 @@ private void UpdateDerivedClassMapping(List items, Dictionary { item.Name }); + _derivedClassMapping.Add(superClass, [item.Name]); } } } diff --git a/src/Docfx.Dotnet/ManagedReference/Resolvers/YamlMetadataResolver.cs b/src/Docfx.Dotnet/ManagedReference/Resolvers/YamlMetadataResolver.cs index f8001c4132c..57eda24d1df 100644 --- a/src/Docfx.Dotnet/ManagedReference/Resolvers/YamlMetadataResolver.cs +++ b/src/Docfx.Dotnet/ManagedReference/Resolvers/YamlMetadataResolver.cs @@ -8,8 +8,8 @@ namespace Docfx.Dotnet; internal static class YamlMetadataResolver { // Order matters - private static readonly List pipelines = new() - { + private static readonly List pipelines = + [ new LayoutCheckAndCleanup(), new SetParent(), new ResolveReference(), @@ -17,7 +17,7 @@ internal static class YamlMetadataResolver new BuildMembers(), new SetDerivedClass(), new BuildToc() - }; + ]; /// /// TODO: input Namespace list instead; @@ -33,7 +33,7 @@ public static MetadataModel ResolveMetadata( MetadataModel viewModel = new() { TocYamlViewModel = GenerateToc(allMembers, allReferences, namespaceLayout), - Members = new List(), + Members = [], }; ResolverContext context = new() { @@ -74,9 +74,9 @@ private static MetadataItem GenerateNestedTocStructure(IEnumerable namespacedItems = new(); + Dictionary namespacedItems = []; var dotsPerNamespace = namespaces.ToDictionary(x => x.Key, x => x.Value.Name.Where(y => y == '.').Count()); foreach (var member in namespaces @@ -95,10 +95,10 @@ private static MetadataItem GenerateNestedTocStructure(IEnumerable { @@ -57,7 +60,7 @@ private static string SpecTypeGenericParameter(IReadOnlyList names, stri { return id; } - return TypeParameterRegex.Replace( + return TypeParameterRegex().Replace( id, match => { @@ -72,7 +75,7 @@ private static string SpecMethodGenericParameter(IReadOnlyList names, st { return id; } - return MethodParameterRegex.Replace( + return MethodParameterRegex().Replace( id, match => { @@ -82,7 +85,7 @@ private static string SpecMethodGenericParameter(IReadOnlyList names, st } /// - /// spec extension method's receiver type. + /// spec extension method's receiver type. /// for below overload: M(this A), M(this A, A), AddReference applies to the first method and AddSpecReference applies to the second method might get same id without prepending receiver type. /// /// symbol diff --git a/src/Docfx.Dotnet/ManagedReference/Visitors/SymbolVisitorAdapter.cs b/src/Docfx.Dotnet/ManagedReference/Visitors/SymbolVisitorAdapter.cs index 0ede8bde10a..771bc40a11a 100644 --- a/src/Docfx.Dotnet/ManagedReference/Visitors/SymbolVisitorAdapter.cs +++ b/src/Docfx.Dotnet/ManagedReference/Visitors/SymbolVisitorAdapter.cs @@ -8,17 +8,18 @@ using Docfx.DataContracts.ManagedReference; using Docfx.Plugins; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Shared.Extensions; namespace Docfx.Dotnet; -internal class SymbolVisitorAdapter : SymbolVisitor +internal partial class SymbolVisitorAdapter : SymbolVisitor { - private static readonly Regex MemberSigRegex = new(@"^([\w\{\}`]+\.)+", RegexOptions.Compiled); + [GeneratedRegex(@"^([\w\{\}`]+\.)+")] + private static partial Regex MemberSigRegex(); + private static readonly IReadOnlyList EmptyListOfString = Array.Empty(); private readonly Compilation _compilation; private readonly YamlModelGenerator _generator; - private readonly Dictionary _references = new(); + private readonly Dictionary _references = []; private readonly IMethodSymbol[] _extensionMethods; private readonly ExtractMetadataConfig _config; private readonly SymbolFilter _filter; @@ -29,7 +30,7 @@ public SymbolVisitorAdapter(Compilation compilation, YamlModelGenerator generato _generator = generator; _filter = filter; _config = config; - _extensionMethods = extensionMethods?.Where(_filter.IncludeApi).ToArray() ?? Array.Empty(); + _extensionMethods = extensionMethods?.Where(_filter.IncludeApi).ToArray() ?? []; } public override MetadataItem DefaultVisit(ISymbol symbol) @@ -43,13 +44,13 @@ public override MetadataItem DefaultVisit(ISymbol symbol) { Name = VisitorHelper.GetId(symbol), CommentId = VisitorHelper.GetCommentId(symbol), - DisplayNames = new SortedList(), - DisplayNamesWithType = new SortedList(), - DisplayQualifiedNames = new SortedList(), + DisplayNames = [], + DisplayNamesWithType = [], + DisplayQualifiedNames = [], Source = _config.DisableGitFeatures ? null : VisitorHelper.GetSourceDetail(symbol, _compilation), }; var assemblyName = symbol.ContainingAssembly?.Name; - item.AssemblyNameList = string.IsNullOrEmpty(assemblyName) || assemblyName is "?" ? null : new List { assemblyName }; + item.AssemblyNameList = string.IsNullOrEmpty(assemblyName) || assemblyName is "?" ? null : [assemblyName]; if (symbol is not INamespaceSymbol) { var namespaceName = VisitorHelper.GetId(symbol.ContainingNamespace); @@ -153,10 +154,10 @@ public override MetadataItem VisitNamedType(INamedTypeSymbol symbol) } item.Type = VisitorHelper.GetMemberTypeFromTypeKind(symbol.TypeKind); - item.Syntax ??= new SyntaxDetail { Content = new SortedList() }; + item.Syntax ??= new SyntaxDetail { Content = [] }; if (item.Syntax.Content == null) { - item.Syntax.Content = new SortedList(); + item.Syntax.Content = []; } _generator.GenerateSyntax(symbol, item.Syntax, _filter); @@ -164,7 +165,7 @@ public override MetadataItem VisitNamedType(INamedTypeSymbol symbol) { if (item.Syntax.TypeParameters == null) { - item.Syntax.TypeParameters = new List(); + item.Syntax.TypeParameters = []; } foreach (var p in symbol.TypeParameters) @@ -180,7 +181,7 @@ public override MetadataItem VisitNamedType(INamedTypeSymbol symbol) AddMethodSyntax(symbol.DelegateInvokeMethod, item, typeGenericParameters, EmptyListOfString); } - item.Items = new List(); + item.Items = []; foreach ( var member in symbol.GetMembers() .Where(static s => @@ -210,13 +211,13 @@ public override MetadataItem VisitMethod(IMethodSymbol symbol) { return null; } - result.Syntax ??= new SyntaxDetail { Content = new SortedList() }; + result.Syntax ??= new SyntaxDetail { Content = [] }; if (symbol.TypeParameters.Length > 0) { if (result.Syntax.TypeParameters == null) { - result.Syntax.TypeParameters = new List(); + result.Syntax.TypeParameters = []; } foreach (var p in symbol.TypeParameters) @@ -234,11 +235,11 @@ public override MetadataItem VisitMethod(IMethodSymbol symbol) if (result.Syntax.Content == null) { - result.Syntax.Content = new SortedList(); + result.Syntax.Content = []; } _generator.GenerateSyntax(symbol, result.Syntax, _filter); - if (symbol is {IsOverride: true, OverriddenMethod: not null}) + if (symbol is { IsOverride: true, OverriddenMethod: not null }) { result.Overridden = AddSpecReference(symbol.OverriddenMethod, typeGenericParameters, methodGenericParameters); } @@ -262,10 +263,10 @@ public override MetadataItem VisitField(IFieldSymbol symbol) { return null; } - result.Syntax ??= new SyntaxDetail { Content = new SortedList() }; + result.Syntax ??= new SyntaxDetail { Content = [] }; if (result.Syntax.Content == null) { - result.Syntax.Content = new SortedList(); + result.Syntax.Content = []; } _generator.GenerateSyntax(symbol, result.Syntax, _filter); @@ -287,16 +288,16 @@ public override MetadataItem VisitEvent(IEventSymbol symbol) { return null; } - result.Syntax ??= new SyntaxDetail { Content = new SortedList() }; + result.Syntax ??= new SyntaxDetail { Content = [] }; if (result.Syntax.Content == null) { - result.Syntax.Content = new SortedList(); + result.Syntax.Content = []; } _generator.GenerateSyntax(symbol, result.Syntax, _filter); var typeGenericParameters = symbol.ContainingType.IsGenericType ? symbol.ContainingType.Accept(TypeGenericParameterNameVisitor.Instance) : EmptyListOfString; - if (symbol is {IsOverride: true, OverriddenEvent: not null}) + if (symbol is { IsOverride: true, OverriddenEvent: not null }) { result.Overridden = AddSpecReference(symbol.OverriddenEvent, typeGenericParameters); } @@ -321,14 +322,14 @@ public override MetadataItem VisitProperty(IPropertySymbol symbol) { return null; } - result.Syntax ??= new SyntaxDetail { Content = new SortedList() }; + result.Syntax ??= new SyntaxDetail { Content = [] }; if (result.Syntax.Parameters == null) { - result.Syntax.Parameters = new List(); + result.Syntax.Parameters = []; } if (result.Syntax.Content == null) { - result.Syntax.Content = new SortedList(); + result.Syntax.Content = []; } _generator.GenerateSyntax(symbol, result.Syntax, _filter); @@ -350,7 +351,7 @@ public override MetadataItem VisitProperty(IPropertySymbol symbol) Debug.Assert(result.Syntax.Return.Type != null); } - if (symbol is {IsOverride: true, OverriddenProperty: not null}) + if (symbol is { IsOverride: true, OverriddenProperty: not null }) { result.Overridden = AddSpecReference(symbol.OverriddenProperty, typeGenericParameters); } @@ -385,9 +386,9 @@ public string AddReference(string id, string commentId) var reference = new ReferenceItem { CommentId = commentId }; if (DocumentationCommentId.GetFirstSymbolForDeclarationId(commentId, _compilation) is { } symbol) { - reference.NameParts = new(); - reference.NameWithTypeParts = new(); - reference.QualifiedNameParts = new(); + reference.NameParts = []; + reference.NameWithTypeParts = []; + reference.QualifiedNameParts = []; reference.IsDefinition = symbol.IsDefinition; _generator.GenerateReference(symbol, reference, asOverload: false, _filter); @@ -547,7 +548,7 @@ private void GenerateInheritance(INamedTypeSymbol symbol, MetadataItem item) { var type = symbol; var inheritance = new List(); - dict = new Dictionary(); + dict = []; var typeParameterNames = symbol.IsGenericType ? symbol.Accept(TypeGenericParameterNameVisitor.Instance) : EmptyListOfString; while (type != null) { @@ -585,7 +586,7 @@ where _filter.IncludeApi(t) } else if (symbol.TypeKind == TypeKind.Interface) { - dict = new Dictionary(); + dict = []; var typeParameterNames = symbol.IsGenericType ? symbol.Accept(TypeGenericParameterNameVisitor.Instance) : EmptyListOfString; AddInheritedMembers(symbol, symbol, dict, typeParameterNames); for (int i = 0; i < symbol.AllInterfaces.Length; i++) @@ -669,7 +670,7 @@ where _filter.IncludeApi(m) where IsInheritable(m) select m) { - var sig = MemberSigRegex.Replace(SpecIdHelper.GetSpecId(m, typeParameterNames), string.Empty); + var sig = MemberSigRegex().Replace(SpecIdHelper.GetSpecId(m, typeParameterNames), string.Empty); if (!dict.ContainsKey(sig)) { dict.Add(sig, type.Equals(symbol, SymbolEqualityComparer.Default) ? null : AddSpecReference(m, typeParameterNames)); @@ -690,7 +691,7 @@ private void AddMethodSyntax(IMethodSymbol symbol, MetadataItem result, IReadOnl { if (result.Syntax.Parameters == null) { - result.Syntax.Parameters = new List(); + result.Syntax.Parameters = []; } foreach (var p in symbol.Parameters) @@ -717,7 +718,7 @@ private XmlCommentParserContext GetXmlCommentParserContext(MetadataItem item) void AddReferenceDelegate(string id, string commentId) { var r = AddReference(id, commentId); - item.References ??= new Dictionary(); + item.References ??= []; // only record the id now, the value would be fed at later phase after merge item.References[id] = null; diff --git a/src/Docfx.Dotnet/ManagedReference/Visitors/TypeGenericParameterNameVisitor.cs b/src/Docfx.Dotnet/ManagedReference/Visitors/TypeGenericParameterNameVisitor.cs index fabeabcf217..e3e4f436222 100644 --- a/src/Docfx.Dotnet/ManagedReference/Visitors/TypeGenericParameterNameVisitor.cs +++ b/src/Docfx.Dotnet/ManagedReference/Visitors/TypeGenericParameterNameVisitor.cs @@ -27,7 +27,7 @@ public override List VisitNamedType(INamedTypeSymbol symbol) } if (symbol.TypeParameters.Length > 0) { - result ??= new List(); + result ??= []; for (int i = 0; i < symbol.TypeParameters.Length; i++) { result.Add(symbol.TypeParameters[i].Name); diff --git a/src/Docfx.Dotnet/ManagedReference/Visitors/VisitorHelper.cs b/src/Docfx.Dotnet/ManagedReference/Visitors/VisitorHelper.cs index 0db6a1a587f..04cc202c6d7 100644 --- a/src/Docfx.Dotnet/ManagedReference/Visitors/VisitorHelper.cs +++ b/src/Docfx.Dotnet/ManagedReference/Visitors/VisitorHelper.cs @@ -12,10 +12,12 @@ namespace Docfx.Dotnet; -internal static class VisitorHelper +internal static partial class VisitorHelper { public static string GlobalNamespaceId { get; set; } - private static readonly Regex GenericMethodPostFix = new(@"``\d+$", RegexOptions.Compiled); + + [GeneratedRegex(@"``\d+$")] + private static partial Regex GenericMethodPostFix(); public static string PathFriendlyId(string id) { @@ -29,7 +31,7 @@ public static string GetId(ISymbol symbol) return null; } - if (symbol is INamespaceSymbol {IsGlobalNamespace: true}) + if (symbol is INamespaceSymbol { IsGlobalNamespace: true }) { return GlobalNamespaceId; } @@ -109,7 +111,7 @@ public static string GetOverloadIdBody(ISymbol symbol) uidBody = uidBody.Remove(index); } } - uidBody = GenericMethodPostFix.Replace(uidBody, string.Empty); + uidBody = GenericMethodPostFix().Replace(uidBody, string.Empty); return uidBody; } diff --git a/src/Docfx.Dotnet/ManagedReference/Visitors/YamlModelGenerator.cs b/src/Docfx.Dotnet/ManagedReference/Visitors/YamlModelGenerator.cs index 79d205e1f36..889f9a36f96 100644 --- a/src/Docfx.Dotnet/ManagedReference/Visitors/YamlModelGenerator.cs +++ b/src/Docfx.Dotnet/ManagedReference/Visitors/YamlModelGenerator.cs @@ -33,22 +33,22 @@ public void DefaultVisit(ISymbol symbol, MetadataItem item) public void GenerateReference(ISymbol symbol, ReferenceItem reference, bool asOverload, SymbolFilter filter) { if (!reference.NameParts.ContainsKey(SyntaxLanguage.CSharp)) - reference.NameParts.Add(SyntaxLanguage.CSharp, new()); + reference.NameParts.Add(SyntaxLanguage.CSharp, []); if (!reference.NameWithTypeParts.ContainsKey(SyntaxLanguage.CSharp)) - reference.NameWithTypeParts.Add(SyntaxLanguage.CSharp, new()); + reference.NameWithTypeParts.Add(SyntaxLanguage.CSharp, []); if (!reference.QualifiedNameParts.ContainsKey(SyntaxLanguage.CSharp)) - reference.QualifiedNameParts.Add(SyntaxLanguage.CSharp, new()); + reference.QualifiedNameParts.Add(SyntaxLanguage.CSharp, []); reference.NameParts[SyntaxLanguage.CSharp] = SymbolFormatter.GetNameParts(symbol, SyntaxLanguage.CSharp, nullableReferenceType: false, asOverload).ToLinkItems(_compilation, _memberLayout, _allAssemblies, asOverload, filter); reference.NameWithTypeParts[SyntaxLanguage.CSharp] = SymbolFormatter.GetNameWithTypeParts(symbol, SyntaxLanguage.CSharp, nullableReferenceType: false, asOverload).ToLinkItems(_compilation, _memberLayout, _allAssemblies, asOverload, filter); reference.QualifiedNameParts[SyntaxLanguage.CSharp] = SymbolFormatter.GetQualifiedNameParts(symbol, SyntaxLanguage.CSharp, nullableReferenceType: false, asOverload).ToLinkItems(_compilation, _memberLayout, _allAssemblies, asOverload, filter); if (!reference.NameParts.ContainsKey(SyntaxLanguage.VB)) - reference.NameParts.Add(SyntaxLanguage.VB, new()); + reference.NameParts.Add(SyntaxLanguage.VB, []); if (!reference.NameWithTypeParts.ContainsKey(SyntaxLanguage.VB)) - reference.NameWithTypeParts.Add(SyntaxLanguage.VB, new()); + reference.NameWithTypeParts.Add(SyntaxLanguage.VB, []); if (!reference.QualifiedNameParts.ContainsKey(SyntaxLanguage.VB)) - reference.QualifiedNameParts.Add(SyntaxLanguage.VB, new()); + reference.QualifiedNameParts.Add(SyntaxLanguage.VB, []); reference.NameParts[SyntaxLanguage.VB] = SymbolFormatter.GetNameParts(symbol, SyntaxLanguage.VB, nullableReferenceType: false, asOverload).ToLinkItems(_compilation, _memberLayout, _allAssemblies, asOverload, filter); reference.NameWithTypeParts[SyntaxLanguage.VB] = SymbolFormatter.GetNameWithTypeParts(symbol, SyntaxLanguage.VB, nullableReferenceType: false, asOverload).ToLinkItems(_compilation, _memberLayout, _allAssemblies, asOverload, filter); @@ -66,9 +66,9 @@ public string AddReference(ISymbol symbol, Dictionary ref var id = VisitorHelper.GetId(symbol); var reference = new ReferenceItem { - NameParts = new(), - NameWithTypeParts = new(), - QualifiedNameParts = new(), + NameParts = [], + NameWithTypeParts = [], + QualifiedNameParts = [], IsDefinition = symbol.IsDefinition, CommentId = VisitorHelper.GetCommentId(symbol) }; @@ -87,9 +87,9 @@ public string AddOverloadReference(ISymbol symbol, Dictionary { "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr" }; + _voidElements = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"]; } public override void WriteEndElement() diff --git a/src/Docfx.Dotnet/Parsers/XmlComment.cs b/src/Docfx.Dotnet/Parsers/XmlComment.cs index 20afb45bf3a..5cf6105c619 100644 --- a/src/Docfx.Dotnet/Parsers/XmlComment.cs +++ b/src/Docfx.Dotnet/Parsers/XmlComment.cs @@ -19,14 +19,24 @@ namespace Docfx.Dotnet; -internal class XmlComment +internal partial class XmlComment { private const string IdSelector = @"((?![0-9])[\w_])+[\w\(\)\.\{\}\[\]\|\*\^~#@!`,_<>:]*"; - private static readonly Regex CommentIdRegex = new("^(?N|T|M|P|F|E|Overload):(?" + IdSelector + ")$", RegexOptions.Compiled); - private static readonly Regex RegionRegex = new(@"^\s*#region\s*(.*)$"); - private static readonly Regex XmlRegionRegex = new(@"^\s*$"); - private static readonly Regex EndRegionRegex = new(@"^\s*#endregion\s*.*$"); - private static readonly Regex XmlEndRegionRegex = new(@"^\s*$"); + + [GeneratedRegex("^(?N|T|M|P|F|E|Overload):(?" + IdSelector + ")$")] + private static partial Regex CommentIdRegex(); + + [GeneratedRegex(@"^\s*#region\s*(.*)$")] + private static partial Regex RegionRegex(); + + [GeneratedRegex(@"^\s*$")] + private static partial Regex XmlRegionRegex(); + + [GeneratedRegex(@"^\s*#endregion\s*.*$")] + private static partial Regex EndRegionRegex(); + + [GeneratedRegex(@"^\s*$")] + private static partial Regex XmlEndRegionRegex(); private readonly XmlCommentParserContext _context; @@ -60,9 +70,8 @@ private XmlComment(string xml, XmlCommentParserContext context) else xml = $"{innerXml}"; } - // Workaround: https://github.com/dotnet/roslyn/pull/66668 - if (!xml.StartsWith("", StringComparison.Ordinal)) + else if (!xml.StartsWith("", StringComparison.Ordinal)) { xml = $"{xml}"; } @@ -282,10 +291,10 @@ private static (Regex, Regex) GetRegionRegex(string source) case ".HTML": case ".CSHTML": case ".VBHTML": - return (XmlRegionRegex, XmlEndRegionRegex); + return (XmlRegionRegex(), XmlEndRegionRegex()); } - return (RegionRegex, EndRegionRegex); + return (RegionRegex(), EndRegionRegex()); } private static void ResolveLangword(XNode node) @@ -323,7 +332,7 @@ private void ResolveCrefLink(XNode node, string nodeSelector, Action GetMultipleCrefInfo(XPathNavigator navigator, else if (!string.IsNullOrEmpty(commentId)) { // Check if exception type is valid and trim prefix - var match = CommentIdRegex.Match(commentId); + var match = CommentIdRegex().Match(commentId); if (match.Success) { var id = match.Groups["id"].Value; @@ -480,7 +489,7 @@ private static IEnumerable GetMultipleLinkInfo(XPathNavigator navigato else if (!string.IsNullOrEmpty(commentId)) { // Check if cref type is valid and trim prefix - var match = CommentIdRegex.Match(commentId); + var match = CommentIdRegex().Match(commentId); if (match.Success) { var id = match.Groups["id"].Value; @@ -631,7 +640,7 @@ static void MarkdownXmlDecode(MarkdownObject node) MarkdownXmlDecode(child); break; - case LeafBlock {Inline: not null} leafBlock: + case LeafBlock { Inline: not null } leafBlock: foreach (var child in leafBlock.Inline) MarkdownXmlDecode(child); break; diff --git a/src/Docfx.Dotnet/SourceLink/SourceLinkMap.cs b/src/Docfx.Dotnet/SourceLink/SourceLinkMap.cs index a65b97499bf..4c315a87cbb 100644 --- a/src/Docfx.Dotnet/SourceLink/SourceLinkMap.cs +++ b/src/Docfx.Dotnet/SourceLink/SourceLinkMap.cs @@ -3,8 +3,8 @@ using System.Collections.ObjectModel; using System.Diagnostics; -using System.Text.Json; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; #nullable enable diff --git a/src/Docfx.Dotnet/SymbolFilter.cs b/src/Docfx.Dotnet/SymbolFilter.cs index 47685377b9d..6813e5c4016 100644 --- a/src/Docfx.Dotnet/SymbolFilter.cs +++ b/src/Docfx.Dotnet/SymbolFilter.cs @@ -95,7 +95,7 @@ bool IncludeAttributeDefault(ISymbol symbol) private bool IsSymbolAccessible(ISymbol symbol) { // TODO: should we include implicitly declared members like constructors? They are part of the API contract. - if (symbol is {IsImplicitlyDeclared: true, Kind: not SymbolKind.Namespace}) + if (symbol is { IsImplicitlyDeclared: true, Kind: not SymbolKind.Namespace }) return false; if (_config.IncludeExplicitInterfaceImplementations && diff --git a/src/Docfx.Dotnet/SymbolFormatter.Symbols.cs b/src/Docfx.Dotnet/SymbolFormatter.Symbols.cs index 4ed64f8862b..97e3af902bc 100644 --- a/src/Docfx.Dotnet/SymbolFormatter.Symbols.cs +++ b/src/Docfx.Dotnet/SymbolFormatter.Symbols.cs @@ -98,7 +98,7 @@ private class ParameterSymbol : IParameterSymbol public void Accept(SymbolVisitor visitor) => visitor.VisitParameter(this); #nullable enable - public TResult? Accept(SymbolVisitor visitor) => throw new NotImplementedException(); + public TResult Accept(SymbolVisitor visitor) => throw new NotImplementedException(); #nullable disable public TResult Accept(SymbolVisitor visitor, TArgument argument) => throw new NotImplementedException(); public bool Equals([NotNullWhen(true)] ISymbol other, SymbolEqualityComparer equalityComparer) => throw new NotImplementedException(); diff --git a/src/Docfx.Dotnet/SymbolFormatter.Syntax.cs b/src/Docfx.Dotnet/SymbolFormatter.Syntax.cs index 9e8db3d1da9..0b4b384fe4b 100644 --- a/src/Docfx.Dotnet/SymbolFormatter.Syntax.cs +++ b/src/Docfx.Dotnet/SymbolFormatter.Syntax.cs @@ -368,7 +368,7 @@ private void AddTypedConstant(TypedConstant typedConstant) AddPunctuation(")"); break; - case TypedConstantKind.Array when typedConstant is {IsNull: false, Type: not null}: + case TypedConstantKind.Array when typedConstant is { IsNull: false, Type: not null }: AddKeyword("new", "New"); AddSpace(); AddTypeName(typedConstant.Type); @@ -460,7 +460,7 @@ private void AddEnumConstant(TypedConstant typedConstant) private bool ExpandEnumClassName(ISymbol symbol, SymbolDisplayPart part) { - if (symbol.Kind != SymbolKind.Field && part is {Kind: SymbolDisplayPartKind.EnumMemberName, Symbol: not null}) + if (symbol.Kind != SymbolKind.Field && part is { Kind: SymbolDisplayPartKind.EnumMemberName, Symbol: not null }) { _parts.Add(new(SymbolDisplayPartKind.EnumName, part.Symbol.ContainingSymbol, part.Symbol.ContainingSymbol.Name)); _parts.Add(new(SymbolDisplayPartKind.Punctuation, null, ".")); @@ -472,7 +472,7 @@ private bool ExpandEnumClassName(ISymbol symbol, SymbolDisplayPart part) private bool StaticClassToVBModule(ISymbol symbol, SymbolDisplayPart part) { - if (Language is SyntaxLanguage.VB && symbol is {IsStatic: true, Kind: SymbolKind.NamedType} && + if (Language is SyntaxLanguage.VB && symbol is { IsStatic: true, Kind: SymbolKind.NamedType } && part.Kind == SymbolDisplayPartKind.Keyword && part.ToString() == "Class") { _parts.Add(new(SymbolDisplayPartKind.Keyword, null, "Module")); diff --git a/src/Docfx.Dotnet/SymbolFormatter.cs b/src/Docfx.Dotnet/SymbolFormatter.cs index 0e6bf1b496d..ee76da87457 100644 --- a/src/Docfx.Dotnet/SymbolFormatter.cs +++ b/src/Docfx.Dotnet/SymbolFormatter.cs @@ -131,7 +131,7 @@ LinkItem ToLinkItem(SymbolDisplayPart part) if (symbol is null || part.Kind is SymbolDisplayPartKind.TypeParameterName) return new() { DisplayName = part.ToString() }; - if (symbol is INamedTypeSymbol {IsGenericType: true} type) + if (symbol is INamedTypeSymbol { IsGenericType: true } type) symbol = type.ConstructedFrom; return new() diff --git a/src/Docfx.Dotnet/SymbolHelper.cs b/src/Docfx.Dotnet/SymbolHelper.cs index d49889a6a32..7d2113c6151 100644 --- a/src/Docfx.Dotnet/SymbolHelper.cs +++ b/src/Docfx.Dotnet/SymbolHelper.cs @@ -33,7 +33,7 @@ public static bool IsMember(this ISymbol symbol) public static bool IsClass(this ISymbol symbol) { - return symbol.Kind is SymbolKind.NamedType && symbol is INamedTypeSymbol {TypeKind: TypeKind.Class}; + return symbol.Kind is SymbolKind.NamedType && symbol is INamedTypeSymbol { TypeKind: TypeKind.Class }; } public static bool IsEnumMember(this ISymbol symbol) diff --git a/src/Docfx.Dotnet/SymbolUrlResolver.SourceLink.cs b/src/Docfx.Dotnet/SymbolUrlResolver.SourceLink.cs index adc14d64930..ed54a5c4e88 100644 --- a/src/Docfx.Dotnet/SymbolUrlResolver.SourceLink.cs +++ b/src/Docfx.Dotnet/SymbolUrlResolver.SourceLink.cs @@ -18,7 +18,7 @@ namespace Docfx.Dotnet; partial class SymbolUrlResolver { - private static readonly ConditionalWeakTable s_sourceLinkProviders = new(); + private static readonly ConditionalWeakTable s_sourceLinkProviders = []; public static string? GetPdbSourceLinkUrl(Compilation compilation, ISymbol symbol) { @@ -89,8 +89,15 @@ public SourceLinkProvider(PEReader peReader, MetadataReaderProvider pdbReaderPro private string? TryGetSourceLinkUrl(DocumentHandle handle) { var document = _pdbReader.GetDocument(handle); - if (document.Name.IsNil) + try + { + if (document.Name.IsNil) + return null; + } + catch (BadImageFormatException) + { return null; + } var documentName = _pdbReader.GetString(document.Name); if (documentName is null) diff --git a/src/Docfx.Dotnet/YamlViewModelExtensions.cs b/src/Docfx.Dotnet/YamlViewModelExtensions.cs index e1690b0bce4..5c910db7eb9 100644 --- a/src/Docfx.Dotnet/YamlViewModelExtensions.cs +++ b/src/Docfx.Dotnet/YamlViewModelExtensions.cs @@ -42,7 +42,7 @@ public static MetadataItem ShrinkToSimpleToc(this MetadataItem item) { foreach (var i in item.Items) { - shrinkedItem.Items ??= new List(); + shrinkedItem.Items ??= []; if (i.IsInvalid) { @@ -77,7 +77,7 @@ public static MetadataItem ShrinkToSimpleTocWithNamespaceNotEmpty(this MetadataI { foreach (var i in item.Items) { - shrinkedItem.Items ??= new List(); + shrinkedItem.Items ??= []; if (i.IsInvalid) { @@ -180,7 +180,7 @@ private static ReferenceViewModel ToReferenceViewModel(KeyValuePair 0}) + if (model.Value.NameParts is { Count: > 0 }) { result.Name = GetName(model.Value.NameParts, SyntaxLanguage.Default); var nameForCSharp = GetName(model.Value.NameParts, SyntaxLanguage.CSharp); @@ -270,7 +270,7 @@ public static ItemViewModel ToItemViewModel(this MetadataItem model, ExtractMeta Attributes = model.Attributes, }; - if (model.Parent is {Name: not null} && !model.Name.StartsWith(model.Parent.Name)) + if (model.Parent is { Name: not null } && !model.Name.StartsWith(model.Parent.Name)) { result.Id = model.Name.Substring(model.Name.LastIndexOf('.') + 1); } @@ -330,7 +330,7 @@ public static SyntaxDetailViewModel ToSyntaxDetailViewModel(this SyntaxDetail mo TypeParameters = model.TypeParameters, Return = model.Return, }; - if (model.Content is {Count: > 0}) + if (model.Content is { Count: > 0 }) { result.Content = model.Content.GetLanguageProperty(SyntaxLanguage.Default); var contentForCSharp = model.Content.GetLanguageProperty(SyntaxLanguage.CSharp); @@ -379,7 +379,7 @@ public static TValue GetLanguageProperty(this SortedList 0}) + if (model.Items is { Count: > 0 }) { foreach (var item in model.Items) { diff --git a/src/Docfx.Glob/FileGlob.cs b/src/Docfx.Glob/FileGlob.cs index 2fd54a43982..3ce3e43cfd1 100644 --- a/src/Docfx.Glob/FileGlob.cs +++ b/src/Docfx.Glob/FileGlob.cs @@ -9,7 +9,7 @@ public static IEnumerable GetFiles(string cwd, IEnumerable patte { if (patterns == null) { - return Enumerable.Empty(); + return []; } if (string.IsNullOrEmpty(cwd)) @@ -18,7 +18,7 @@ public static IEnumerable GetFiles(string cwd, IEnumerable patte } var globArray = patterns.Select(s => new GlobMatcher(s, options)).ToArray(); var excludeGlobArray = excludePatterns == null ? - Array.Empty() : + [] : excludePatterns.Select(s => new GlobMatcher(s, options)).ToArray(); return GetFilesCore(cwd, globArray, excludeGlobArray); } diff --git a/src/Docfx.Glob/GlobMatcher.cs b/src/Docfx.Glob/GlobMatcher.cs index 9e83ac95a83..c1dc15a237a 100644 --- a/src/Docfx.Glob/GlobMatcher.cs +++ b/src/Docfx.Glob/GlobMatcher.cs @@ -8,21 +8,25 @@ namespace Docfx.Glob; -public class GlobMatcher : IEquatable +public partial class GlobMatcher : IEquatable { #region Private fields private static readonly StringComparer Comparer = FilePathComparer.OSPlatformSensitiveStringComparer; - private static readonly string[] EmptyString = Array.Empty(); + private static readonly string[] EmptyString = []; private const char NegateChar = '!'; private const string GlobStar = "**"; private const string ReplacerGroupName = "replacer"; private static readonly HashSet NeedEscapeCharactersInRegex = new(@"'().*{}+?[]^$\!".ToCharArray()); - private static readonly Regex UnescapeGlobRegex = new(@"\\(?.)", RegexOptions.Compiled); + + [GeneratedRegex(@"\\(?.)")] + private static partial Regex UnescapeGlobRegex(); /// /// start with * and has more than one * and followed by anything except * or / /// - private static readonly Regex ExpandGlobStarRegex = new(@"^\*{2,}(?=[^/*])", RegexOptions.Compiled); + [GeneratedRegex(@"^\*{2,}(?=[^/*])")] + private static partial Regex ExpandGlobStarRegex(); + // Never match .abc file unless AllowDotMatch option is set private const string PatternStartWithDotAllowed = @"(?!(?:^|\/)\.{1,2}(?:$|\/))"; private const string PatternStartWithoutDotAllowed = @"(?!\.)"; @@ -37,7 +41,8 @@ public class GlobMatcher : IEquatable /// private const string SingleStarToRegex = "[^/]*?"; - private static readonly Regex GlobStarRegex = new(@"^\*{2,}/?$", RegexOptions.Compiled); + [GeneratedRegex(@"^\*{2,}/?$")] + private static partial Regex GlobStarRegex(); private readonly GlobRegexItem[][] _items; private readonly bool _negate = false; @@ -115,7 +120,7 @@ private IEnumerable Compile(string pattern) if (Options.HasFlag(GlobMatcherOptions.AllowExpand)) { globs = ExpandGroup(pattern, Options); - if (globs.Length == 0) return Enumerable.Empty(); + if (globs.Length == 0) return []; } else { @@ -159,7 +164,7 @@ private static bool IsFolderPath(string path) private GlobRegexItem ConvertSingleGlobPart(string globPart) { // Return GlobStar for ** - if (Options.HasFlag(GlobMatcherOptions.AllowGlobStar) && GlobStarRegex.IsMatch(globPart)) + if (Options.HasFlag(GlobMatcherOptions.AllowGlobStar) && GlobStarRegex().IsMatch(globPart)) { return IsFolderPath(globPart) ? GlobRegexItem.GlobStar : GlobRegexItem.GlobStarForFileOnly; } @@ -326,10 +331,10 @@ private static IEnumerable ExpandGlobStarShortcut(IEnumerable gl { foreach (var part in globParts) { - if (ExpandGlobStarRegex.IsMatch(part)) + if (ExpandGlobStarRegex().IsMatch(part)) { yield return GlobStar + "/"; - yield return ExpandGlobStarRegex.Replace(part, "*"); + yield return ExpandGlobStarRegex().Replace(part, "*"); } else { @@ -413,7 +418,7 @@ private bool DisallowedMatchExists(string filePart) private static string UnescapeGlob(string s) { - return UnescapeGlobRegex.Replace(s, new MatchEvaluator(ReplaceReplacerGroup)); + return UnescapeGlobRegex().Replace(s, new MatchEvaluator(ReplaceReplacerGroup)); } private static string ReplaceReplacerGroup(Match m) @@ -553,8 +558,7 @@ public override GlobNode FinishLevel() } public override List Flatten() { - List result = new(1); - result.Add(_builder); + List result = [_builder]; return result; } } @@ -564,7 +568,7 @@ public class ChoiceNode : GlobNode public ChoiceNode(GlobNode parentNode) : base(parentNode) { - _nodes = new List(); + _nodes = []; } public override GlobNode AddChar(char c) { @@ -589,7 +593,7 @@ public override GlobNode FinishLevel() } public override List Flatten() { - List result = new(); + List result = []; foreach (GlobNode node in _nodes) { foreach (StringBuilder builder in node.Flatten()) @@ -606,7 +610,7 @@ public class SequenceNode : GlobNode public SequenceNode(GlobNode parentNode) : base(parentNode) { - _nodes = new List(); + _nodes = []; } public override GlobNode AddChar(char c) { @@ -630,11 +634,10 @@ public override GlobNode FinishLevel() } public override List Flatten() { - List result = new(); - result.Add(new StringBuilder()); + List result = [new StringBuilder()]; foreach (GlobNode node in _nodes) { - List tmp = new(); + List tmp = []; foreach (StringBuilder builder in node.Flatten()) { foreach (StringBuilder sb in result) diff --git a/src/Docfx.MarkdigEngine.Extensions/Aggregator/TabGroupAggregator.cs b/src/Docfx.MarkdigEngine.Extensions/Aggregator/TabGroupAggregator.cs index b2d531fccd1..f3cda27bcb3 100644 --- a/src/Docfx.MarkdigEngine.Extensions/Aggregator/TabGroupAggregator.cs +++ b/src/Docfx.MarkdigEngine.Extensions/Aggregator/TabGroupAggregator.cs @@ -9,9 +9,10 @@ namespace Docfx.MarkdigEngine.Extensions; -public class TabGroupAggregator : BlockAggregator +public partial class TabGroupAggregator : BlockAggregator { - private static readonly Regex HrefRegex = new(@"^#tab\/(?[a-zA-Z0-9\-]+(?:\+[a-zA-Z0-9\-]+)*)(?:\/(?[a-zA-Z0-9\-]+)?)?$", RegexOptions.Compiled); + [GeneratedRegex(@"^#tab\/(?[a-zA-Z0-9\-]+(?:\+[a-zA-Z0-9\-]+)*)(?:\/(?[a-zA-Z0-9\-]+)?)?$")] + private static partial Regex HrefRegex(); protected override bool AggregateCore(HeadingBlock headBlock, BlockAggregateContext context) { @@ -106,9 +107,9 @@ private static TabItemBlock CreateTabItem( private static Tuple ParseHeading(HeadingBlock block) { var child = block.Inline.FirstChild; - if (child is {NextSibling: null} and LinkInline link) + if (child is { NextSibling: null } and LinkInline link) { - var m = HrefRegex.Match(link.Url); + var m = HrefRegex().Match(link.Url); if (m.Success) { return Tuple.Create(m.Groups["id"].Value, m.Groups["condition"].Value, link); diff --git a/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/CodeSnippetExtractor.cs b/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/CodeSnippetExtractor.cs index 072a9b97d3d..1053efc6f54 100644 --- a/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/CodeSnippetExtractor.cs +++ b/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/CodeSnippetExtractor.cs @@ -7,9 +7,11 @@ namespace Docfx.MarkdigEngine.Extensions; -public class CodeSnippetExtractor +public partial class CodeSnippetExtractor { - private static readonly Regex TagnameFormat = new(@"^[\w\.-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + [GeneratedRegex(@"^[\w\.-]+$", RegexOptions.IgnoreCase, "en-AU")] + private static partial Regex TagnameFormat(); + private readonly string StartLineTemplate; private readonly string EndLineTemplate; private readonly bool IsEndLineContainsTagName; @@ -112,6 +114,6 @@ private static bool MatchTag(string line, string template, out string tagName, b if (index != afterTagName.Length) return false; while (column < line.Length && CharHelper.IsWhitespace(line[column])) column++; - return column == line.Length && (!containTagName || TagnameFormat.IsMatch(tagName)); + return column == line.Length && (!containTagName || TagnameFormat().IsMatch(tagName)); } } diff --git a/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/HtmlCodeSnippetRenderer.cs b/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/HtmlCodeSnippetRenderer.cs index 7cbd512a00d..fa6c849dbf9 100644 --- a/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/HtmlCodeSnippetRenderer.cs +++ b/src/Docfx.MarkdigEngine.Extensions/CodeSnippet/HtmlCodeSnippetRenderer.cs @@ -110,17 +110,17 @@ public class HtmlCodeSnippetRenderer : HtmlObjectRenderer { "vb", new string[] {"vbnet", "vbscript", "bas", "vbs", "vba" } } }; - private static readonly Dictionary s_languageByFileExtension = new(); + private static readonly Dictionary s_languageByFileExtension = []; // If we ever come across a language that has not been defined above, we shouldn't break the build. // We can at least try it with a default language, "C#" for now, and try and resolve the code snippet. - private static readonly HashSet s_defaultExtractors = new(); + private static readonly HashSet s_defaultExtractors = []; // Language names and aliases follow http://highlightjs.readthedocs.org/en/latest/css-classes-reference.html#language-names-and-aliases // Language file extensions follow https://github.com/github/linguist/blob/master/lib/linguist/languages.yml // Currently only supports parts of the language names, aliases and extensions // Later we can move the repository's supported/custom language names, aliases, extensions and corresponding comments regexes to docfx build configuration - private static readonly Dictionary> s_languageExtractors = new(); + private static readonly Dictionary> s_languageExtractors = []; private readonly MarkdownContext _context; @@ -198,7 +198,7 @@ static void AddExtractorItem(string language, CodeSnippetExtractor extractor) } else { - s_languageExtractors[language] = new HashSet { extractor }; + s_languageExtractors[language] = [extractor]; } } } @@ -299,22 +299,22 @@ public string GetContent(string content, CodeSnippet obj) var tagWithPrefix = TagPrefix + obj.TagName; foreach (var extractor in extractors) { - HashSet tagLines = new(); + HashSet tagLines = []; var tagToCodeRangeMapping = extractor.GetAllTags(allLines, ref tagLines); if (tagToCodeRangeMapping.TryGetValue(obj.TagName, out var cr) || tagToCodeRangeMapping.TryGetValue(tagWithPrefix, out cr)) { - return GetCodeLines(allLines, obj, new List { cr }, tagLines); + return GetCodeLines(allLines, obj, [cr], tagLines); } } } else if (obj.BookMarkRange != null) { - return GetCodeLines(allLines, obj, new List { obj.BookMarkRange }); + return GetCodeLines(allLines, obj, [obj.BookMarkRange]); } else if (obj.StartEndRange != null) { - return GetCodeLines(allLines, obj, new List { obj.StartEndRange }); + return GetCodeLines(allLines, obj, [obj.StartEndRange]); } else if (obj.CodeRanges != null) { @@ -322,7 +322,7 @@ public string GetContent(string content, CodeSnippet obj) } else { - return GetCodeLines(allLines, obj, new List { new() { Start = 0, End = allLines.Length } }); + return GetCodeLines(allLines, obj, [new() { Start = 0, End = allLines.Length }]); } return string.Empty; @@ -340,7 +340,7 @@ private static IEnumerable ReadAllLines(string content) private static string GetCodeLines(string[] allLines, CodeSnippet obj, List codeRanges, HashSet ignoreLines = null) { - List codeLines = new(); + List codeLines = []; StringBuilder showCode = new(); int commonIndent = int.MaxValue; @@ -458,7 +458,7 @@ public static bool TryGetLineRanges(string query, out List codeRanges return false; } - codeRanges ??= new List(); + codeRanges ??= []; codeRanges.Add(codeRange); } diff --git a/src/Docfx.MarkdigEngine.Extensions/ExtensionsHelper.cs b/src/Docfx.MarkdigEngine.Extensions/ExtensionsHelper.cs index 1619e0bd5d2..2a47f838972 100644 --- a/src/Docfx.MarkdigEngine.Extensions/ExtensionsHelper.cs +++ b/src/Docfx.MarkdigEngine.Extensions/ExtensionsHelper.cs @@ -8,11 +8,16 @@ namespace Docfx.MarkdigEngine.Extensions; -public static class ExtensionsHelper +public static partial class ExtensionsHelper { - public static readonly Regex HtmlEscapeWithEncode = new("&", RegexOptions.Compiled); - public static readonly Regex HtmlEscapeWithoutEncode = new(@"&(?!#?\w+;)", RegexOptions.Compiled); - public static readonly Regex HtmlUnescape = new(@"&([#\w]+);", RegexOptions.Compiled); + [GeneratedRegex("&")] + private static partial Regex HtmlEscapeWithEncode(); + + [GeneratedRegex(@"&(?!#?\w+;)")] + private static partial Regex HtmlEscapeWithoutEncode(); + + [GeneratedRegex(@"&([#\w]+);")] + private static partial Regex HtmlUnescape(); public static char SkipSpaces(ref StringSlice slice) { @@ -29,7 +34,7 @@ public static char SkipSpaces(ref StringSlice slice) public static string Escape(string html, bool encode = false) { return html - .ReplaceRegex(encode ? HtmlEscapeWithEncode : HtmlEscapeWithoutEncode, "&") + .ReplaceRegex(encode ? HtmlEscapeWithEncode() : HtmlEscapeWithoutEncode(), "&") .Replace("<", "<") .Replace(">", ">") .Replace("\"", """) @@ -38,7 +43,7 @@ public static string Escape(string html, bool encode = false) public static string Unescape(string html) { - return HtmlUnescape.Replace(html, match => + return HtmlUnescape().Replace(html, match => { var n = match.Groups[1].Value; @@ -134,7 +139,7 @@ public static void SkipWhitespace(ref StringSlice slice) } } - public static string TryGetStringBeforeChars(IEnumerable chars, ref StringSlice slice, bool breakOnWhitespace = false) + public static string TryGetStringBeforeChars(IReadOnlyList chars, ref StringSlice slice, bool breakOnWhitespace = false) { StringSlice savedSlice = slice; var c = slice.CurrentChar; @@ -234,12 +239,12 @@ private static bool MatchPath(ref StringSlice slice, ref string path) string includedFilePath; if (slice.CurrentChar == '<') { - includedFilePath = TryGetStringBeforeChars(new char[] { ')', '>' }, ref slice, breakOnWhitespace: true); + includedFilePath = TryGetStringBeforeChars([')', '>'], ref slice, breakOnWhitespace: true); } else { - includedFilePath = TryGetStringBeforeChars(new char[] { ')' }, ref slice, breakOnWhitespace: true); - }; + includedFilePath = TryGetStringBeforeChars([')'], ref slice, breakOnWhitespace: true); + } if (includedFilePath == null) { @@ -259,7 +264,7 @@ private static bool MatchPath(ref StringSlice slice, ref string path) } else { - var title = TryGetStringBeforeChars(new char[] { ')' }, ref slice, breakOnWhitespace: false); + var title = TryGetStringBeforeChars([')'], ref slice, breakOnWhitespace: false); if (title == null) { return false; diff --git a/src/Docfx.MarkdigEngine.Extensions/HeadingId/HeadingIdRewriter.cs b/src/Docfx.MarkdigEngine.Extensions/HeadingId/HeadingIdRewriter.cs index fd570714c4e..d413b75b748 100644 --- a/src/Docfx.MarkdigEngine.Extensions/HeadingId/HeadingIdRewriter.cs +++ b/src/Docfx.MarkdigEngine.Extensions/HeadingId/HeadingIdRewriter.cs @@ -9,10 +9,13 @@ namespace Docfx.MarkdigEngine.Extensions; -public class HeadingIdRewriter : IMarkdownObjectRewriter +public partial class HeadingIdRewriter : IMarkdownObjectRewriter { - private static readonly Regex OpenARegex = new(@"^\$", RegexOptions.Compiled); - private static readonly Regex CloseARegex = new(@"^\<\/a\>$", RegexOptions.Compiled); + [GeneratedRegex(@"^\$")] + private static partial Regex OpenARegex(); + + [GeneratedRegex(@"^\<\/a\>$")] + private static partial Regex CloseARegex(); public void PostProcess(IMarkdownObject markdownObject) { @@ -66,12 +69,12 @@ private static string ParseHeading(HeadingBlock headBlock) return null; } - var m = OpenARegex.Match(openATag.Tag); + var m = OpenARegex().Match(openATag.Tag); if (!m.Success) { return null; } - if (!CloseARegex.IsMatch(closeATag.Tag)) + if (!CloseARegex().IsMatch(closeATag.Tag)) { return null; } diff --git a/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSetting.cs b/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSetting.cs index 87cf1a0d20a..8872302adc8 100644 --- a/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSetting.cs +++ b/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSetting.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Text.Json; using System.Text.Json.Nodes; -using System.Text.Json.Serialization; #nullable enable diff --git a/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.NewtonsoftJson.cs b/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.NewtonsoftJson.cs index 2b5b4b514d9..9434a18f1b5 100644 --- a/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.NewtonsoftJson.cs +++ b/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.NewtonsoftJson.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Docfx.MarkdigEngine.Extensions; diff --git a/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.SystemTextJson.cs b/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.SystemTextJson.cs index bd903601a1b..93f7a1cf69d 100644 --- a/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.SystemTextJson.cs +++ b/src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSettingConverter.SystemTextJson.cs @@ -3,8 +3,6 @@ using System.Text.Json; using System.Text.Json.Serialization; -using System.Text.Json.Nodes; -using System.Xml.Linq; namespace Docfx.MarkdigEngine.Extensions; diff --git a/src/Docfx.MarkdigEngine.Extensions/MonikerRange/MonikerRangeParser.cs b/src/Docfx.MarkdigEngine.Extensions/MonikerRange/MonikerRangeParser.cs index 3e8a92f5756..ec73184fe3a 100644 --- a/src/Docfx.MarkdigEngine.Extensions/MonikerRange/MonikerRangeParser.cs +++ b/src/Docfx.MarkdigEngine.Extensions/MonikerRange/MonikerRangeParser.cs @@ -142,7 +142,7 @@ public override BlockState TryContinue(BlockProcessor processor, Block block) public override bool Close(BlockProcessor processor, Block block) { var monikerRange = (MonikerRangeBlock)block; - if (monikerRange is {Closed: false}) + if (monikerRange is { Closed: false }) { _context.LogWarning("invalid-moniker-range", $"No \"::: {EndString}\" found for \"{monikerRange.MonikerRange}\", MonikerRange does not end explicitly.", block); } diff --git a/src/Docfx.MarkdigEngine.Extensions/Noloc/NolocParser.cs b/src/Docfx.MarkdigEngine.Extensions/Noloc/NolocParser.cs index b7dfa65b018..12447ff19bd 100644 --- a/src/Docfx.MarkdigEngine.Extensions/Noloc/NolocParser.cs +++ b/src/Docfx.MarkdigEngine.Extensions/Noloc/NolocParser.cs @@ -24,7 +24,7 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice) return false; } - var text = ExtensionsHelper.TryGetStringBeforeChars(new char[] { '\"', '\n' }, ref slice); + var text = ExtensionsHelper.TryGetStringBeforeChars(['\"', '\n'], ref slice); if (text == null || text.Contains('\n')) { diff --git a/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlCodeBlockRenderer.cs b/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlCodeBlockRenderer.cs index 5957c059df4..0f6154d6dca 100644 --- a/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlCodeBlockRenderer.cs +++ b/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlCodeBlockRenderer.cs @@ -44,7 +44,7 @@ public PlantUmlCodeBlockRenderer(MarkdownContext context, PlantUmlOptions settin protected override void Write(HtmlRenderer renderer, CodeBlock obj) { - if (obj is FencedCodeBlock {Info: string info} fencedCodeBlock + if (obj is FencedCodeBlock { Info: string info } fencedCodeBlock && info.Equals("plantuml", StringComparison.OrdinalIgnoreCase)) { IPlantUmlRenderer plantUmlRenderer = rendererFactory.CreateRenderer(_settings); diff --git a/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlExtension.cs b/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlExtension.cs index 469d9bc73bc..56ebdbe8a88 100644 --- a/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlExtension.cs +++ b/src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlExtension.cs @@ -18,7 +18,7 @@ public class PlantUmlOptions [JsonProperty("remoteUrl")] [JsonPropertyName("remoteUrl")] - public string RemoteUrl { get; set; } + public string RemoteUrl { get; set; } = "http://www.plantuml.com/plantuml/"; [JsonProperty("localPlantUmlPath")] [JsonPropertyName("localPlantUmlPath")] @@ -30,7 +30,7 @@ public class PlantUmlOptions [JsonProperty("renderingMode")] [JsonPropertyName("renderingMode")] - public RenderingMode RenderingMode { get; set; } + public RenderingMode RenderingMode { get; set; } = RenderingMode.Remote; [JsonProperty("delimitor")] [JsonPropertyName("delimitor")] diff --git a/src/Docfx.MarkdigEngine.Extensions/QuoteSectionNote/QuoteSectionNoteRender.cs b/src/Docfx.MarkdigEngine.Extensions/QuoteSectionNote/QuoteSectionNoteRender.cs index d96394903bb..da1ee519202 100644 --- a/src/Docfx.MarkdigEngine.Extensions/QuoteSectionNote/QuoteSectionNoteRender.cs +++ b/src/Docfx.MarkdigEngine.Extensions/QuoteSectionNote/QuoteSectionNoteRender.cs @@ -1,13 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.ObjectModel; +using System.Text.RegularExpressions; using System.Web; using Markdig.Renderers; using Markdig.Renderers.Html; namespace Docfx.MarkdigEngine.Extensions; -public class QuoteSectionNoteRender : HtmlObjectRenderer +public partial class QuoteSectionNoteRender : HtmlObjectRenderer { private readonly MarkdownContext _context; private readonly Dictionary _notes; @@ -100,13 +102,14 @@ private static void WriteVideo(HtmlRenderer renderer, QuoteSectionNoteBlock obj) public static string FixUpLink(string link) { - if (!link.Contains("https")) + if (link.StartsWith("http:")) { - link = link.Replace("http", "https"); + link = "https:" + link.Substring("http:".Length); } if (Uri.TryCreate(link, UriKind.Absolute, out Uri videoLink)) { var host = videoLink.Host; + var path = videoLink.LocalPath; var query = videoLink.Query; if (query.Length > 1) { @@ -125,16 +128,115 @@ public static string FixUpLink(string link) query += "&nocookie=true"; } } - else if (host.Equals("youtube.com", StringComparison.OrdinalIgnoreCase) || host.Equals("www.youtube.com", StringComparison.OrdinalIgnoreCase)) + else if (hostsYouTube.Contains(host, StringComparer.OrdinalIgnoreCase)) { // case 2, YouTube video - host = "www.youtube-nocookie.com"; + var idYouTube = GetYouTubeId(host, path, ref query); + if (idYouTube != null) + { + host = "www.youtube-nocookie.com"; + path = "/embed/" + idYouTube; + query = AddYouTubeRel(query); + } + else + { + //YouTube Playlist + var listYouTube = GetYouTubeList(query); + if (listYouTube != null) + { + host = "www.youtube-nocookie.com"; + path = "/embed/videoseries"; + query = "list=" + listYouTube; + query = AddYouTubeRel(query); + } + } + + //Keep this to preserve previous behavior + if (host.Equals("youtube.com", StringComparison.OrdinalIgnoreCase) || host.Equals("www.youtube.com", StringComparison.OrdinalIgnoreCase)) + { + host = "www.youtube-nocookie.com"; + } } - var builder = new UriBuilder(videoLink) { Host = host, Query = query }; + var builder = new UriBuilder(videoLink) { Host = host, Path = path, Query = query }; link = builder.Uri.ToString(); } return link; } + + /// + /// Only related videos from the same channel + /// https://developers.google.com/youtube/player_parameters + /// + private static string AddYouTubeRel(string query) + { + // Add rel=0 unless specified in the original link + if (query.Split('&').Any(q => q.StartsWith("rel=")) == false) + { + if (query.Length == 0) + return "rel=0"; + else + return query + "&rel=0"; + } + + return query; + } + + private static readonly ReadOnlyCollection hostsYouTube = new string[] { + "youtube.com", + "www.youtube.com", + "youtu.be", + "www.youtube-nocookie.com", + }.AsReadOnly(); + + private static string GetYouTubeId(string host, string path, ref string query) + { + if (host == "youtu.be") + { + return path.Substring(1); + } + + var match = ReYouTubeQueryVideo().Match(query); + if (match.Success) + { + //Remove from query + query = query.Replace(match.Groups[0].Value, "").Trim('&').Replace("&&", "&"); + return match.Groups[2].Value; + } + + match = ReYouTubePathId().Match(path); + if (match.Success) + { + var id = match.Groups[1].Value; + + if (id == "videoseries") + return null; + + return id; + } + + return null; + } + + [GeneratedRegex(@"(^|&)v=([^&]+)")] + private static partial Regex ReYouTubeQueryVideo(); + + [GeneratedRegex(@"(^|&)list=([^&]+)")] + private static partial Regex ReYouTubeQueryList(); + + [GeneratedRegex(@"/embed/([^/]+)$")] + private static partial Regex ReYouTubePathId(); + + private static string GetYouTubeList(string query) + { + var match = ReYouTubeQueryList().Match(query); + if (match.Success) + { + return match.Groups[2].Value; + } + + return null; + } + } diff --git a/src/Docfx.MarkdigEngine.Extensions/ResolveLink/ResolveLinkExtension.cs b/src/Docfx.MarkdigEngine.Extensions/ResolveLink/ResolveLinkExtension.cs index 321d577d9ad..6eab26c3c14 100644 --- a/src/Docfx.MarkdigEngine.Extensions/ResolveLink/ResolveLinkExtension.cs +++ b/src/Docfx.MarkdigEngine.Extensions/ResolveLink/ResolveLinkExtension.cs @@ -49,7 +49,7 @@ private void UpdateLinks(MarkdownObject markdownObject) } break; - case LeafBlock {Inline: not null} leafBlock: + case LeafBlock { Inline: not null } leafBlock: foreach (var subInline in leafBlock.Inline) { UpdateLinks(subInline); diff --git a/src/Docfx.MarkdigEngine.Extensions/Rewriter/MarkdownDocumentVisitor.cs b/src/Docfx.MarkdigEngine.Extensions/Rewriter/MarkdownDocumentVisitor.cs index fa3e396666e..5d40f352a7d 100644 --- a/src/Docfx.MarkdigEngine.Extensions/Rewriter/MarkdownDocumentVisitor.cs +++ b/src/Docfx.MarkdigEngine.Extensions/Rewriter/MarkdownDocumentVisitor.cs @@ -43,7 +43,7 @@ private void RewriteContainerBlock(ContainerBlock blocks) for (var i = 0; i < blocks.Count; i++) { var block = blocks[i]; - if (block is LeafBlock {Inline: not null} leafBlock) + if (block is LeafBlock { Inline: not null } leafBlock) { RewriteContainerInline(leafBlock.Inline); } diff --git a/src/Docfx.MarkdigEngine.Extensions/TabGroup/ActiveAndVisibleRewriter.cs b/src/Docfx.MarkdigEngine.Extensions/TabGroup/ActiveAndVisibleRewriter.cs index adce056fc14..04c4d8712f8 100644 --- a/src/Docfx.MarkdigEngine.Extensions/TabGroup/ActiveAndVisibleRewriter.cs +++ b/src/Docfx.MarkdigEngine.Extensions/TabGroup/ActiveAndVisibleRewriter.cs @@ -10,7 +10,7 @@ namespace Docfx.MarkdigEngine.Extensions; public class ActiveAndVisibleRewriter : IMarkdownObjectRewriter { private readonly MarkdownContext _context; - private readonly List tabSelectionInfo = new(); + private readonly List tabSelectionInfo = []; public ActiveAndVisibleRewriter(MarkdownContext context) { diff --git a/src/Docfx.MarkdigEngine.Extensions/TripleColon/ImageExtension.cs b/src/Docfx.MarkdigEngine.Extensions/TripleColon/ImageExtension.cs index b8057c314ce..bf7d4efac61 100644 --- a/src/Docfx.MarkdigEngine.Extensions/TripleColon/ImageExtension.cs +++ b/src/Docfx.MarkdigEngine.Extensions/TripleColon/ImageExtension.cs @@ -158,7 +158,7 @@ public bool Render(HtmlRenderer renderer, MarkdownObject obj, Action log { renderer.Write(""); - if (tripleColonObj is ContainerBlock {LastChild: not null} block) + if (tripleColonObj is ContainerBlock { LastChild: not null } block) { var inline = (block.LastChild as ParagraphBlock).Inline; renderer.WriteChildren(inline); diff --git a/src/Docfx.MarkdigEngine.Extensions/TripleColon/TripleColonBlockParser.cs b/src/Docfx.MarkdigEngine.Extensions/TripleColon/TripleColonBlockParser.cs index 69ed2936180..bc7b35ff8a1 100644 --- a/src/Docfx.MarkdigEngine.Extensions/TripleColon/TripleColonBlockParser.cs +++ b/src/Docfx.MarkdigEngine.Extensions/TripleColon/TripleColonBlockParser.cs @@ -105,7 +105,7 @@ public override BlockState TryOpen(BlockProcessor processor) public override BlockState TryContinue(BlockProcessor processor, Block block) { var slice = processor.Line; - var colonBlock = (TripleColonBlock) block; + var colonBlock = (TripleColonBlock)block; var endingTripleColons = colonBlock.EndingTripleColons; Type type = ((TripleColonBlock)block).Extension.GetType(); diff --git a/src/Docfx.MarkdigEngine.Extensions/TripleColon/VideoExtension.cs b/src/Docfx.MarkdigEngine.Extensions/TripleColon/VideoExtension.cs index cf6be57a68d..76900fae9bf 100644 --- a/src/Docfx.MarkdigEngine.Extensions/TripleColon/VideoExtension.cs +++ b/src/Docfx.MarkdigEngine.Extensions/TripleColon/VideoExtension.cs @@ -155,7 +155,7 @@ public bool Render(HtmlRenderer renderer, MarkdownObject markdownObject, Action< renderer.WriteLine("
"); renderer.Write($""); renderer.WriteLine("
"); - if (tripleColonObj is ContainerBlock {LastChild: not null} block) + if (tripleColonObj is ContainerBlock { LastChild: not null } block) { var inline = (block.LastChild as ParagraphBlock).Inline; renderer.WriteChildren(inline); diff --git a/src/Docfx.MarkdigEngine.Extensions/TripleColon/ZoneExtension.cs b/src/Docfx.MarkdigEngine.Extensions/TripleColon/ZoneExtension.cs index f62c5a1eca1..6c405b31698 100644 --- a/src/Docfx.MarkdigEngine.Extensions/TripleColon/ZoneExtension.cs +++ b/src/Docfx.MarkdigEngine.Extensions/TripleColon/ZoneExtension.cs @@ -8,10 +8,13 @@ namespace Docfx.MarkdigEngine.Extensions; -public class ZoneExtension : ITripleColonExtensionInfo +public partial class ZoneExtension : ITripleColonExtensionInfo { - private static readonly Regex s_pivotRegex = new(@"^\s*(?:[a-z0-9-]+)(?:\s*,\s*[a-z0-9-]+)*\s*$"); - private static readonly Regex s_pivotReplaceCommasRegex = new(@"\s*,\s*"); + [GeneratedRegex(@"^\s*(?:[a-z0-9-]+)(?:\s*,\s*[a-z0-9-]+)*\s*$")] + private static partial Regex s_pivotRegex(); + + [GeneratedRegex(@"\s*,\s*")] + private static partial Regex s_pivotReplaceCommasRegex(); public string Name => "zone"; @@ -46,7 +49,7 @@ public bool TryProcessAttributes(IDictionary attributes, out Htm target = value; break; case "pivot": - if (!s_pivotRegex.IsMatch(value)) + if (!s_pivotRegex().IsMatch(value)) { logError($"Invalid pivot \"{value}\". Pivot must be a comma-delimited list of pivot names. Pivot names must be lower-case and contain only letters, numbers or dashes."); return false; @@ -80,7 +83,7 @@ public bool TryProcessAttributes(IDictionary attributes, out Htm if (!string.IsNullOrEmpty(pivot)) { htmlAttributes.AddClass("has-pivot"); - htmlAttributes.AddProperty("data-pivot", pivot.Trim().ReplaceRegex(s_pivotReplaceCommasRegex, " ")); + htmlAttributes.AddProperty("data-pivot", pivot.Trim().ReplaceRegex(s_pivotReplaceCommasRegex(), " ")); } return true; } diff --git a/src/Docfx.MarkdigEngine/MarkdigMarkdownService.cs b/src/Docfx.MarkdigEngine/MarkdigMarkdownService.cs index 3a7ebcf566a..4623b4b0476 100644 --- a/src/Docfx.MarkdigEngine/MarkdigMarkdownService.cs +++ b/src/Docfx.MarkdigEngine/MarkdigMarkdownService.cs @@ -135,7 +135,7 @@ private MarkdownPipeline CreateMarkdownPipeline(bool isInline, bool multipleYaml builder.UseInlineOnly(); } - if (_parameters?.Extensions?.MarkdigExtensions is {Length: > 0} extensions) + if (_parameters?.Extensions?.MarkdigExtensions is { Length: > 0 } extensions) { builder.UseOptionalExtensions(extensions); } diff --git a/src/Docfx.Plugins/FileModel.cs b/src/Docfx.Plugins/FileModel.cs index 6c5b6e7adc6..c49cd10fe16 100644 --- a/src/Docfx.Plugins/FileModel.cs +++ b/src/Docfx.Plugins/FileModel.cs @@ -67,9 +67,9 @@ public string File public string Key { get; } - public ImmutableHashSet LinkToFiles { get; set; } = ImmutableHashSet.Empty; + public ImmutableHashSet LinkToFiles { get; set; } = []; - public ImmutableHashSet LinkToUids { get; set; } = ImmutableHashSet.Empty; + public ImmutableHashSet LinkToUids { get; set; } = []; public ImmutableDictionary> UidLinkSources { get; set; } = ImmutableDictionary>.Empty; diff --git a/src/Docfx.Plugins/GroupInfo.cs b/src/Docfx.Plugins/GroupInfo.cs index f1a2eaea0d5..46de030df40 100644 --- a/src/Docfx.Plugins/GroupInfo.cs +++ b/src/Docfx.Plugins/GroupInfo.cs @@ -9,5 +9,5 @@ public class GroupInfo public string Destination { get; set; } - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Plugins/Manifest.cs b/src/Docfx.Plugins/Manifest.cs index 729c8b853c6..3af14a535d6 100644 --- a/src/Docfx.Plugins/Manifest.cs +++ b/src/Docfx.Plugins/Manifest.cs @@ -27,7 +27,7 @@ public Manifest() { } [JsonProperty("files")] [JsonPropertyName("files")] - public List Files { get; init; } = new(); + public List Files { get; init; } = []; [JsonProperty("groups")] [JsonPropertyName("groups")] diff --git a/src/Docfx.Plugins/ManifestGroupInfo.cs b/src/Docfx.Plugins/ManifestGroupInfo.cs index 0bf3b2b5edf..c123eadf3c2 100644 --- a/src/Docfx.Plugins/ManifestGroupInfo.cs +++ b/src/Docfx.Plugins/ManifestGroupInfo.cs @@ -22,7 +22,7 @@ public class ManifestGroupInfo [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; // Default constructor for System.Text.Json deserialization public ManifestGroupInfo() { } diff --git a/src/Docfx.Plugins/ManifestItem.cs b/src/Docfx.Plugins/ManifestItem.cs index 003278e7a7a..8f684435026 100644 --- a/src/Docfx.Plugins/ManifestItem.cs +++ b/src/Docfx.Plugins/ManifestItem.cs @@ -18,7 +18,7 @@ public class ManifestItem [JsonProperty("output")] [JsonPropertyName("output")] - public Dictionary Output { get; init; } = new(); + public Dictionary Output { get; init; } = []; [JsonProperty("version")] [JsonPropertyName("version")] @@ -30,5 +30,5 @@ public class ManifestItem [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Plugins/OutputFileInfo.cs b/src/Docfx.Plugins/OutputFileInfo.cs index 3779d0357e5..ad4c0e8bbda 100644 --- a/src/Docfx.Plugins/OutputFileInfo.cs +++ b/src/Docfx.Plugins/OutputFileInfo.cs @@ -18,5 +18,5 @@ public class OutputFileInfo [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Plugins/TreeItem.cs b/src/Docfx.Plugins/TreeItem.cs index fa53c634788..302c6c691a2 100644 --- a/src/Docfx.Plugins/TreeItem.cs +++ b/src/Docfx.Plugins/TreeItem.cs @@ -14,5 +14,5 @@ public class TreeItem [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/src/Docfx.Plugins/XRefSpec.cs b/src/Docfx.Plugins/XRefSpec.cs index 7fad3792ed8..7f20872794f 100644 --- a/src/Docfx.Plugins/XRefSpec.cs +++ b/src/Docfx.Plugins/XRefSpec.cs @@ -17,7 +17,7 @@ public sealed class XRefSpec : IDictionary public XRefSpec() { - _dict = new Dictionary(); + _dict = []; } public XRefSpec(IDictionary dictionary) diff --git a/src/Docfx.YamlSerialization/Docfx.YamlSerialization.csproj b/src/Docfx.YamlSerialization/Docfx.YamlSerialization.csproj index 4fdad984229..fa53905d37c 100644 --- a/src/Docfx.YamlSerialization/Docfx.YamlSerialization.csproj +++ b/src/Docfx.YamlSerialization/Docfx.YamlSerialization.csproj @@ -1,4 +1,8 @@ + + enable + + diff --git a/src/Docfx.YamlSerialization/ExtensibleMemberAttribute.cs b/src/Docfx.YamlSerialization/ExtensibleMemberAttribute.cs index 13c1eabe81a..f6d101faa74 100644 --- a/src/Docfx.YamlSerialization/ExtensibleMemberAttribute.cs +++ b/src/Docfx.YamlSerialization/ExtensibleMemberAttribute.cs @@ -9,12 +9,12 @@ public sealed class ExtensibleMemberAttribute : Attribute public string Prefix { get; } public ExtensibleMemberAttribute() - : this(null) + : this(string.Empty) { } public ExtensibleMemberAttribute(string prefix) { - Prefix = prefix ?? string.Empty; + Prefix = prefix; } } diff --git a/src/Docfx.YamlSerialization/Helpers/ReflectionUtility.cs b/src/Docfx.YamlSerialization/Helpers/ReflectionUtility.cs index 6c36e33d24b..da63545b1d6 100644 --- a/src/Docfx.YamlSerialization/Helpers/ReflectionUtility.cs +++ b/src/Docfx.YamlSerialization/Helpers/ReflectionUtility.cs @@ -5,7 +5,7 @@ namespace Docfx.YamlSerialization.Helpers; internal static class ReflectionUtility { - public static Type GetImplementedGenericInterface(Type type, Type genericInterfaceType) + public static Type? GetImplementedGenericInterface(Type type, Type genericInterfaceType) { foreach (var interfaceType in GetImplementedInterfaces(type)) { diff --git a/src/Docfx.YamlSerialization/Helpers/Regexes.cs b/src/Docfx.YamlSerialization/Helpers/Regexes.cs index 7127542f127..e4fce049ce3 100644 --- a/src/Docfx.YamlSerialization/Helpers/Regexes.cs +++ b/src/Docfx.YamlSerialization/Helpers/Regexes.cs @@ -5,19 +5,23 @@ namespace Docfx.YamlSerialization.Helpers; -internal static class Regexes +internal static partial class Regexes { // todo : boolean more for yaml http://yaml.org/type/bool.html // y|Y|yes|Yes|YES|n|N|no|No|NO // |true|True|TRUE|false|False|FALSE // |null|Null|NULL|~ // |on|On|ON|off|Off|OFF - public static readonly Regex BooleanLike = new("^(true|True|TRUE|false|False|FALSE)$", RegexOptions.Compiled); + [GeneratedRegex("^(true|True|TRUE|false|False|FALSE)$")] + public static partial Regex BooleanLike(); - public static readonly Regex NullLike = new("^(null|Null|NULL|~)$", RegexOptions.Compiled); + [GeneratedRegex("^(null|Null|NULL|~)$")] + public static partial Regex NullLike(); - public static readonly Regex IntegerLike = new("^-?(0|[1-9][0-9]*)$", RegexOptions.Compiled); + [GeneratedRegex("^-?(0|[1-9][0-9]*)$")] + public static partial Regex IntegerLike(); // https://yaml.org/spec/1.2/spec.html#id2805071 - public static readonly Regex FloatLike = new(@"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$", RegexOptions.Compiled); + [GeneratedRegex(@"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$")] + public static partial Regex FloatLike(); } diff --git a/src/Docfx.YamlSerialization/NodeDeserializers/EmitArrayNodeDeserializer.cs b/src/Docfx.YamlSerialization/NodeDeserializers/EmitArrayNodeDeserializer.cs index 513d15c718e..0dc273ac031 100644 --- a/src/Docfx.YamlSerialization/NodeDeserializers/EmitArrayNodeDeserializer.cs +++ b/src/Docfx.YamlSerialization/NodeDeserializers/EmitArrayNodeDeserializer.cs @@ -13,11 +13,11 @@ namespace Docfx.YamlSerialization.NodeDeserializers; public class EmitArrayNodeDeserializer : INodeDeserializer { private static readonly MethodInfo DeserializeHelperMethod = - typeof(EmitArrayNodeDeserializer).GetMethod(nameof(DeserializeHelper)); - private static readonly ConcurrentDictionary, object>> _funcCache = + typeof(EmitArrayNodeDeserializer).GetMethod(nameof(DeserializeHelper))!; + private static readonly ConcurrentDictionary, object?>> _funcCache = new(); - bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object value) + bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value) { if (!expectedType.IsArray) { @@ -31,22 +31,22 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func(IParser reader, Type expectedType, Func nestedObjectDeserializer) + public static TItem[] DeserializeHelper(IParser reader, Type expectedType, Func nestedObjectDeserializer) { var items = new List(); EmitGenericCollectionNodeDeserializer.DeserializeHelper(reader, expectedType, nestedObjectDeserializer, items); return items.ToArray(); } - private static Func, object> AddItem(Type expectedType) + private static Func, object?> AddItem(Type expectedType) { var dm = new DynamicMethod(string.Empty, typeof(object), [typeof(IParser), typeof(Type), typeof(Func)]); var il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(expectedType.GetElementType())); + il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(expectedType.GetElementType()!)); il.Emit(OpCodes.Ret); - return (Func, object>)dm.CreateDelegate(typeof(Func, object>)); + return (Func, object?>)dm.CreateDelegate(typeof(Func, object?>)); } } diff --git a/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericCollectionNodeDeserializer.cs b/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericCollectionNodeDeserializer.cs index 1863ba70ba9..58f5dd74ff2 100644 --- a/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericCollectionNodeDeserializer.cs +++ b/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericCollectionNodeDeserializer.cs @@ -17,21 +17,19 @@ namespace Docfx.YamlSerialization.NodeDeserializers; public class EmitGenericCollectionNodeDeserializer : INodeDeserializer { private static readonly MethodInfo DeserializeHelperMethod = - typeof(EmitGenericCollectionNodeDeserializer).GetMethod(nameof(DeserializeHelper)); + typeof(EmitGenericCollectionNodeDeserializer).GetMethod(nameof(DeserializeHelper))!; private readonly IObjectFactory _objectFactory; - private readonly Dictionary _gpCache = - new(); - private readonly Dictionary, object>> _actionCache = - new(); + private readonly Dictionary _gpCache = []; + private readonly Dictionary, object?>> _actionCache = []; public EmitGenericCollectionNodeDeserializer(IObjectFactory objectFactory) { _objectFactory = objectFactory; } - bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object value) + bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value) { - if (!_gpCache.TryGetValue(expectedType, out Type gp)) + if (!_gpCache.TryGetValue(expectedType, out var gp)) { var collectionType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(ICollection<>)); if (collectionType != null) @@ -66,7 +64,7 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func).MakeGenericType(gp)); il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(gp)); il.Emit(OpCodes.Ret); - action = (Action, object>)dm.CreateDelegate(typeof(Action, object>)); + action = (Action, object?>)dm.CreateDelegate(typeof(Action, object?>)); _actionCache[gp] = action; } @@ -75,13 +73,11 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func(IParser reader, Type expectedType, Func nestedObjectDeserializer, ICollection result) + public static void DeserializeHelper(IParser reader, Type expectedType, Func nestedObjectDeserializer, ICollection result) { reader.Consume(); while (!reader.Accept(out _)) { - var current = reader.Current; - var value = nestedObjectDeserializer(reader, typeof(TItem)); if (value is not IValuePromise promise) { @@ -90,11 +86,12 @@ public static void DeserializeHelper(IParser reader, Type expectedType, F else if (result is IList list) { var index = list.Count; - result.Add(default); + result.Add(default!); promise.ValueAvailable += v => list[index] = TypeConverter.ChangeType(v, NullNamingConvention.Instance); } else { + var current = reader.Current!; throw new ForwardAnchorNotSupportedException( current.Start, current.End, diff --git a/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericDictionaryNodeDeserializer.cs b/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericDictionaryNodeDeserializer.cs index 4094f4d174d..8294a3dd44d 100644 --- a/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericDictionaryNodeDeserializer.cs +++ b/src/Docfx.YamlSerialization/NodeDeserializers/EmitGenericDictionaryNodeDeserializer.cs @@ -14,21 +14,19 @@ namespace Docfx.YamlSerialization.NodeDeserializers; public class EmitGenericDictionaryNodeDeserializer : INodeDeserializer { private static readonly MethodInfo DeserializeHelperMethod = - typeof(EmitGenericDictionaryNodeDeserializer).GetMethod(nameof(DeserializeHelper)); + typeof(EmitGenericDictionaryNodeDeserializer).GetMethod(nameof(DeserializeHelper))!; private readonly IObjectFactory _objectFactory; - private readonly Dictionary _gpCache = - new(); - private readonly Dictionary, Action, object>> _actionCache = - new(); + private readonly Dictionary _gpCache = []; + private readonly Dictionary, Action, object?>> _actionCache = []; public EmitGenericDictionaryNodeDeserializer(IObjectFactory objectFactory) { _objectFactory = objectFactory; } - bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object value) + bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value) { - if (!_gpCache.TryGetValue(expectedType, out Type[] gp)) + if (!_gpCache.TryGetValue(expectedType, out var gp)) { var dictionaryType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IDictionary<,>)); if (dictionaryType != null) @@ -67,7 +65,7 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func).MakeGenericType(gp)); il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(gp)); il.Emit(OpCodes.Ret); - action = (Action, object>)dm.CreateDelegate(typeof(Action, object>)); + action = (Action, object?>)dm.CreateDelegate(typeof(Action, object?>)); _actionCache[cacheKey] = action; } action(reader, expectedType, nestedObjectDeserializer, value); @@ -78,7 +76,7 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func(IParser reader, Type expectedType, Func nestedObjectDeserializer, IDictionary result) + public static void DeserializeHelper(IParser reader, Type expectedType, Func nestedObjectDeserializer, IDictionary result) { while (!reader.Accept(out _)) { @@ -92,12 +90,12 @@ public static void DeserializeHelper(IParser reader, Type expected if (valuePromise == null) { // Happy path: both key and value are known - result[(TKey)key] = (TValue)value; + result[(TKey)key!] = (TValue)value!; } else { // Key is known, value is pending - valuePromise.ValueAvailable += v => result[(TKey)key] = (TValue)v; + valuePromise.ValueAvailable += v => result[(TKey)key!] = (TValue)v!; } } else @@ -105,7 +103,7 @@ public static void DeserializeHelper(IParser reader, Type expected if (valuePromise == null) { // Key is pending, value is known - keyPromise.ValueAvailable += v => result[(TKey)v] = (TValue)value; + keyPromise.ValueAvailable += v => result[(TKey)v!] = (TValue)value!; } else { @@ -116,7 +114,7 @@ public static void DeserializeHelper(IParser reader, Type expected { if (hasFirstPart) { - result[(TKey)v] = (TValue)value; + result[(TKey)v!] = (TValue)value!; } else { @@ -129,7 +127,7 @@ public static void DeserializeHelper(IParser reader, Type expected { if (hasFirstPart) { - result[(TKey)key] = (TValue)v; + result[(TKey)key] = (TValue)v!; } else { diff --git a/src/Docfx.YamlSerialization/NodeDeserializers/ExtensibleObjectNodeDeserializer.cs b/src/Docfx.YamlSerialization/NodeDeserializers/ExtensibleObjectNodeDeserializer.cs index 0e0c4802005..24980f3120d 100644 --- a/src/Docfx.YamlSerialization/NodeDeserializers/ExtensibleObjectNodeDeserializer.cs +++ b/src/Docfx.YamlSerialization/NodeDeserializers/ExtensibleObjectNodeDeserializer.cs @@ -22,7 +22,7 @@ public ExtensibleObjectNodeDeserializer(IObjectFactory objectFactory, ITypeInspe _ignoreUnmatched = ignoreUnmatched; } - bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object value) + bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value) { if (!reader.TryConsume(out _)) { diff --git a/src/Docfx.YamlSerialization/NodeTypeResolvers/ScalarYamlNodeTypeResolver.cs b/src/Docfx.YamlSerialization/NodeTypeResolvers/ScalarYamlNodeTypeResolver.cs index bca576600d1..30115993df1 100644 --- a/src/Docfx.YamlSerialization/NodeTypeResolvers/ScalarYamlNodeTypeResolver.cs +++ b/src/Docfx.YamlSerialization/NodeTypeResolvers/ScalarYamlNodeTypeResolver.cs @@ -9,19 +9,19 @@ namespace Docfx.YamlSerialization.NodeTypeResolvers; internal sealed class ScalarYamlNodeTypeResolver : INodeTypeResolver { - bool INodeTypeResolver.Resolve(NodeEvent nodeEvent, ref Type currentType) + bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (currentType == typeof(string) || currentType == typeof(object)) { - if (nodeEvent is Scalar {IsPlainImplicit: true} scalar) + if (nodeEvent is Scalar { IsPlainImplicit: true } scalar) { - if (Regexes.BooleanLike.IsMatch(scalar.Value)) + if (Regexes.BooleanLike().IsMatch(scalar.Value)) { currentType = typeof(bool); return true; } - if (Regexes.IntegerLike.IsMatch(scalar.Value)) + if (Regexes.IntegerLike().IsMatch(scalar.Value)) { if (int.TryParse(scalar.Value, out _)) { @@ -40,7 +40,7 @@ bool INodeTypeResolver.Resolve(NodeEvent nodeEvent, ref Type currentType) } } - if (Regexes.FloatLike.IsMatch(scalar.Value)) + if (Regexes.FloatLike().IsMatch(scalar.Value)) { currentType = typeof(double); return true; diff --git a/src/Docfx.YamlSerialization/ObjectDescriptors/BetterObjectDescriptor.cs b/src/Docfx.YamlSerialization/ObjectDescriptors/BetterObjectDescriptor.cs index 6732bc80dda..93e5f2a1d02 100644 --- a/src/Docfx.YamlSerialization/ObjectDescriptors/BetterObjectDescriptor.cs +++ b/src/Docfx.YamlSerialization/ObjectDescriptors/BetterObjectDescriptor.cs @@ -9,27 +9,27 @@ namespace Docfx.YamlSerialization.ObjectDescriptors; public class BetterObjectDescriptor : IObjectDescriptor { - public BetterObjectDescriptor(object value, Type type, Type staticType) + public BetterObjectDescriptor(object? value, Type type, Type staticType) : this(value, type, staticType, ScalarStyle.Any) { } - public BetterObjectDescriptor(object value, Type type, Type staticType, ScalarStyle scalarStyle) + public BetterObjectDescriptor(object? value, Type type, Type staticType, ScalarStyle scalarStyle) { Value = value; Type = type; StaticType = staticType; ScalarStyle = scalarStyle == ScalarStyle.Any && NeedQuote(value) ? ScalarStyle.DoubleQuoted : scalarStyle; - static bool NeedQuote(object val) + static bool NeedQuote(object? val) { - if (val is not string s) + if (val is not string s || s == null) return false; - return Regexes.BooleanLike.IsMatch(s) - || Regexes.NullLike.IsMatch(s) - || Regexes.IntegerLike.IsMatch(s) - || Regexes.FloatLike.IsMatch(s) + return Regexes.BooleanLike().IsMatch(s) + || Regexes.NullLike().IsMatch(s) + || Regexes.IntegerLike().IsMatch(s) + || Regexes.FloatLike().IsMatch(s) || s.StartsWith('\'') || s.StartsWith('"') || s.Length > 0 && char.IsWhiteSpace(s[0]); @@ -42,5 +42,5 @@ static bool NeedQuote(object val) public Type Type { get; } - public object Value { get; } + public object? Value { get; } } diff --git a/src/Docfx.YamlSerialization/ObjectFactories/DefaultEmitObjectFactory.cs b/src/Docfx.YamlSerialization/ObjectFactories/DefaultEmitObjectFactory.cs index 300a7cf9cbb..5cef58e0f1e 100644 --- a/src/Docfx.YamlSerialization/ObjectFactories/DefaultEmitObjectFactory.cs +++ b/src/Docfx.YamlSerialization/ObjectFactories/DefaultEmitObjectFactory.cs @@ -10,15 +10,15 @@ namespace Docfx.YamlSerialization.ObjectFactories; public class DefaultEmitObjectFactory : ObjectFactoryBase { - private readonly Dictionary> _cache = new(); + private readonly Dictionary> _cache = []; private static Type[] EmptyTypes => Type.EmptyTypes; public override object Create(Type type) { - if (!_cache.TryGetValue(type, out Func func)) + if (!_cache.TryGetValue(type, out var func)) { var realType = type; - if (type is {IsInterface: true, IsGenericType: true}) + if (type is { IsInterface: true, IsGenericType: true }) { var def = type.GetGenericTypeDefinition(); var args = type.GetGenericArguments(); @@ -46,7 +46,12 @@ public override object Create(Type type) { func = CreateValueTypeFactory(type); } - _cache[type] = func; + else + { + throw new InvalidOperationException($"Failed to gets type instance create func for type: {type.FullName}."); + } + + _cache[type] = func!; } return func(); } @@ -56,7 +61,7 @@ private static Func CreateReferenceTypeFactory(ConstructorInfo ctor) var dm = new DynamicMethod(string.Empty, typeof(object), EmptyTypes); var il = dm.GetILGenerator(); il.Emit(OpCodes.Newobj, ctor); - if (ctor.DeclaringType.IsValueType) + if (ctor.DeclaringType!.IsValueType) { il.Emit(OpCodes.Box, ctor.DeclaringType); } diff --git a/src/Docfx.YamlSerialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs b/src/Docfx.YamlSerialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs index 8037ffaac46..29dfdfab69a 100644 --- a/src/Docfx.YamlSerialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs +++ b/src/Docfx.YamlSerialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs @@ -22,18 +22,16 @@ namespace Docfx.YamlSerialization.ObjectGraphTraversalStrategies; public class FullObjectGraphTraversalStrategy : IObjectGraphTraversalStrategy { private static MethodInfo TraverseGenericDictionaryHelperMethod { get; } = - typeof(FullObjectGraphTraversalStrategy).GetMethod(nameof(TraverseGenericDictionaryHelper)); + typeof(FullObjectGraphTraversalStrategy).GetMethod(nameof(TraverseGenericDictionaryHelper))!; protected YamlSerializer Serializer { get; } private readonly int _maxRecursion; private readonly ITypeInspector _typeDescriptor; private readonly ITypeResolver _typeResolver; private readonly INamingConvention _namingConvention; - private readonly Dictionary, Action> _behaviorCache = - new(); - private readonly Dictionary, Action> _traverseGenericDictionaryCache = - new(); + private readonly Dictionary, Action> _behaviorCache = []; + private readonly Dictionary, Action> _traverseGenericDictionaryCache = []; - public FullObjectGraphTraversalStrategy(YamlSerializer serializer, ITypeInspector typeDescriptor, ITypeResolver typeResolver, int maxRecursion, INamingConvention namingConvention) + public FullObjectGraphTraversalStrategy(YamlSerializer serializer, ITypeInspector typeDescriptor, ITypeResolver typeResolver, int maxRecursion, INamingConvention? namingConvention) { if (maxRecursion <= 0) { @@ -47,7 +45,7 @@ public FullObjectGraphTraversalStrategy(YamlSerializer serializer, ITypeInspecto _typeDescriptor = typeDescriptor; _typeResolver = typeResolver; _maxRecursion = maxRecursion; - _namingConvention = namingConvention; + _namingConvention = namingConvention ?? NullNamingConvention.Instance; } void IObjectGraphTraversalStrategy.Traverse(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context) @@ -141,7 +139,7 @@ protected virtual void TraverseObject(IObjectDescriptor value, IObject } _behaviorCache[key] = action; } - action(value, visitor, currentDepth, context); + action(value, visitor, currentDepth, context!); } protected virtual void TraverseDictionary(IObjectDescriptor dictionary, object visitor, int currentDepth, object context) @@ -150,7 +148,7 @@ protected virtual void TraverseDictionary(IObjectDescriptor dictionary var c = (TContext)context; v.VisitMappingStart(dictionary, typeof(object), typeof(object), c); - foreach (DictionaryEntry entry in (IDictionary)dictionary.Value) + foreach (DictionaryEntry entry in (IDictionary)dictionary.NonNullValue()) { var key = GetObjectDescriptor(entry.Key, typeof(object)); var value = GetObjectDescriptor(entry.Value, typeof(object)); @@ -180,12 +178,12 @@ private void TraverseGenericDictionary(IObjectDescriptor dictionary, T action = GetTraverseGenericDictionaryHelper(entryTypes[0], entryTypes[1], typeof(TContext)); _traverseGenericDictionaryCache[key] = action; } - action(this, dictionary.Value, v, currentDepth, _namingConvention ?? NullNamingConvention.Instance, c); + action(this, dictionary.Value, v, currentDepth, _namingConvention, c); v.VisitMappingEnd(dictionary, c); } - private static Action GetTraverseGenericDictionaryHelper(Type tkey, Type tvalue, Type tcontext) + private static Action GetTraverseGenericDictionaryHelper(Type tkey, Type tvalue, Type tcontext) { var dm = new DynamicMethod(string.Empty, typeof(void), [typeof(FullObjectGraphTraversalStrategy), typeof(object), typeof(IObjectGraphVisitor), typeof(int), typeof(INamingConvention), typeof(IObjectGraphVisitorContext)]); var il = dm.GetILGenerator(); @@ -198,7 +196,7 @@ private static Action)dm.CreateDelegate(typeof(Action)); + return (Action)dm.CreateDelegate(typeof(Action)); } [EditorBrowsable(EditorBrowsableState.Never)] @@ -212,10 +210,10 @@ public static void TraverseGenericDictionaryHelper( { var v = (IObjectGraphVisitor)visitor; var c = (TContext)context; - var isDynamic = dictionary.GetType().FullName.Equals("System.Dynamic.ExpandoObject"); + var isDynamic = dictionary.GetType().FullName!.Equals("System.Dynamic.ExpandoObject"); foreach (var entry in dictionary) { - var keyString = isDynamic ? namingConvention.Apply(entry.Key.ToString()) : entry.Key.ToString(); + var keyString = isDynamic ? namingConvention.Apply(entry.Key!.ToString()!) : entry.Key!.ToString(); var key = self.GetObjectDescriptor(keyString, typeof(TKey)); var value = self.GetObjectDescriptor(entry.Value, typeof(TValue)); @@ -238,7 +236,7 @@ private void TraverseList(IObjectDescriptor value, IObjectGraphVisitor v.VisitSequenceStart(value, itemType, c); - foreach (var item in (IEnumerable)value.Value) + foreach (var item in (IEnumerable)value.NonNullValue()) { Traverse(GetObjectDescriptor(item, itemType), v, currentDepth, c); } @@ -252,9 +250,10 @@ protected virtual void TraverseProperties(IObjectDescriptor value, IOb var c = (TContext)context; v.VisitMappingStart(value, typeof(string), typeof(object), c); + var source = value.NonNullValue(); foreach (var propertyDescriptor in _typeDescriptor.GetProperties(value.Type, value.Value)) { - var propertyValue = propertyDescriptor.Read(value.Value); + var propertyValue = propertyDescriptor.Read(source); if (v.EnterMapping(propertyDescriptor, propertyValue, c)) { @@ -266,7 +265,7 @@ protected virtual void TraverseProperties(IObjectDescriptor value, IOb v.VisitMappingEnd(value, c); } - private IObjectDescriptor GetObjectDescriptor(object value, Type staticType) + private IObjectDescriptor GetObjectDescriptor(object? value, Type staticType) { return new BetterObjectDescriptor(value, _typeResolver.Resolve(staticType, value), staticType); } diff --git a/src/Docfx.YamlSerialization/ObjectGraphVisitors/ExclusiveObjectGraphVisitor.cs b/src/Docfx.YamlSerialization/ObjectGraphVisitors/ExclusiveObjectGraphVisitor.cs index d4c1afaec7e..0afe1efc7ee 100644 --- a/src/Docfx.YamlSerialization/ObjectGraphVisitors/ExclusiveObjectGraphVisitor.cs +++ b/src/Docfx.YamlSerialization/ObjectGraphVisitors/ExclusiveObjectGraphVisitor.cs @@ -18,7 +18,7 @@ public ExclusiveObjectGraphVisitor(IObjectGraphVisitor nextVisitor) { } - private static object GetDefault(Type type) + private static object? GetDefault(Type type) { return type.IsValueType ? Activator.CreateInstance(type) : null; } @@ -26,7 +26,7 @@ private static object GetDefault(Type type) public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) { var defaultValueAttribute = key.GetCustomAttribute(); - object defaultValue = defaultValueAttribute != null + object? defaultValue = defaultValueAttribute != null ? defaultValueAttribute.Value : GetDefault(key.Type); diff --git a/src/Docfx.YamlSerialization/TypeInspectors/EmitTypeInspector.cs b/src/Docfx.YamlSerialization/TypeInspectors/EmitTypeInspector.cs index e153787418e..bd893e48aed 100644 --- a/src/Docfx.YamlSerialization/TypeInspectors/EmitTypeInspector.cs +++ b/src/Docfx.YamlSerialization/TypeInspectors/EmitTypeInspector.cs @@ -22,7 +22,7 @@ public EmitTypeInspector(ITypeResolver resolver) _resolver = resolver; } - public override IEnumerable GetProperties(Type type, object container) + public override IEnumerable GetProperties(Type type, object? container) { var item = _cache.GetOrAdd(type, CachingItem.Create); if (item.Error != null) @@ -45,7 +45,7 @@ private IEnumerable GetPropertyDescriptors(CachingItem item return from p in item.Properties select new EmitPropertyDescriptor(p, _resolver); } - public override IPropertyDescriptor GetProperty(Type type, object container, string name) + public override IPropertyDescriptor? GetProperty(Type type, object? container, string name) { var item = _cache.GetOrAdd(type, CachingItem.Create); if (item.Error != null) @@ -56,6 +56,7 @@ public override IPropertyDescriptor GetProperty(Type type, object container, str { return null; } + return (from ep in item.ExtensibleProperties where name.StartsWith(ep.Prefix, StringComparison.Ordinal) select new ExtensiblePropertyDescriptor(ep, name, _resolver)).FirstOrDefault(); @@ -65,11 +66,11 @@ private sealed class CachingItem { private CachingItem() { } - public Exception Error { get; private set; } + public Exception? Error { get; private set; } - public List Properties { get; } = new(); + public List Properties { get; } = []; - public List ExtensibleProperties { get; } = new(); + public List ExtensibleProperties { get; } = []; public static CachingItem Create(Type type) { @@ -103,7 +104,7 @@ public static CachingItem Create(Type type) } else { - Type valueType = GetGenericValueType(propertyType); + Type? valueType = GetGenericValueType(propertyType); if (valueType == null) { @@ -130,7 +131,7 @@ public static CachingItem Create(Type type) private static Func CreateReader(MethodInfo getMethod) { - var hostType = getMethod.DeclaringType; + var hostType = getMethod.DeclaringType!; var propertyType = getMethod.ReturnType; var dm = new DynamicMethod(string.Empty, typeof(object), [typeof(object)]); var il = dm.GetILGenerator(); @@ -153,9 +154,9 @@ private static Func CreateReader(MethodInfo getMethod) return (Func)dm.CreateDelegate(typeof(Func)); } - private static Action CreateWriter(MethodInfo setMethod) + private static Action CreateWriter(MethodInfo setMethod) { - var hostType = setMethod.DeclaringType; + var hostType = setMethod.DeclaringType!; var propertyType = setMethod.GetParameters()[0].ParameterType; var dm = new DynamicMethod(string.Empty, typeof(void), [typeof(object), typeof(object)]); var il = dm.GetILGenerator(); @@ -173,12 +174,12 @@ private static Action CreateWriter(MethodInfo setMethod) il.Emit(OpCodes.Unbox_Any, propertyType); il.Emit(isValueType ? OpCodes.Call : OpCodes.Callvirt, setMethod); il.Emit(OpCodes.Ret); - return (Action)dm.CreateDelegate(typeof(Action)); + return (Action)dm.CreateDelegate(typeof(Action)); } - private static Type GetGenericValueType(Type propertyType) + private static Type? GetGenericValueType(Type propertyType) { - Type valueType = null; + Type? valueType = null; if (propertyType.IsInterface) { valueType = GetGenericValueTypeCore(propertyType); @@ -189,7 +190,7 @@ where t.IsVisible return valueType; } - private static Type GetGenericValueTypeCore(Type type) + private static Type? GetGenericValueTypeCore(Type type) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>)) @@ -205,7 +206,7 @@ private static Type GetGenericValueTypeCore(Type type) private static Func> CreateDictionaryKeyReader(MethodInfo getMethod, Type valueType) { - var hostType = getMethod.DeclaringType; + var hostType = getMethod.DeclaringType!; var propertyType = getMethod.ReturnType; var dictType = typeof(IDictionary<,>).MakeGenericType(typeof(string), valueType); var dm = new DynamicMethod(string.Empty, typeof(ICollection), [typeof(object)]); @@ -241,7 +242,7 @@ private static Func> CreateDictionaryKeyReader(Metho il.MarkLabel(notNullLabel); il.Emit(OpCodes.Ldloc_0); } - il.Emit(OpCodes.Callvirt, dictType.GetMethod("get_Keys")); + il.Emit(OpCodes.Callvirt, dictType.GetMethod("get_Keys")!); il.Emit(OpCodes.Ret); return (Func>)dm.CreateDelegate(typeof(Func>)); @@ -249,7 +250,7 @@ private static Func> CreateDictionaryKeyReader(Metho private static Func CreateDictionaryReader(MethodInfo getMethod, Type valueType) { - var hostType = getMethod.DeclaringType; + var hostType = getMethod.DeclaringType!; var propertyType = getMethod.ReturnType; var dictType = typeof(IDictionary<,>).MakeGenericType(typeof(string), valueType); var dm = new DynamicMethod(string.Empty, typeof(object), [typeof(object), typeof(string)]); @@ -288,7 +289,7 @@ private static Func CreateDictionaryReader(MethodInfo ge } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, (byte)0); - il.Emit(OpCodes.Callvirt, dictType.GetMethod("TryGetValue")); + il.Emit(OpCodes.Callvirt, dictType.GetMethod("TryGetValue")!); il.Emit(OpCodes.Brfalse_S, nullLabel); il.Emit(OpCodes.Ldloc_0); if (valueType.IsValueType) @@ -303,9 +304,9 @@ private static Func CreateDictionaryReader(MethodInfo ge return (Func)dm.CreateDelegate(typeof(Func)); } - private static Action CreateDictionaryWriter(MethodInfo getMethod, Type valueType) + private static Action CreateDictionaryWriter(MethodInfo getMethod, Type valueType) { - var hostType = getMethod.DeclaringType; + var hostType = getMethod.DeclaringType!; var propertyType = getMethod.ReturnType; var dictType = typeof(IDictionary<,>).MakeGenericType(typeof(string), valueType); var dm = new DynamicMethod(string.Empty, typeof(void), [typeof(object), typeof(string), typeof(object)]); @@ -341,11 +342,11 @@ private static Action CreateDictionaryWriter(MethodInfo il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Unbox_Any, valueType); - il.Emit(OpCodes.Callvirt, dictType.GetMethod("set_Item")); + il.Emit(OpCodes.Callvirt, dictType.GetMethod("set_Item")!); il.MarkLabel(nullLabel); il.Emit(OpCodes.Ret); - return (Action)dm.CreateDelegate(typeof(Action)); + return (Action)dm.CreateDelegate(typeof(Action)); } } @@ -356,20 +357,20 @@ private sealed class EmitPropertyDescriptorSkeleton public EmitPropertyDescriptorSkeleton() { - _attributeFunc = t => Property.GetCustomAttribute(t); + _attributeFunc = t => Property!.GetCustomAttribute(t)!; } - internal PropertyInfo Property { get; set; } + internal required PropertyInfo Property { get; set; } - internal Func Reader { get; set; } + internal required Func Reader { get; set; } - internal Action Writer { get; set; } + internal required Action? Writer { get; set; } public bool CanWrite { get; set; } - public string Name { get; set; } + public required string Name { get; set; } - public Type Type { get; set; } + public required Type Type { get; set; } public Attribute GetCustomAttribute(Type type) { @@ -398,7 +399,7 @@ public EmitPropertyDescriptor(EmitPropertyDescriptorSkeleton skeleton, ITypeReso public Type Type => _skeleton.Type; - public Type TypeOverride { get; set; } + public Type? TypeOverride { get; set; } public T GetCustomAttribute() where T : Attribute => (T)_skeleton.GetCustomAttribute(typeof(T)); @@ -408,23 +409,24 @@ public IObjectDescriptor Read(object target) return new BetterObjectDescriptor(value, TypeOverride ?? _typeResolver.Resolve(Type, value), Type, ScalarStyle); } - public void Write(object target, object value) + public void Write(object target, object? value) { - _skeleton.Writer(target, value); + if (_skeleton.CanWrite && _skeleton.Writer != null) + _skeleton.Writer(target, value); } } private sealed class ExtensiblePropertyDescriptorSkeleton { - internal string Prefix { get; set; } + internal required string Prefix { get; set; } - internal Func Reader { get; set; } + internal required Func Reader { get; set; } - internal Action Writer { get; set; } + internal required Action Writer { get; set; } - internal Func> KeyReader { get; set; } + internal required Func> KeyReader { get; set; } - public Type Type { get; set; } + public required Type Type { get; set; } public ICollection GetAllKeys(object target) => KeyReader(target); } @@ -457,9 +459,9 @@ public ExtensiblePropertyDescriptor( public Type Type => _skeleton.Type; - public Type TypeOverride { get; set; } + public Type? TypeOverride { get; set; } - public T GetCustomAttribute() where T : Attribute => null; + public T? GetCustomAttribute() where T : Attribute => null; public IObjectDescriptor Read(object target) { @@ -471,7 +473,7 @@ public IObjectDescriptor Read(object target) return new BetterObjectDescriptor(value, TypeOverride ?? _typeResolver.Resolve(Type, value), Type, ScalarStyle); } - public void Write(object target, object value) + public void Write(object target, object? value) { if (Name == null || Name.Length <= _skeleton.Prefix.Length) { diff --git a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleNamingConventionTypeInspector.cs b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleNamingConventionTypeInspector.cs index 8f6a03f2c81..aeb619b4593 100644 --- a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleNamingConventionTypeInspector.cs +++ b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleNamingConventionTypeInspector.cs @@ -19,10 +19,10 @@ public ExtensibleNamingConventionTypeInspector(IExtensibleTypeInspector innerTyp this.namingConvention = namingConvention; } - public override IEnumerable GetProperties(Type type, object container) => + public override IEnumerable GetProperties(Type type, object? container) => from p in innerTypeDescriptor.GetProperties(type, container) select (IPropertyDescriptor)new PropertyDescriptor(p) { Name = namingConvention.Apply(p.Name) }; - public override IPropertyDescriptor GetProperty(Type type, object container, string name) => + public override IPropertyDescriptor? GetProperty(Type type, object? container, string name) => innerTypeDescriptor.GetProperty(type, container, name); } diff --git a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleReadableAndWritablePropertiesTypeInspector.cs b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleReadableAndWritablePropertiesTypeInspector.cs index 5ed13063d70..1407f50a52a 100644 --- a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleReadableAndWritablePropertiesTypeInspector.cs +++ b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleReadableAndWritablePropertiesTypeInspector.cs @@ -14,11 +14,11 @@ public ExtensibleReadableAndWritablePropertiesTypeInspector(IExtensibleTypeInspe _innerTypeDescriptor = innerTypeDescriptor; } - public override IEnumerable GetProperties(Type type, object container) => + public override IEnumerable GetProperties(Type type, object? container) => from p in _innerTypeDescriptor.GetProperties(type, container) where p.CanWrite select p; - public override IPropertyDescriptor GetProperty(Type type, object container, string name) => + public override IPropertyDescriptor? GetProperty(Type type, object? container, string name) => _innerTypeDescriptor.GetProperty(type, container, name); } diff --git a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleTypeInspectorSkeleton.cs b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleTypeInspectorSkeleton.cs index b31bf7a6977..235855130aa 100644 --- a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleTypeInspectorSkeleton.cs +++ b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleTypeInspectorSkeleton.cs @@ -9,9 +9,9 @@ namespace Docfx.YamlSerialization.TypeInspectors; public abstract class ExtensibleTypeInspectorSkeleton : ITypeInspector, IExtensibleTypeInspector { - public abstract IEnumerable GetProperties(Type type, object container); + public abstract IEnumerable GetProperties(Type type, object? container); - public IPropertyDescriptor GetProperty(Type type, object container, string name, bool ignoreUnmatched) + public IPropertyDescriptor GetProperty(Type type, object? container, string name, bool ignoreUnmatched) { var candidates = from p in GetProperties(type, container) @@ -29,7 +29,7 @@ from p in GetProperties(type, container) if (ignoreUnmatched) { - return null; + return null!; } throw new InvalidOperationException( @@ -60,5 +60,5 @@ from p in GetProperties(type, container) return property; } - public virtual IPropertyDescriptor GetProperty(Type type, object container, string name) => null; + public virtual IPropertyDescriptor? GetProperty(Type type, object? container, string name) => null; } diff --git a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleYamlAttributesTypeInspector.cs b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleYamlAttributesTypeInspector.cs index 9897f36df56..21878ccdaa2 100644 --- a/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleYamlAttributesTypeInspector.cs +++ b/src/Docfx.YamlSerialization/TypeInspectors/ExtensibleYamlAttributesTypeInspector.cs @@ -17,7 +17,7 @@ public ExtensibleYamlAttributesTypeInspector(IExtensibleTypeInspector innerTypeD this.innerTypeDescriptor = innerTypeDescriptor; } - public override IEnumerable GetProperties(Type type, object container) + public override IEnumerable GetProperties(Type type, object? container) { return innerTypeDescriptor.GetProperties(type, container) .Where(p => p.GetCustomAttribute() == null) @@ -46,6 +46,6 @@ public override IEnumerable GetProperties(Type type, object .OrderBy(p => p.Order); } - public override IPropertyDescriptor GetProperty(Type type, object container, string name) => + public override IPropertyDescriptor? GetProperty(Type type, object? container, string name) => innerTypeDescriptor.GetProperty(type, container, name); } diff --git a/src/Docfx.YamlSerialization/TypeInspectors/IExtensibleTypeInspector.cs b/src/Docfx.YamlSerialization/TypeInspectors/IExtensibleTypeInspector.cs index 9ce4a40898b..9802ec5deab 100644 --- a/src/Docfx.YamlSerialization/TypeInspectors/IExtensibleTypeInspector.cs +++ b/src/Docfx.YamlSerialization/TypeInspectors/IExtensibleTypeInspector.cs @@ -7,5 +7,5 @@ namespace Docfx.YamlSerialization.TypeInspectors; public interface IExtensibleTypeInspector : ITypeInspector { - IPropertyDescriptor GetProperty(Type type, object container, string name); + IPropertyDescriptor? GetProperty(Type type, object? container, string name); } diff --git a/src/Docfx.YamlSerialization/YamlDeserializer.cs b/src/Docfx.YamlSerialization/YamlDeserializer.cs index fb8f374d27f..221e8b70d56 100644 --- a/src/Docfx.YamlSerialization/YamlDeserializer.cs +++ b/src/Docfx.YamlSerialization/YamlDeserializer.cs @@ -45,22 +45,22 @@ public sealed class YamlDeserializer private sealed class TypeDescriptorProxy : ITypeInspector { - public ITypeInspector TypeDescriptor; + public ITypeInspector TypeDescriptor = default!; - public IEnumerable GetProperties(Type type, object container) + public IEnumerable GetProperties(Type type, object? container) { return TypeDescriptor.GetProperties(type, container); } - public IPropertyDescriptor GetProperty(Type type, object container, string name, bool ignoreUnmatched) + public IPropertyDescriptor GetProperty(Type type, object? container, string name, bool ignoreUnmatched) { return TypeDescriptor.GetProperty(type, container, name, ignoreUnmatched); } } public YamlDeserializer( - IObjectFactory objectFactory = null, - INamingConvention namingConvention = null, + IObjectFactory? objectFactory = null, + INamingConvention? namingConvention = null, bool ignoreUnmatched = false, bool ignoreNotFoundAnchor = true) { @@ -85,8 +85,8 @@ public YamlDeserializer( _converters.Add(yamlTypeConverter); } - NodeDeserializers = new List - { + NodeDeserializers = + [ new TypeConverterNodeDeserializer(_converters), new NullNodeDeserializer(), new ScalarNodeDeserializer(attemptUnknownTypeDeserialization: false, _reflectionTypeConverter, YamlFormatter.Default, NullNamingConvention.Instance), @@ -97,14 +97,14 @@ public YamlDeserializer( new CollectionNodeDeserializer(objectFactory, NullNamingConvention.Instance), new EnumerableNodeDeserializer(), new ExtensibleObjectNodeDeserializer(objectFactory, _typeDescriptor, ignoreUnmatched) - }; + ]; _tagMappings = new Dictionary(PredefinedTagMappings); - TypeResolvers = new List - { + TypeResolvers = + [ new TagNodeTypeResolver(_tagMappings), new DefaultContainersNodeTypeResolver(), new ScalarYamlNodeTypeResolver() - }; + ]; NodeValueDeserializer nodeValueDeserializer = new(NodeDeserializers, TypeResolvers, _reflectionTypeConverter, NullNamingConvention.Instance); if (ignoreNotFoundAnchor) @@ -127,27 +127,27 @@ public void RegisterTypeConverter(IYamlTypeConverter typeConverter) _converters.Add(typeConverter); } - public T Deserialize(TextReader input, IValueDeserializer deserializer = null) + public T? Deserialize(TextReader input, IValueDeserializer? deserializer = null) { - return (T)Deserialize(input, typeof(T), deserializer); + return (T?)Deserialize(input, typeof(T), deserializer); } - public object Deserialize(TextReader input, IValueDeserializer deserializer = null) + public object? Deserialize(TextReader input, IValueDeserializer? deserializer = null) { return Deserialize(input, typeof(object), deserializer); } - public object Deserialize(TextReader input, Type type, IValueDeserializer deserializer = null) + public object? Deserialize(TextReader input, Type type, IValueDeserializer? deserializer = null) { return Deserialize(new Parser(input), type, deserializer); } - public T Deserialize(IParser reader, IValueDeserializer deserializer = null) + public T? Deserialize(IParser reader, IValueDeserializer? deserializer = null) { - return (T)Deserialize(reader, typeof(T), deserializer); + return (T?)Deserialize(reader, typeof(T), deserializer); } - public object Deserialize(IParser reader, IValueDeserializer deserializer = null) + public object? Deserialize(IParser reader, IValueDeserializer? deserializer = null) { return Deserialize(reader, typeof(object), deserializer); } @@ -158,7 +158,7 @@ public object Deserialize(IParser reader, IValueDeserializer deserializer = null /// The where to deserialize the object. /// The static type of the object to deserialize. /// Returns the deserialized object. - public object Deserialize(IParser parser, Type type, IValueDeserializer deserializer = null) + public object? Deserialize(IParser parser, Type type, IValueDeserializer? deserializer = null) { ArgumentNullException.ThrowIfNull(parser); ArgumentNullException.ThrowIfNull(type); @@ -167,7 +167,7 @@ public object Deserialize(IParser parser, Type type, IValueDeserializer deserial var hasDocumentStart = parser.TryConsume(out _); deserializer ??= _valueDeserializer; - object result = null; + object? result = null; if (!parser.Accept(out _) && !parser.Accept(out _)) { using var state = new SerializerState(); @@ -205,7 +205,7 @@ public void OnDeserialization() { foreach (var promise in Values) { - if (!promise.HasValue) + if (!promise.HasValue && promise.Alias != null) { // If promise is not resolved, reset to it's alias value promise.Value = "*" + promise.Alias.Value; @@ -216,26 +216,26 @@ public void OnDeserialization() private sealed class ValuePromise : IValuePromise { - public event Action ValueAvailable; + public event Action? ValueAvailable; public bool HasValue { get; private set; } - private object value; + private object? value; - public readonly AnchorAlias Alias; + public readonly AnchorAlias? Alias; public ValuePromise(AnchorAlias alias) { Alias = alias; } - public ValuePromise(object value) + public ValuePromise(object? value) { HasValue = true; this.value = value; } - public object Value + public object? Value { get { @@ -259,13 +259,13 @@ public object Value } } - public object DeserializeValue(IParser reader, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer) + public object? DeserializeValue(IParser reader, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer) { - object value; + object? value; if (reader.TryConsume(out var alias)) { var aliasState = state.Get(); - if (!aliasState.TryGetValue(alias.Value, out ValuePromise valuePromise)) + if (!aliasState.TryGetValue(alias.Value, out var valuePromise)) { valuePromise = new ValuePromise(alias); aliasState.Add(alias.Value, valuePromise); @@ -287,7 +287,7 @@ public object DeserializeValue(IParser reader, Type expectedType, SerializerStat { var aliasState = state.Get(); - if (!aliasState.TryGetValue(anchor.Value, out ValuePromise valuePromise)) + if (!aliasState.TryGetValue(anchor.Value, out var valuePromise)) { aliasState.Add(anchor.Value, new ValuePromise(value)); } diff --git a/src/Docfx.YamlSerialization/YamlSerializer.cs b/src/Docfx.YamlSerialization/YamlSerializer.cs index 69e9a64582b..4c2c6170481 100644 --- a/src/Docfx.YamlSerialization/YamlSerializer.cs +++ b/src/Docfx.YamlSerialization/YamlSerializer.cs @@ -24,7 +24,7 @@ public class YamlSerializer private readonly INamingConvention _namingConvention; private readonly ITypeResolver _typeResolver; - public YamlSerializer(SerializationOptions options = SerializationOptions.None, INamingConvention namingConvention = null) + public YamlSerializer(SerializationOptions options = SerializationOptions.None, INamingConvention? namingConvention = null) { _options = options; _namingConvention = namingConvention ?? NullNamingConvention.Instance; @@ -76,7 +76,7 @@ private IObjectGraphVisitor CreateEmittingVisitor(IEmitter emitter, IO { IObjectGraphVisitor emittingVisitor = new EmittingObjectGraphVisitor(eventEmitter); - void nestedObjectSerializer(object v, Type t = null) => SerializeValue(emitter, v, t); + void nestedObjectSerializer(object? v, Type? t = null) => SerializeValue(emitter, v, t); emittingVisitor = new CustomSerializationObjectGraphVisitor(emittingVisitor, Converters, nestedObjectSerializer); @@ -96,7 +96,7 @@ private IObjectGraphVisitor CreateEmittingVisitor(IEmitter emitter, IO return emittingVisitor; } - public void SerializeValue(IEmitter emitter, object value, Type type) + public void SerializeValue(IEmitter emitter, object? value, Type? type) { var graph = type != null ? new BetterObjectDescriptor(value, type, type) diff --git a/src/docfx/Models/BuildCommand.cs b/src/docfx/Models/BuildCommand.cs index 4dcc87189a3..4ac804afbc7 100644 --- a/src/docfx/Models/BuildCommand.cs +++ b/src/docfx/Models/BuildCommand.cs @@ -56,7 +56,7 @@ internal static void MergeOptionsToConfig(BuildCommandOptions options, BuildJson { config.Xref = new ListWithStringFallback( - (config.Xref ?? new ListWithStringFallback()) + (config.Xref ?? []) .Concat(options.XRefMaps) .Where(x => !string.IsNullOrWhiteSpace(x)) .Distinct()); @@ -100,7 +100,7 @@ void SetGlobalMetadataFromCommandLineArgs() { if (options.Metadata != null) { - config.GlobalMetadata ??= new(); + config.GlobalMetadata ??= []; foreach (var metadata in options.Metadata) { var (key, value) = ParseMetadata(metadata); diff --git a/src/docfx/Models/MetadataCommand.cs b/src/docfx/Models/MetadataCommand.cs index 516990ca0be..d41552f48e6 100644 --- a/src/docfx/Models/MetadataCommand.cs +++ b/src/docfx/Models/MetadataCommand.cs @@ -27,6 +27,7 @@ private static void MergeOptionsToConfig(MetadataCommandOptions options, DocfxCo item.ShouldSkipMarkup |= options.ShouldSkipMarkup; item.DisableGitFeatures |= options.DisableGitFeatures; item.DisableDefaultFilter |= options.DisableDefaultFilter; + item.NoRestore |= options.NoRestore; item.CategoryLayout = options.CategoryLayout ?? item.CategoryLayout; item.NamespaceLayout = options.NamespaceLayout ?? item.NamespaceLayout; item.MemberLayout = options.MemberLayout ?? item.MemberLayout; diff --git a/src/docfx/Models/MetadataCommandOptions.cs b/src/docfx/Models/MetadataCommandOptions.cs index 2b4ef828c68..9b4ad66ef71 100644 --- a/src/docfx/Models/MetadataCommandOptions.cs +++ b/src/docfx/Models/MetadataCommandOptions.cs @@ -45,6 +45,10 @@ internal class MetadataCommandOptions : LogOptions [CommandOption("--disableDefaultFilter")] public bool DisableDefaultFilter { get; set; } + [Description("Do not run `dotnet restore` before building the projects")] + [CommandOption("--noRestore")] + public bool NoRestore { get; set; } + [Description("Determines the category layout in table of contents.")] [CommandOption("--categoryLayout")] public CategoryLayout? CategoryLayout { get; set; } diff --git a/src/docfx/Models/TemplateCommand.cs b/src/docfx/Models/TemplateCommand.cs index 2961c3d8857..b30ce1d4566 100644 --- a/src/docfx/Models/TemplateCommand.cs +++ b/src/docfx/Models/TemplateCommand.cs @@ -53,7 +53,7 @@ public override int Execute(CommandContext context, Options options) foreach (var template in templates) { - var manager = new TemplateManager(new List { template }, null, null); + var manager = new TemplateManager([template], null, null); if (manager.TryExportTemplateFiles(Path.Combine(outputFolder, template))) { Logger.LogInfo($"{template} is exported to {outputFolder}"); diff --git a/src/docfx/docfx.csproj b/src/docfx/docfx.csproj index 0ea31d91aab..599cc40dc5a 100644 --- a/src/docfx/docfx.csproj +++ b/src/docfx/docfx.csproj @@ -11,11 +11,9 @@ - @@ -27,16 +25,11 @@ - - diff --git a/templates/modern/partials/class.header.tmpl.partial b/templates/modern/partials/class.header.tmpl.partial index 64168b21533..7f442c64c5f 100644 --- a/templates/modern/partials/class.header.tmpl.partial +++ b/templates/modern/partials/class.header.tmpl.partial @@ -139,7 +139,8 @@
{{#children}}
{{syntax.content.0.value}}
-
{{{summary}}}
+ {{#remarks}}
{{{summary}}}{{{remarks}}}
{{/remarks}} + {{^remarks}}
{{{summary}}}
{{/remarks}} {{/children}}
{{/children}} diff --git a/templates/modern/src/docfx.scss b/templates/modern/src/docfx.scss index 67c36fb035f..a4a6d6d90ac 100644 --- a/templates/modern/src/docfx.scss +++ b/templates/modern/src/docfx.scss @@ -3,13 +3,12 @@ * The .NET Foundation licenses this file to you under the MIT license. */ -$enable-important-utilities: false; -$container-max-widths: ( - xxl: 1768px -) !default; - @use "mixins"; -@use "bootstrap/scss/bootstrap"; +@use "bootstrap/scss/bootstrap" with ( + $container-max-widths: ( + xxl: 1768px + ) +); @use "highlight"; @use "layout"; @use "nav"; diff --git a/templates/package-lock.json b/templates/package-lock.json index 2dd1fcb7bfb..6637a0443d2 100644 --- a/templates/package-lock.json +++ b/templates/package-lock.json @@ -27,21 +27,21 @@ "lunr": "2.3.9", "lunr-languages": "^1.14.0", "mathjax": "^3.2.2", - "mermaid": "^11.4.0", + "mermaid": "^11.4.1", "tsx": "^4.19.2" }, "devDependencies": { "@types/lunr": "^2.3.7", - "@typescript-eslint/eslint-plugin": "^8.12.2", - "@typescript-eslint/parser": "^8.12.2", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", "browser-sync": "^3.0.3", "esbuild": "~0.24.0", "esbuild-sass-plugin": "~3.3.1", "eslint": "^8.57.1", "eslint-config-standard": "^17.1.0", - "stylelint": "^16.10.0", - "stylelint-config-standard-scss": "^13.1.0", - "typescript": "^5.6.3", + "stylelint": "^16.11.0", + "stylelint-config-standard-scss": "^14.0.0", + "typescript": "^5.7.2", "yargs": "^17.7.2" } }, @@ -220,9 +220,9 @@ "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==" }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.2.tgz", - "integrity": "sha512-6tC/MnlEvs5suR4Ahef4YlBccJDHZuxGsAlxXmybWjZ5jPxlzLSMlRZ9mVHSRvlD+CmtE7+hJ+UQbfXrws/rUQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", "dev": true, "funding": [ { @@ -234,17 +234,18 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": ">=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.2" + "@csstools/css-tokenizer": "^3.0.3" } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.2.tgz", - "integrity": "sha512-IuTRcD53WHsXPCZ6W7ubfGqReTJ9Ra0yRRFmXYP/Re8hFYYfoIYIK4080X5luslVLWimhIeFq0hj09urVMQzTw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", "dev": true, "funding": [ { @@ -256,37 +257,15 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@csstools/media-query-list-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz", - "integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.1", - "@csstools/css-tokenizer": "^3.0.1" - } - }, - "node_modules/@csstools/selector-specificity": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz", - "integrity": "sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", "dev": true, "funding": [ { @@ -298,11 +277,13 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": ">=18" }, "peerDependencies": { - "postcss-selector-parser": "^6.1.0" + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" } }, "node_modules/@default/anchor-js": { @@ -891,14 +872,6 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", - "dependencies": { - "@types/trusted-types": "*" - } - }, "node_modules/@types/geojson": { "version": "7946.0.14", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", @@ -932,16 +905,16 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", - "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/type-utils": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -956,24 +929,20 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", - "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "debug": "^4.3.4" }, "engines": { @@ -984,22 +953,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1010,13 +975,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", - "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/utils": "8.12.2", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1027,16 +992,15 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1047,13 +1011,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1068,22 +1032,20 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", - "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2" + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1093,17 +1055,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.18.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1113,6 +1076,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -1872,12 +1847,13 @@ } }, "node_modules/css-tree": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.0.tgz", - "integrity": "sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.1.tgz", + "integrity": "sha512-8Fxxv+tGhORlshCdCwnNJytvlvq46sOLSYEx2ZIGurahWvMucSRnyjPA3AmrMq4VPRYbHVpWj5VkiVasrM2H4Q==", "dev": true, + "license": "MIT", "dependencies": { - "mdn-data": "2.10.0", + "mdn-data": "2.12.1", "source-map-js": "^1.0.1" }, "engines": { @@ -2546,9 +2522,13 @@ } }, "node_modules/dompurify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", - "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.1.tgz", + "integrity": "sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/easy-extender": { "version": "2.3.4", @@ -4720,10 +4700,11 @@ } }, "node_modules/mdn-data": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.10.0.tgz", - "integrity": "sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw==", - "dev": true + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.1.tgz", + "integrity": "sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/meow": { "version": "13.2.0", @@ -4747,15 +4728,15 @@ } }, "node_modules/mermaid": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.0.tgz", - "integrity": "sha512-mxCfEYvADJqOiHfGpJXLs4/fAjHz448rH0pfY5fAoxiz70rQiDSzUUy4dNET2T08i46IVpjohPd6WWbzmRHiPA==", + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.1.tgz", + "integrity": "sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==", + "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.0.1", "@iconify/utils": "^2.1.32", "@mermaid-js/parser": "^0.3.0", "@types/d3": "^7.4.3", - "@types/dompurify": "^3.0.5", "cytoscape": "^3.29.2", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", @@ -4763,7 +4744,7 @@ "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.11", "dayjs": "^1.11.10", - "dompurify": "^3.0.11 <3.1.7", + "dompurify": "^3.2.1", "katex": "^0.16.9", "khroma": "^2.1.0", "lodash-es": "^4.17.21", @@ -5261,9 +5242,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -5279,9 +5260,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -6427,9 +6409,9 @@ } }, "node_modules/stylelint": { - "version": "16.10.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.10.0.tgz", - "integrity": "sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ==", + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.11.0.tgz", + "integrity": "sha512-zrl4IrKmjJQ+h9FoMp69UMCq5SxeHk0URhxUBj4d3ISzo/DplOFBJZc7t7Dr6otB+1bfbbKNLOmCDpzKSlW+Nw==", "dev": true, "funding": [ { @@ -6441,17 +6423,18 @@ "url": "https://github.com/sponsors/stylelint" } ], + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.1", - "@csstools/css-tokenizer": "^3.0.1", - "@csstools/media-query-list-parser": "^3.0.1", - "@csstools/selector-specificity": "^4.0.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2", + "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", - "css-tree": "^3.0.0", + "css-tree": "^3.0.1", "debug": "^4.3.7", "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", @@ -6463,16 +6446,16 @@ "ignore": "^6.0.2", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.34.0", + "known-css-properties": "^0.35.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", - "picocolors": "^1.0.1", - "postcss": "^8.4.47", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", - "postcss-selector-parser": "^6.1.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -6559,20 +6542,21 @@ } }, "node_modules/stylelint-config-standard-scss": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-13.1.0.tgz", - "integrity": "sha512-Eo5w7/XvwGHWkeGLtdm2FZLOMYoZl1omP2/jgFCXyl2x5yNz7/8vv4Tj6slHvMSSUNTaGoam/GAZ0ZhukvalfA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-14.0.0.tgz", + "integrity": "sha512-6Pa26D9mHyi4LauJ83ls3ELqCglU6VfCXchovbEqQUiEkezvKdv6VgsIoMy58i00c854wVmOw0k8W5FTpuaVqg==", "dev": true, + "license": "MIT", "dependencies": { - "stylelint-config-recommended-scss": "^14.0.0", - "stylelint-config-standard": "^36.0.0" + "stylelint-config-recommended-scss": "^14.1.0", + "stylelint-config-standard": "^36.0.1" }, "engines": { "node": ">=18.12.0" }, "peerDependencies": { "postcss": "^8.3.3", - "stylelint": "^16.3.1" + "stylelint": "^16.11.0" }, "peerDependenciesMeta": { "postcss": { @@ -6602,11 +6586,28 @@ "stylelint": "^16.0.2" } }, - "node_modules/stylelint-scss/node_modules/mdn-data": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.11.1.tgz", - "integrity": "sha512-Hdx3wmyqPFrhd6YHVuSkUK2eIGAcxR0xlndcgZqjA68yMJTbfXrjJwbgsBOsNjI7LnBIVUQnmyMVSdi/ob0GpQ==", - "dev": true + "node_modules/stylelint/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", @@ -6648,6 +6649,27 @@ "node": ">= 4" } }, + "node_modules/stylelint/node_modules/known-css-properties": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", + "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/stylelint/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -6991,9 +7013,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/templates/package.json b/templates/package.json index 294817e7768..87021359ac8 100644 --- a/templates/package.json +++ b/templates/package.json @@ -36,21 +36,21 @@ "lunr": "2.3.9", "lunr-languages": "^1.14.0", "mathjax": "^3.2.2", - "mermaid": "^11.4.0", + "mermaid": "^11.4.1", "tsx": "^4.19.2" }, "devDependencies": { "@types/lunr": "^2.3.7", - "@typescript-eslint/eslint-plugin": "^8.12.2", - "@typescript-eslint/parser": "^8.12.2", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", "browser-sync": "^3.0.3", "esbuild": "~0.24.0", "esbuild-sass-plugin": "~3.3.1", "eslint": "^8.57.1", "eslint-config-standard": "^17.1.0", - "stylelint": "^16.10.0", - "stylelint-config-standard-scss": "^13.1.0", - "typescript": "^5.6.3", + "stylelint": "^16.11.0", + "stylelint-config-standard-scss": "^14.0.0", + "typescript": "^5.7.2", "yargs": "^17.7.2" } } diff --git a/test/Directory.Build.props b/test/Directory.Build.props index b4ab82100c6..58979e35535 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -12,7 +12,7 @@ false - + @@ -20,15 +20,11 @@ $(MSBuildThisFileDirectory)TestResults - $(VSTestLogger);trx%3BLogFileName=TestResults-$(MSBuildProjectName)-$(TargetFramework).trx - $(VSTestLogger);html%3BLogFileName=TestResults-$(MSBuildProjectName)-$(TargetFramework).html + $(VSTestLogger);trx%3BLogFileName=TestResults-$(MSBuildProjectName)-$(TargetFramework)-$(RUNNER_OS).trx + $(VSTestLogger);html%3BLogFileName=TestResults-$(MSBuildProjectName)-$(TargetFramework)-$(RUNNER_OS).html - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/test/Directory.Packages.props b/test/Directory.Packages.props new file mode 100644 index 00000000000..3fca3350206 --- /dev/null +++ b/test/Directory.Packages.props @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/test/Docfx.Build.Common.Tests/MarkdownReaderTest.cs b/test/Docfx.Build.Common.Tests/MarkdownReaderTest.cs index a8c47d11e89..5e5da0a699e 100644 --- a/test/Docfx.Build.Common.Tests/MarkdownReaderTest.cs +++ b/test/Docfx.Build.Common.Tests/MarkdownReaderTest.cs @@ -26,7 +26,7 @@ public void TestReadMarkdownAsOverwrite() var fileName = "ut_ReadMarkdownAsOverwrite.md"; var fullPath = Path.Combine(baseDir, fileName); File.WriteAllText(fullPath, content); - var host = new HostService(Enumerable.Empty()) + var host = new HostService([]) { MarkdownService = new MarkdigMarkdownService(new MarkdownServiceParameters { BasePath = string.Empty }), SourceFiles = ImmutableDictionary.Create() diff --git a/test/Docfx.Build.Common.Tests/ModelAttributeHandlerTest.cs b/test/Docfx.Build.Common.Tests/ModelAttributeHandlerTest.cs index 4db7ad6775f..79047dc6bb0 100644 --- a/test/Docfx.Build.Common.Tests/ModelAttributeHandlerTest.cs +++ b/test/Docfx.Build.Common.Tests/ModelAttributeHandlerTest.cs @@ -20,7 +20,7 @@ public void TestSimpleModelWithUniqueIdentityReferenceAttributeShouldSucceed() var model = new SimpleModel { Identity = "Identity1", - Identities = new List { "Identity2" } + Identities = ["Identity2"] }; var context = Handle(model); @@ -61,7 +61,7 @@ public void TestModelWithInvalidItemTypeShouldThrow() { var model = new InvalidModel2 { - Identities = new List { 0 } + Identities = [0] }; Assert.Throws( () => Handle(model) @@ -73,23 +73,23 @@ public void TestComplexModelWithUniqueIdentityReferenceAttributeShouldSucceed() { var model = new ComplexModel { - Identities = new List { "1", "2", "3" }, + Identities = ["1", "2", "3"], Identity = "0", Inner = new ComplexModel { - Identities = new List { "1.1", "1.2", "1.3" }, + Identities = ["1.1", "1.2", "1.3"], Identity = "0.0", OtherProperty = "innerothers", Inner = new ComplexModel { - Identities = new List { "1.1.1", "1.1.2" }, + Identities = ["1.1.1", "1.1.2"], Identity = "0.0.0", OtherProperty = "innersinner" } }, OtherProperty = "others", - InnerModels = new List - { + InnerModels = + [ new() { Identity = "2.1", @@ -100,7 +100,7 @@ public void TestComplexModelWithUniqueIdentityReferenceAttributeShouldSucceed() Identity = "2.2", CrefType = TestCrefType.Href } - } + ] }; var context = Handle(model); @@ -238,7 +238,7 @@ public void TesteModelWithIListMarkdownContentAttributeShouldSucceed() { var model = new MarkdownModelWithIList { - ListContent = new List { "*list*" }, + ListContent = ["*list*"], ArrayContent = ["@xref", "*content"] }; @@ -295,7 +295,7 @@ private static HandleModelAttributesContext GetDefaultContext() { return new HandleModelAttributesContext { - Host = new HostService(Enumerable.Empty()) + Host = new HostService([]) { MarkdownService = new MarkdigMarkdownService(new MarkdownServiceParameters { BasePath = string.Empty }), SourceFiles = new Dictionary diff --git a/test/Docfx.Build.OverwriteDocuments.Tests/OverwriteDocumentModelCreatorTest.cs b/test/Docfx.Build.OverwriteDocuments.Tests/OverwriteDocumentModelCreatorTest.cs index b4f82ef9148..01dbcbe25ee 100644 --- a/test/Docfx.Build.OverwriteDocuments.Tests/OverwriteDocumentModelCreatorTest.cs +++ b/test/Docfx.Build.OverwriteDocuments.Tests/OverwriteDocumentModelCreatorTest.cs @@ -58,7 +58,7 @@ public void ContentConvertTest() }); } - var contentsMetadata = new OverwriteDocumentModelCreator("test.yml.md").ConvertContents(new Dictionary(), contents); + var contentsMetadata = new OverwriteDocumentModelCreator("test.yml.md").ConvertContents([], contents); Assert.Equal(3, contentsMetadata.Count); Assert.Equal("summary,return,function", ExtractDictionaryKeys(contentsMetadata)); Assert.Equal(2, ((Dictionary)contentsMetadata["return"]).Count); @@ -79,26 +79,27 @@ public void ContentConvertTest() public void DuplicateOPathInMarkdownSectionTest() { var testOPath = "function/parameters"; - var contents = new List(); - - contents.Add(new MarkdownPropertyModel - { - PropertyName = testOPath, - PropertyNameSource = Markdown.Parse($"## `{testOPath}`")[0], - PropertyValue = Markdown.Parse("test1").ToList() - }); - contents.Add(new MarkdownPropertyModel + var contents = new List { - PropertyName = testOPath, - PropertyNameSource = Markdown.Parse($"## `{testOPath}`")[0], - PropertyValue = Markdown.Parse("test2").ToList() - }); + new MarkdownPropertyModel + { + PropertyName = testOPath, + PropertyNameSource = Markdown.Parse($"## `{testOPath}`")[0], + PropertyValue = Markdown.Parse("test1").ToList() + }, + new MarkdownPropertyModel + { + PropertyName = testOPath, + PropertyNameSource = Markdown.Parse($"## `{testOPath}`")[0], + PropertyValue = Markdown.Parse("test2").ToList() + } + }; Dictionary contentsMetadata; Logger.RegisterListener(_listener); try { - contentsMetadata = new OverwriteDocumentModelCreator("test.yml.md").ConvertContents(new Dictionary(), contents); + contentsMetadata = new OverwriteDocumentModelCreator("test.yml.md").ConvertContents([], contents); } finally { @@ -188,7 +189,7 @@ public void InvalidOPathsTest1() }); } - var ex = Assert.Throws(() => new OverwriteDocumentModelCreator("test.yml.md").ConvertContents(new Dictionary(), contents)); + var ex = Assert.Throws(() => new OverwriteDocumentModelCreator("test.yml.md").ConvertContents([], contents)); Assert.Equal( "A(parameters) is not expected to be an array like \"A[c=d]/B\", however it is used as an array in line 0 with `parameters[id=\"para1\"]/...`", ex.Message); @@ -215,7 +216,7 @@ public void InvalidOPathsTest2() }); } - var ex = Assert.Throws(() => new OverwriteDocumentModelCreator("test.yml.md").ConvertContents(new Dictionary(), contents)); + var ex = Assert.Throws(() => new OverwriteDocumentModelCreator("test.yml.md").ConvertContents([], contents)); Assert.Equal( "A(parameters) is not expected to be an object like \"A/B\", however it is used as an object in line 0 with `parameters/...`", ex.Message); diff --git a/test/Docfx.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs b/test/Docfx.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs index 9eb31f8b71a..e2dcb241d03 100644 --- a/test/Docfx.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs +++ b/test/Docfx.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs @@ -438,7 +438,7 @@ public void SystemKeysListShouldBeComplete() var outputRawModelPath = GetRawModelFilePath("contacts.json"); Assert.True(File.Exists(outputRawModelPath)); - var model = JsonUtility.Deserialize>(outputRawModelPath); ; + var model = JsonUtility.Deserialize>(outputRawModelPath); var systemKeys = ToList(model[Constants.PropertyName.SystemKeys]); Assert.NotEmpty(systemKeys); foreach (var key in model.Keys.Where(key => key[0] != '_' && !userKeys.Contains(key))) diff --git a/test/Docfx.Build.RestApi.WithPlugins.Tests/SplitRestApiToOperationLevelTest.cs b/test/Docfx.Build.RestApi.WithPlugins.Tests/SplitRestApiToOperationLevelTest.cs index 4f9f8656300..db65cfef4c8 100644 --- a/test/Docfx.Build.RestApi.WithPlugins.Tests/SplitRestApiToOperationLevelTest.cs +++ b/test/Docfx.Build.RestApi.WithPlugins.Tests/SplitRestApiToOperationLevelTest.cs @@ -36,7 +36,7 @@ public SplitRestApiToOperationLevelTest() RawModelExportSettings = { Export = true }, TransformDocument = true, }; - _templateManager = new TemplateManager(new List { "template" }, null, "TestData/"); + _templateManager = new TemplateManager(["template"], null, "TestData/"); } [Fact] diff --git a/test/Docfx.Build.SchemaDriven.Tests/MarkdownFragmentsValidationTest.cs b/test/Docfx.Build.SchemaDriven.Tests/MarkdownFragmentsValidationTest.cs index a04406a268e..1c1497e016b 100644 --- a/test/Docfx.Build.SchemaDriven.Tests/MarkdownFragmentsValidationTest.cs +++ b/test/Docfx.Build.SchemaDriven.Tests/MarkdownFragmentsValidationTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Docfx.Build.Engine; using Docfx.Common; using Docfx.Plugins; diff --git a/test/Docfx.Build.SchemaDriven.Tests/MergeMarkdownFragmentsTest.cs b/test/Docfx.Build.SchemaDriven.Tests/MergeMarkdownFragmentsTest.cs index f82fa591e58..97158492044 100644 --- a/test/Docfx.Build.SchemaDriven.Tests/MergeMarkdownFragmentsTest.cs +++ b/test/Docfx.Build.SchemaDriven.Tests/MergeMarkdownFragmentsTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Docfx.Build.Engine; using Docfx.Common; using Docfx.Plugins; diff --git a/test/Docfx.Build.SchemaDriven.Tests/SchemaDrivenProcessorTest.cs b/test/Docfx.Build.SchemaDriven.Tests/SchemaDrivenProcessorTest.cs index 400694d1d06..0337e095193 100644 --- a/test/Docfx.Build.SchemaDriven.Tests/SchemaDrivenProcessorTest.cs +++ b/test/Docfx.Build.SchemaDriven.Tests/SchemaDrivenProcessorTest.cs @@ -3,7 +3,6 @@ using System.Collections.Immutable; using System.Composition; -using System.Text.RegularExpressions; using Docfx.Build.Engine; using Docfx.Common; diff --git a/test/Docfx.Build.SchemaDriven.Tests/SchemaFragmentsIteratorTest.cs b/test/Docfx.Build.SchemaDriven.Tests/SchemaFragmentsIteratorTest.cs index 35f256a0879..a0d6cbcb63b 100644 --- a/test/Docfx.Build.SchemaDriven.Tests/SchemaFragmentsIteratorTest.cs +++ b/test/Docfx.Build.SchemaDriven.Tests/SchemaFragmentsIteratorTest.cs @@ -24,7 +24,7 @@ public void TestSchemaFragmentsIterator() } // act - iterator.Traverse(yamlStream.Documents[0].RootNode, new Dictionary(), schema); + iterator.Traverse(yamlStream.Documents[0].RootNode, [], schema); // assert Assert.Single(counter.ExistingUids); diff --git a/test/Docfx.Build.Tests/ConceptualDocumentProcessorTest.cs b/test/Docfx.Build.Tests/ConceptualDocumentProcessorTest.cs index 4d4c7961e93..630ff1c7c5e 100644 --- a/test/Docfx.Build.Tests/ConceptualDocumentProcessorTest.cs +++ b/test/Docfx.Build.Tests/ConceptualDocumentProcessorTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; -using System.Reflection; using System.Web; using Docfx.Build.Engine; using Docfx.Common; @@ -44,7 +43,7 @@ public ConceptualDocumentProcessorTest() // Prepare conceptual template var templateCreator = new FileCreator(_templateFolder); var file = templateCreator.CreateFile("{{{conceptual}}}", "conceptual.html.tmpl", "default"); - _templateManager = new TemplateManager(new List { "default" }, null, _templateFolder); + _templateManager = new TemplateManager(["default"], null, _templateFolder); } public override void Dispose() diff --git a/test/Docfx.Build.Tests/DocumentBuilderTest.cs b/test/Docfx.Build.Tests/DocumentBuilderTest.cs index 67b4ae138f4..69ec1562538 100644 --- a/test/Docfx.Build.Tests/DocumentBuilderTest.cs +++ b/test/Docfx.Build.Tests/DocumentBuilderTest.cs @@ -48,19 +48,17 @@ public void TestBuild() CreateFile("conceptual.html.primary.tmpl", "{{{conceptual}}}", _templateFolder); var tocFile = CreateFile("toc.md", - new[] - { + [ "# [test1](test.md#bookmark)", "## [test2](test/test.md)", "## [GitHub](GitHub.md?shouldBeAbbreviated=true#test)", "# Api", "## [Console](@System.Console)", "## [ConsoleColor](xref:System.ConsoleColor)", - }, + ], _inputFolder); var conceptualFile = CreateFile("test.md", - new[] - { + [ "---", "uid: XRef1", "a: b", @@ -96,11 +94,10 @@ public void TestBuild() "Test href generator: [Git](Git.md?shouldBeAbbreviated=true#test)", "

", "test", - }, + ], _inputFolder); var conceptualFile2 = CreateFile("test/test.md", - new[] - { + [ "---", "uid: XRef2", "a: b", @@ -112,11 +109,10 @@ public void TestBuild() "Test link: [link text](../test.md)", "

", "test", - }, + ], _inputFolder); var conceptualFile3 = CreateFile("check-xrefmap.md", - new[] - { + [ "---", "uid: XRef1", "a: b", @@ -125,11 +121,10 @@ public void TestBuild() "---", "# Hello World", "Test xrefmap with duplicate uid in different files: XRef1 should be recorded with file check-xrefmap.md" - }, + ], _inputFolder); var conceptualFile4 = CreateFile("test/verify-xrefmap.md", - new[] - { + [ "---", "uid: XRef2", "a: b", @@ -138,7 +133,7 @@ public void TestBuild() "---", "# Hello World", "Test xrefmap with duplicate uid in different files: XRef2 should be recorded with file test/test.md" - }, + ], _inputFolder); FileCollection files = new(Directory.GetCurrentDirectory()); @@ -320,34 +315,32 @@ public void TestBuildConceptualWithTemplateShouldSucceed() ", _templateFolder); CreateFile("conceptual.html.tmpl", "{{.}}", _templateFolder); var conceptualFile = CreateFile("test.md", - new[] - { + [ "---", "uid: XRef1", "---", "# Hello World", "Test link: [link text](test/test.md)", "test", - }, + ], _inputFolder); var conceptualFile2 = CreateFile("test/test.md", - new[] - { + [ "---", "uid: XRef2", "---", "test", - }, + ], _inputFolder); - var tocFile = CreateFile("toc.md", new[] - { + var tocFile = CreateFile("toc.md", + [ "#[Test](test.md)" - }, + ], _inputFolder); - var tocFile2 = CreateFile("test/toc.md", new[] - { + var tocFile2 = CreateFile("test/toc.md", + [ "#[Test](test.md)" - }, + ], _inputFolder); FileCollection files = new(Directory.GetCurrentDirectory()); files.Add(DocumentType.Article, new[] { conceptualFile, conceptualFile2, tocFile, tocFile2 }); @@ -517,15 +510,13 @@ public void TestBuildWithInvalidPath() CreateFile("conceptual.html.primary.tmpl", "{{{conceptual}}}", _templateFolder); var tocFile = CreateFile("toc.md", - new[] - { + [ "# [test1](test.md)", "## [test2](test/test.md)", - }, + ], _inputFolder); var conceptualFile = CreateFile("test.md", - new[] - { + [ "# Hello World", "Test link: [link 1](test/test.md)", "Test link: [link 2](http://www.microsoft.com)", @@ -537,14 +528,13 @@ public void TestBuildWithInvalidPath() "Test link: [link 8](test/test.md#top)", "Test link: [link 9](a.md#top)", "Test link: [link 10](#top)", - }, + ], _inputFolder); var conceptualFile2 = CreateFile("test/test.md", - new[] - { + [ "# Hello World", "Test link: [link 1](../test.md)", - }, + ], _inputFolder); FileCollection files = new(Directory.GetCurrentDirectory()); @@ -630,19 +620,17 @@ public void TestBuildWithInvalidPathWithTokenAndMapping() CreateFile("conceptual.html.primary.tmpl", "{{{conceptual}}}", _templateFolder); var conceptualFile = CreateFile("a/a.md", - new[] - { + [ "[link a](invalid-a.md)", "[link b](../b/invalid-b.md)", "[!include[](../b/token.md)]", - }, + ], _inputFolder); var tokenFile = CreateFile("b/token.md", - new[] - { + [ "[link a](../a/invalid-a.md)", "[link b](invalid-b.md)", - }, + ], _inputFolder); FileCollection files = new(Directory.GetCurrentDirectory()); @@ -651,7 +639,7 @@ public void TestBuildWithInvalidPathWithTokenAndMapping() BuildDocument( files, - new Dictionary(), + [], templateFolder: _templateFolder); { @@ -672,7 +660,7 @@ public void TestBuildWithInvalidPathWithTokenAndMapping() private class FakeResponseHandler : DelegatingHandler { - private readonly Dictionary _fakeResponses = new(); + private readonly Dictionary _fakeResponses = []; protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { @@ -703,7 +691,7 @@ public void TestBuildWithMultipleVersion() BuildDocument( files, - new Dictionary(), + [], templateFolder: _templateFolder, versionDir: versionDir); @@ -740,10 +728,10 @@ private void BuildDocument( OutputBaseDir = Path.Combine(Directory.GetCurrentDirectory(), _outputFolder), ApplyTemplateSettings = applyTemplateSettings, Metadata = metadata?.ToImmutableDictionary(), - TemplateManager = new TemplateManager(new List { _templateFolder }, null, null), + TemplateManager = new TemplateManager([_templateFolder], null, null), TemplateDir = templateFolder, VersionDir = versionDir, - XRefMaps = ImmutableArray.Create("TestData/xrefmap.yml"), + XRefMaps = ["TestData/xrefmap.yml"], }; builder.Build(parameters); } diff --git a/test/Docfx.Build.Tests/DocumentProcessors/YamlDocumentModel.cs b/test/Docfx.Build.Tests/DocumentProcessors/YamlDocumentModel.cs index d05c828c08e..8623653babe 100644 --- a/test/Docfx.Build.Tests/DocumentProcessors/YamlDocumentModel.cs +++ b/test/Docfx.Build.Tests/DocumentProcessors/YamlDocumentModel.cs @@ -20,10 +20,10 @@ public class YamlDocumentModel [ExtensibleMember] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary Data { get; set; } = new(); + public Dictionary Data { get; set; } = []; [YamlMember(Alias = "metadata")] [JsonProperty("metadata")] [JsonPropertyName("metadata")] - public Dictionary Metadata { get; set; } = new(); + public Dictionary Metadata { get; set; } = []; } diff --git a/test/Docfx.Build.Tests/FileMetadataHelperTest.cs b/test/Docfx.Build.Tests/FileMetadataHelperTest.cs index 0c3fd561d31..2768b57ea0a 100644 --- a/test/Docfx.Build.Tests/FileMetadataHelperTest.cs +++ b/test/Docfx.Build.Tests/FileMetadataHelperTest.cs @@ -122,18 +122,24 @@ public void TestGetChangedGlobs_CrossGlobsChanged() var patterns = new string[] { "*md", "*.m", "abc", "/[]\\*.cs", "*/*.cs", "**" }; var left = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + + [ new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true) - ) +, + ] }); var right = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + + [ new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true), new FileMetadataItem(new GlobMatcher(patterns[2]), "meta", "string") - ) +, + ] }); var actualResults = FileMetadataHelper.GetChangedGlobs(left, right).ToList(); @@ -150,17 +156,18 @@ public void TestGetChangedGlobs_ReduceGlobsChanged() var patterns = new string[] { "*md", "*.m", "abc", "/[]\\*.cs", "*/*.cs", "**" }; var left = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + + [ new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true) - ) +, + ] }); var right = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( - new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L) - ) + ["meta"] = [new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L)] }); var actualResults = FileMetadataHelper.GetChangedGlobs(left, right).ToList(); @@ -176,19 +183,25 @@ public void TestGetChangedGlobs_IncreaseGlobsChanged() var patterns = new string[] { "*md", "*.m", "abc" }; var left = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + + [ new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true) - ) +, + ] }); var right = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + + [ new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true), new FileMetadataItem(new GlobMatcher(patterns[2]), "meta", "string") - ) +, + ] }); var actualResults = FileMetadataHelper.GetChangedGlobs(left, right).ToList(); @@ -204,12 +217,15 @@ public void TestGetChangedGlobs_Changed() var patterns = new string[] { "*md", "*.m", "abc", "/[]\\*.cs", "*/*.cs", "**" }; var left = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + + [ new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true), new FileMetadataItem(new GlobMatcher(patterns[3]), "meta", new Dictionary { ["key"] = "2" }), new FileMetadataItem(new GlobMatcher(patterns[5]), "meta", new Dictionary { ["key"] = new object[] { "1", "2" } }) - ) +, + ] }); var right = new FileMetadata(baseDir, new Dictionary> @@ -238,18 +254,20 @@ public void TestGetChangedGlobs_Changed_Reverse() var patterns = new string[] { "*md", "*.m" }; var left = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + [ new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true) - ) + ] }); var right = new FileMetadata(baseDir, new Dictionary> { - ["meta"] = ImmutableArray.Create( + ["meta"] = + [ new FileMetadataItem(new GlobMatcher(patterns[1]), "meta", true), - new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L) - ) + new FileMetadataItem(new GlobMatcher(patterns[0]), "meta", 1L), + ] }); var actualResults = FileMetadataHelper.GetChangedGlobs(left, right).ToList(); diff --git a/test/Docfx.Build.Tests/JintProcessorHelperTest.cs b/test/Docfx.Build.Tests/JintProcessorHelperTest.cs index e520143599f..ff772e00a34 100644 --- a/test/Docfx.Build.Tests/JintProcessorHelperTest.cs +++ b/test/Docfx.Build.Tests/JintProcessorHelperTest.cs @@ -52,6 +52,6 @@ private sealed class TestData public Dictionary ValueDict { get; set; } = new() { [1] = "Value1", ["key"] = 2 }; - public List ValueList { get; set; } = new() { "ValueA", "ValueB" }; + public List ValueList { get; set; } = ["ValueA", "ValueB"]; } } diff --git a/test/Docfx.Build.Tests/TemplateManagerUnitTest.cs b/test/Docfx.Build.Tests/TemplateManagerUnitTest.cs index a97a85ea613..22c766f0612 100644 --- a/test/Docfx.Build.Tests/TemplateManagerUnitTest.cs +++ b/test/Docfx.Build.Tests/TemplateManagerUnitTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Docfx.Common; using Docfx.Plugins; using Docfx.Tests.Common; @@ -585,7 +584,7 @@ private static void WriteTemplate(string cwd, params Tuple[] fil var filePath = Path.Combine(cwd ?? string.Empty, file.Item1); var directory = Path.GetDirectoryName(filePath); - if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + if (!string.IsNullOrEmpty(directory)) Directory.CreateDirectory(directory); File.WriteAllText(filePath, file.Item2); } diff --git a/test/Docfx.Build.Tests/TemplateProcessorUnitTest.cs b/test/Docfx.Build.Tests/TemplateProcessorUnitTest.cs index afa8b8cfbc1..097a821e3e6 100644 --- a/test/Docfx.Build.Tests/TemplateProcessorUnitTest.cs +++ b/test/Docfx.Build.Tests/TemplateProcessorUnitTest.cs @@ -61,6 +61,6 @@ private ManifestItem Process(string documentType, string fileName, object conten LocalPathFromRoot = fileName, Content = content, }; - return processor.Process(new List { inputItem }, new ApplyTemplateSettings(_inputFolder, _outputFolder))[0]; + return processor.Process([inputItem], new ApplyTemplateSettings(_inputFolder, _outputFolder))[0]; } } diff --git a/test/Docfx.Build.Tests/TocDocumentProcessorTest.cs b/test/Docfx.Build.Tests/TocDocumentProcessorTest.cs index 6b2dbc2ca47..11d201e646f 100644 --- a/test/Docfx.Build.Tests/TocDocumentProcessorTest.cs +++ b/test/Docfx.Build.Tests/TocDocumentProcessorTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; -using System.Reflection; using System.Web; using Docfx.Build.Engine; using Docfx.Common; @@ -60,15 +59,15 @@ public void ProcessMarkdownTocWithComplexHrefShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Constructor", Href = $"{href}.md", TopicHref = $"{href}.md", } - } + ] }; AssertTocEqual(expectedModel, model); @@ -94,27 +93,27 @@ public void ProcessMarkdownTocWithAbsoluteHrefShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Topic1 Language", Href = "/href1", TopicHref = "/href1", - Items = new List - { + Items = + [ new() { Name = "Topic1.1 Language C#", - Items = new List - { + Items = + [ new() { Name = "Topic1.1.1", Href = "/href1.1.1", TopicHref = "/href1.1.1" } - } + ] }, new() { @@ -122,7 +121,7 @@ public void ProcessMarkdownTocWithAbsoluteHrefShouldSucceed() Href = string.Empty, TopicHref = string.Empty } - } + ] }, new() { @@ -130,7 +129,7 @@ public void ProcessMarkdownTocWithAbsoluteHrefShouldSucceed() Href = "http://href.com", TopicHref = "http://href.com" } - } + ] }; AssertTocEqual(expectedModel, model); @@ -158,29 +157,29 @@ public void ProcessMarkdownTocWithRelativeHrefShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Topic1", Href = "/href1", TopicHref = "/href1", - Items = new List - { + Items = + [ new() { Name = "Topic1.1", Href = file1, TopicHref = file1, - Items = new List - { + Items = + [ new() { Name = "Topic1.1.1", Href = file2, TopicHref = file2 } - } + ] }, new() { @@ -188,7 +187,7 @@ public void ProcessMarkdownTocWithRelativeHrefShouldSucceed() Href = string.Empty, TopicHref = string.Empty } - } + ] }, new() { @@ -202,7 +201,7 @@ public void ProcessMarkdownTocWithRelativeHrefShouldSucceed() Href = "invalid.md", TopicHref = "invalid.md" } - } + ] }; AssertTocEqual(expectedModel, model); @@ -238,15 +237,15 @@ public void ProcessYamlTocWithFolderShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Topic1", Href = file1, TopicHref = file1, - Items = new List - { + Items = + [ new() { Name = "Topic1.1", @@ -262,7 +261,7 @@ public void ProcessYamlTocWithFolderShouldSucceed() TopicHref = file1, TocHref = "sub/toc.md", } - } + ] }, new() { @@ -271,7 +270,7 @@ public void ProcessYamlTocWithFolderShouldSucceed() TopicHref = file2, TocHref = "sub/toc.md", } - } + ] }; AssertTocEqual(expectedModel, model); @@ -317,24 +316,24 @@ public void ProcessYamlTocWithMetadataShouldSucceed() var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Topic1", Href = file1, TopicHref = file1, - Items = new List - { + Items = + [ new() { Name = "Topic1.1", Href = file1, // For relative file, href keeps unchanged TopicHref = file1, } - } + ] } - } + ] }; AssertTocEqual(expectedModel, model); } @@ -386,23 +385,23 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Topic1", Href = file1, TopicHref = file1, - Items = new List - { + Items = + [ new() { Name = "Topic1.1", IncludedFrom = "~/sub1/toc.md", Href = null, // For referenced toc, the content from the referenced toc is expanded as the items of current toc, and href is cleared TopicHref = null, - Items = new List - { + Items = + [ new() { Name = "Topic", @@ -413,8 +412,8 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() { Name = "ReferencedToc", IncludedFrom = "~/sub1/sub2/toc.yml", - Items = new List - { + Items = + [ new() { Name = "Topic", @@ -427,22 +426,22 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() Href = "sub1/sub2/a/b/c.md", TopicHref = "sub1/sub2/a/b/c.md", } - } + ] }, new() { Name = "ReferencedToc2", IncludedFrom = "~/sub1/sub3/toc.md", - Items = new List - { + Items = + [ new() { Name = "Not-existed-md", Href = "sub1/sub3/sub2/notexist.md", TopicHref = "sub1/sub3/sub2/notexist.md", }, - } + ] }, new() { @@ -450,7 +449,7 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() Href = "sub1/sub2/notexist.md", TopicHref = "sub1/sub2/notexist.md", } - } + ] }, new() { @@ -459,8 +458,8 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() TopicHref = file1, IncludedFrom = "~/sub1/toc.md", Homepage = file1, - Items = new List - { + Items = + [ new() { Name = "Topic", @@ -471,8 +470,8 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() { Name = "ReferencedToc", IncludedFrom = "~/sub1/sub2/toc.yml", - Items = new List - { + Items = + [ new() { Name = "Topic", @@ -485,21 +484,21 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() Href = "sub1/sub2/a/b/c.md", TopicHref = "sub1/sub2/a/b/c.md", } - } + ] }, new() { Name = "ReferencedToc2", IncludedFrom = "~/sub1/sub3/toc.md", - Items = new List - { + Items = + [ new() { Name = "Not-existed-md", Href = "sub1/sub3/sub2/notexist.md", TopicHref = "sub1/sub3/sub2/notexist.md", } - } + ] }, new() { @@ -507,17 +506,17 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() Href = "sub1/sub2/notexist.md", TopicHref = "sub1/sub2/notexist.md", } - } + ] } - } + ] }, new() { Name = "Topic2", IncludedFrom = "~/sub1/sub2/toc.yml", Href = null, - Items = new List - { + Items = + [ new() { Name = "Topic", @@ -530,9 +529,9 @@ public void ProcessYamlTocWithReferencedTocShouldSucceed() Href = "sub1/sub2/a/b/c.md", TopicHref = "sub1/sub2/a/b/c.md", } - } + ] } - } + ] }; AssertTocEqual(expectedModel, model); @@ -575,7 +574,7 @@ public void ProcessMarkdownTocWithNonExistentReferencedTocShouldLogError() var files = new FileCollection(_inputFolder); files.Add(DocumentType.Article, new[] { toc }); - var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter(new List { WarningCodes.Build.InvalidTocInclude }); + var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter([WarningCodes.Build.InvalidTocInclude]); Logger.RegisterListener(listener); BuildDocument(files); @@ -599,7 +598,7 @@ public void ProcessYamlTocWithNonExistentReferencedTocShouldLogError() var files = new FileCollection(_inputFolder); files.Add(DocumentType.Article, new[] { toc }); - var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter(new List { WarningCodes.Build.InvalidTocInclude }); + var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter([WarningCodes.Build.InvalidTocInclude]); Logger.RegisterListener(listener); BuildDocument(files); Logger.UnregisterListener(listener); @@ -645,8 +644,8 @@ public void ProcessYamlTocWithTocHrefShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); var expectedModel = new TocItemViewModel { - Items = new List - { + Items = + [ new() { Name = "Topic1", @@ -654,8 +653,8 @@ public void ProcessYamlTocWithTocHrefShouldSucceed() TocHref = "/Topic1/", Homepage = "/Topic1/index.html", TopicHref = "/Topic1/index.html", - Items = new List - { + Items = + [ new() { Name = "Topic1.1", @@ -672,7 +671,7 @@ public void ProcessYamlTocWithTocHrefShouldSucceed() Homepage = "/Topic1.2/index.html", TopicHref = "/Topic1.2/index.html", } - } + ] }, new() { @@ -682,7 +681,7 @@ public void ProcessYamlTocWithTocHrefShouldSucceed() TopicHref = file2, Homepage = file2, } - } + ] }; AssertTocEqual(expectedModel, model); @@ -813,7 +812,7 @@ public void WarningShouldBeFromIncludedToc() // Act var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter( - new List { WarningCodes.Build.InvalidFileLink, WarningCodes.Build.UidNotFound }); + [WarningCodes.Build.InvalidFileLink, WarningCodes.Build.UidNotFound]); Logger.RegisterListener(listener); BuildDocument(files); Logger.UnregisterListener(listener); @@ -841,7 +840,7 @@ public void UrlDecodeHrefInYamlToc() // Act var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter( - new List { WarningCodes.Build.InvalidFileLink }); + [WarningCodes.Build.InvalidFileLink]); Logger.RegisterListener(listener); BuildDocument(files); Logger.UnregisterListener(listener); @@ -863,7 +862,7 @@ public void UrlDecodeHrefInMarkdownToc() // Act var listener = TestLoggerListener.CreateLoggerListenerWithCodesFilter( - new List { WarningCodes.Build.InvalidFileLink }); + [WarningCodes.Build.InvalidFileLink]); Logger.RegisterListener(listener); BuildDocument(files); Logger.UnregisterListener(listener); diff --git a/test/Docfx.Build.Tests/TocRestructureTest.cs b/test/Docfx.Build.Tests/TocRestructureTest.cs index b25c761b68f..f1308faf7c9 100644 --- a/test/Docfx.Build.Tests/TocRestructureTest.cs +++ b/test/Docfx.Build.Tests/TocRestructureTest.cs @@ -259,7 +259,7 @@ private TocItemViewModel GetTocItem(string layout) } var root = new TocItemViewModel { - Items = new() + Items = [] }; var stack = new Stack>(); stack.Push(Tuple.Create(new LineInfo @@ -280,7 +280,7 @@ private TocItemViewModel GetTocItem(string layout) var parent = stack.Peek(); if (parent.Item2.Items == null) { - parent.Item2.Items = new(); + parent.Item2.Items = []; } parent.Item2.Items.Add(item); @@ -291,8 +291,8 @@ private TocItemViewModel GetTocItem(string layout) private IEnumerable GetLines(string layout) { - return layout.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries) - .SelectMany(s => s.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries)) + return layout.Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries) + .SelectMany(s => s.Split(["\n"], StringSplitOptions.RemoveEmptyEntries)) .Where(s => !string.IsNullOrWhiteSpace(s)).Select(GetLineInfo); } diff --git a/test/Docfx.Build.Tests/XRefMapDownloaderTest.cs b/test/Docfx.Build.Tests/XRefMapDownloaderTest.cs index b3557df9c27..04f21141a85 100644 --- a/test/Docfx.Build.Tests/XRefMapDownloaderTest.cs +++ b/test/Docfx.Build.Tests/XRefMapDownloaderTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Net; using FluentAssertions; using Xunit; diff --git a/test/Docfx.Build.Tests/XRefMapSerializationTest.cs b/test/Docfx.Build.Tests/XRefMapSerializationTest.cs index 6925b4234f0..8ab4489200b 100644 --- a/test/Docfx.Build.Tests/XRefMapSerializationTest.cs +++ b/test/Docfx.Build.Tests/XRefMapSerializationTest.cs @@ -19,16 +19,16 @@ public void XRefMapSerializationRoundTripTest() BaseUrl = "http://localhost", Sorted = true, HrefUpdated = null, - Redirections = new List - { + Redirections = + [ new() { Href = "Dummy", UidPrefix = "Dummy" }, - }, - References = new List - { + ], + References = + [ new(new Dictionary { ["Additional1"] = "Dummy", @@ -40,7 +40,7 @@ public void XRefMapSerializationRoundTripTest() CommentId ="Dummy", IsSpec = true, }, - }, + ], Others = new Dictionary { ["StringValue"] = "Dummy", diff --git a/test/Docfx.Build.UniversalReference.Tests/UniversalReferenceDocumentProcessorTest.cs b/test/Docfx.Build.UniversalReference.Tests/UniversalReferenceDocumentProcessorTest.cs index 04240ae3d34..acad455356f 100644 --- a/test/Docfx.Build.UniversalReference.Tests/UniversalReferenceDocumentProcessorTest.cs +++ b/test/Docfx.Build.UniversalReference.Tests/UniversalReferenceDocumentProcessorTest.cs @@ -34,7 +34,7 @@ public UniversalReferenceDocumentProcessorTest() RawModelExportSettings = { Export = true }, TransformDocument = true, }; - _templateManager = new TemplateManager(new List { "template" }, null, "TestData/"); + _templateManager = new TemplateManager(["template"], null, "TestData/"); } #region Python diff --git a/test/Docfx.Common.Tests/CompositeDictionaryTest.cs b/test/Docfx.Common.Tests/CompositeDictionaryTest.cs index 2bbe7ee86b0..ff8f6e735bf 100644 --- a/test/Docfx.Common.Tests/CompositeDictionaryTest.cs +++ b/test/Docfx.Common.Tests/CompositeDictionaryTest.cs @@ -105,9 +105,9 @@ public void TestThrowCaseForCompositeDictionary() private sealed class C { - public Dictionary D1 { get; } = new(); - public SortedDictionary D2 { get; } = new(); - public SortedList D3 { get; } = new(); + public Dictionary D1 { get; } = []; + public SortedDictionary D2 { get; } = []; + public SortedList D3 { get; } = []; private CompositeDictionary _cd; public CompositeDictionary CD { diff --git a/test/Docfx.Common.Tests/ConvertToObjectHelperTest.cs b/test/Docfx.Common.Tests/ConvertToObjectHelperTest.cs index 138b4c9795f..bb39a7e9f56 100644 --- a/test/Docfx.Common.Tests/ConvertToObjectHelperTest.cs +++ b/test/Docfx.Common.Tests/ConvertToObjectHelperTest.cs @@ -30,8 +30,8 @@ public void ConvertComplexTypeToObjectShouldWork() var complexType = new ComplexType { String = "String", - List = new List(), - IntDictionary = new Dictionary() + List = [], + IntDictionary = [] }; var result = ConvertToObjectHelper.ConvertStrongTypeToObject(complexType); Assert.Equal(typeof(Dictionary), result.GetType()); @@ -45,8 +45,8 @@ public void ConvertComplexTypeWithJsonAttributeToObjectShouldUseAttributeAsPrope var complexType = new ComplexTypeWithJson { String = "String", - List = new List(), - IntDictionary = new Dictionary() + List = [], + IntDictionary = [] }; var result = ConvertToObjectHelper.ConvertStrongTypeToObject(complexType); Assert.Equal(typeof(Dictionary), result.GetType()); diff --git a/test/Docfx.Common.Tests/PathUtilityTest.cs b/test/Docfx.Common.Tests/PathUtilityTest.cs index aaceedef989..5dba7472edd 100644 --- a/test/Docfx.Common.Tests/PathUtilityTest.cs +++ b/test/Docfx.Common.Tests/PathUtilityTest.cs @@ -46,10 +46,10 @@ private static class TestData { "/temp/dir", "/temp/dir/subdir/", "subdir/"}, // If target path endsWith directory separator char. resolved path should contain directory separator. }; - public static TheoryData EscapedPaths = new() - { + public static TheoryData EscapedPaths = + [ "EscapedHypen(%2D).md", // Contains escaped hypen char "EscapedSpace(%20)_with_NonAsciiChar(α).md", // Contains escaped space char and non-unicode char - }; + ]; } } diff --git a/test/Docfx.Common.Tests/YamlSerializationTest.cs b/test/Docfx.Common.Tests/YamlSerializationTest.cs index a2b1315ffce..74fb179a5c3 100644 --- a/test/Docfx.Common.Tests/YamlSerializationTest.cs +++ b/test/Docfx.Common.Tests/YamlSerializationTest.cs @@ -325,11 +325,11 @@ public void TestListOfClassWithExtensibleMembers() public class ClassWithExtensibleMembers : BasicClass { [ExtensibleMember("s.")] - public SortedDictionary StringExtensions { get; } = new(); + public SortedDictionary StringExtensions { get; } = []; [ExtensibleMember("i.")] - public SortedList IntegerExtensions { get; } = new(); + public SortedList IntegerExtensions { get; } = []; [ExtensibleMember()] - public Dictionary ObjectExtensions { get; } = new(); + public Dictionary ObjectExtensions { get; } = []; } [Fact] @@ -364,7 +364,7 @@ public void TestClassWithInterfaceMember() var sw = new StringWriter(); YamlUtility.Serialize(sw, new ClassWithInterfaceMember { - List = new List { "a" }, + List = ["a"], ReadOnlyList = new[] { "b" }, Collection = new Collection { "c" }, ReadOnlyCollection = ImmutableList.Create("d"), diff --git a/test/Docfx.Dotnet.Tests/ApiFilterUnitTest.cs b/test/Docfx.Dotnet.Tests/ApiFilterUnitTest.cs index 7f7babdf6d3..0a1f3a32b08 100644 --- a/test/Docfx.Dotnet.Tests/ApiFilterUnitTest.cs +++ b/test/Docfx.Dotnet.Tests/ApiFilterUnitTest.cs @@ -10,7 +10,7 @@ namespace Docfx.Dotnet.Tests; [Collection("docfx STA")] public class ApiFilterUnitTest { - private static readonly Dictionary EmptyMSBuildProperties = new(); + private static readonly Dictionary EmptyMSBuildProperties = []; [Fact] public void TestApiFilter() diff --git a/test/Docfx.Dotnet.Tests/GenerateMetadataFromCSUnitTest.cs b/test/Docfx.Dotnet.Tests/GenerateMetadataFromCSUnitTest.cs index 862bdf0d125..fbad40a99f4 100644 --- a/test/Docfx.Dotnet.Tests/GenerateMetadataFromCSUnitTest.cs +++ b/test/Docfx.Dotnet.Tests/GenerateMetadataFromCSUnitTest.cs @@ -12,7 +12,7 @@ namespace Docfx.Dotnet.Tests; [Collection("docfx STA")] public class GenerateMetadataFromCSUnitTest { - private static readonly Dictionary EmptyMSBuildProperties = new(); + private static readonly Dictionary EmptyMSBuildProperties = []; private static MetadataItem Verify(string code, ExtractMetadataConfig config = null, IDictionary msbuildProperties = null, MetadataReference[] references = null) { diff --git a/test/Docfx.Dotnet.Tests/GenerateMetadataFromVBUnitTest.cs b/test/Docfx.Dotnet.Tests/GenerateMetadataFromVBUnitTest.cs index 502a6144ca7..41c5d2d378d 100644 --- a/test/Docfx.Dotnet.Tests/GenerateMetadataFromVBUnitTest.cs +++ b/test/Docfx.Dotnet.Tests/GenerateMetadataFromVBUnitTest.cs @@ -11,7 +11,7 @@ namespace Docfx.Dotnet.Tests; [Collection("docfx STA")] public class GenerateMetadataFromVBUnitTest { - private static readonly Dictionary EmptyMSBuildProperties = new(); + private static readonly Dictionary EmptyMSBuildProperties = []; private static MetadataItem Verify(string code, ExtractMetadataConfig config = null, IDictionary msbuildProperties = null, MetadataReference[] references = null) { diff --git a/test/Docfx.MarkdigEngine.Extensions.Tests/QuoteSectionNoteTest.cs b/test/Docfx.MarkdigEngine.Extensions.Tests/QuoteSectionNoteTest.cs index de4d5279a1d..43a42ff810e 100644 --- a/test/Docfx.MarkdigEngine.Extensions.Tests/QuoteSectionNoteTest.cs +++ b/test/Docfx.MarkdigEngine.Extensions.Tests/QuoteSectionNoteTest.cs @@ -421,6 +421,19 @@ public void TestVideoBlock_Normal() TestUtility.VerifyMarkup(source, expected); } + [Fact] + [Trait("Related", "DfmMarkdown")] + public void TestVideoBlock_Http() + { + var source = @"# Article 2 +> [!VIDEO http://microsoft.com:8080?query=http+A#bookmark] +"; + var expected = @"

Article 2

+
+"; + TestUtility.VerifyMarkup(source, expected); + } + [Fact] [Trait("Related", "DfmMarkdown")] public void TestVideoBlock_Channel9() diff --git a/test/Docfx.MarkdigEngine.Extensions.Tests/TestUtility.cs b/test/Docfx.MarkdigEngine.Extensions.Tests/TestUtility.cs index 32d6ac85ba1..96c98606e4b 100644 --- a/test/Docfx.MarkdigEngine.Extensions.Tests/TestUtility.cs +++ b/test/Docfx.MarkdigEngine.Extensions.Tests/TestUtility.cs @@ -23,9 +23,9 @@ public static string VerifyMarkup( Dictionary notes = null, PlantUmlOptions plantUml = null) { - errors ??= Array.Empty(); - tokens ??= new Dictionary(); - files ??= new Dictionary(); + errors ??= []; + tokens ??= []; + files ??= []; optionalExtensions ??= []; var actualErrors = new List(); diff --git a/test/Docfx.MarkdigEngine.Extensions.Tests/VideoTest.cs b/test/Docfx.MarkdigEngine.Extensions.Tests/VideoTest.cs index 544216da32f..f09d0034673 100644 --- a/test/Docfx.MarkdigEngine.Extensions.Tests/VideoTest.cs +++ b/test/Docfx.MarkdigEngine.Extensions.Tests/VideoTest.cs @@ -13,14 +13,18 @@ public class VideoTest

")] [InlineData(@":::video source=""https://www.youtube.com/embed/wV11_nbT2XE"" title=""Video: Build-Your-First-Android-App-with-Visual-Studio-2019-and-Xamarin"" thumbnail=""media/3-eclipse-install-button.png"" upload-date=""07/27/2020"":::", @"

- + +

+")] + [InlineData(@":::video source=""https://www.youtube.com/embed/wV11_nbT2XE?rel=1"" title=""Video: Build-Your-First-Android-App-with-Visual-Studio-2019-and-Xamarin"" thumbnail=""media/3-eclipse-install-button.png"" upload-date=""07/27/2020"":::", @"

+

")] [InlineData( @":::video source=""https://www.youtube.com/embed/wV11_nbT2XE"" title=""Video: Build-Your-First-Android-App-with-Visual-Studio-2019-and-Xamarin"" thumbnail=""media/3-eclipse-install-button.png"" upload-date=""07/27/2020""::: :::video source=""https://channel9.msdn.com/Shows/XamarinShow/Build-Your-First-Android-App-with-Visual-Studio-2019-and-Xamarin/player?nocookie=true"" title=""Video: Build-Your-First-Android-App-with-Visual-Studio-2019-and-Xamarin"" max-width=""400"" thumbnail=""media/3-eclipse-install-button.png"" upload-date=""07/27/2020""::: ", @"

-