├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── dotnet.yml
├── .gitignore
├── CODE-OF-CONDUCT.md
├── LICENSE
├── README.md
├── build.proj
├── docs
├── PortToDocs.md
└── PortToTripleSlash.md
├── install-as-tool.ps1
├── nuget.config
└── src
├── Common
├── src
│ └── Log.cs
└── tests
│ ├── BasePortTests.cs
│ ├── FileTestData.cs
│ └── TestDirectory.cs
├── Directory.Build.props
├── PortToDocs
├── PortToDocs.sln
├── src
│ ├── app
│ │ ├── PortToDocs.cs
│ │ └── PortToDocs.csproj
│ └── libraries
│ │ ├── Configuration.cs
│ │ ├── Docs
│ │ ├── APIKind.cs
│ │ ├── DocsAPI.cs
│ │ ├── DocsAssemblyInfo.cs
│ │ ├── DocsAttribute.cs
│ │ ├── DocsCommentsContainer.cs
│ │ ├── DocsException.cs
│ │ ├── DocsMember.cs
│ │ ├── DocsMemberSignature.cs
│ │ ├── DocsParam.cs
│ │ ├── DocsParameter.cs
│ │ ├── DocsRelated.cs
│ │ ├── DocsSeeAlso.cs
│ │ ├── DocsType.cs
│ │ ├── DocsTypeParam.cs
│ │ ├── DocsTypeParameter.cs
│ │ ├── DocsTypeSignature.cs
│ │ └── IDocsAPI.cs
│ │ ├── Extensions.cs
│ │ ├── IntelliSenseXml
│ │ ├── IntelliSenseXmlCommentsContainer.cs
│ │ ├── IntelliSenseXmlException.cs
│ │ ├── IntelliSenseXmlMember.cs
│ │ ├── IntelliSenseXmlParam.cs
│ │ ├── IntelliSenseXmlSeeAlso.cs
│ │ └── IntelliSenseXmlTypeParam.cs
│ │ ├── ToDocsPorter.cs
│ │ ├── XmlHelper.cs
│ │ └── libraries.csproj
└── tests
│ ├── PortToDocs.FileSystem.Tests.cs
│ ├── PortToDocs.Strings.Tests.cs
│ ├── StringTestData.cs
│ ├── TestData
│ ├── AssemblyAndNamespaceDifferent
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── AssemblyAndNamespaceSame
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── Basic
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── DontAddMissingRemarks
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── EnumRemarks
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── Exception_ExistingCref
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── Exceptions
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── InheritDoc
│ │ ├── intellisense
│ │ │ ├── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ │ └── System
│ │ │ │ └── System.xml
│ │ ├── xml
│ │ │ ├── MyAssembly
│ │ │ │ └── MyType.xml
│ │ │ └── System
│ │ │ │ └── MyParentType.xml
│ │ └── xml_expected
│ │ │ ├── MyAssembly
│ │ │ └── MyType.xml
│ │ │ └── System
│ │ │ └── MyParentType.xml
│ ├── Remarks_NoEII_NoInterfaceRemarks
│ │ ├── intellisense
│ │ │ ├── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ │ └── System
│ │ │ │ └── System.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ └── MyType.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ ├── Remarks_WithEII_NoInterfaceRemarks
│ │ ├── intellisense
│ │ │ └── MyAssembly
│ │ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ │ └── MyAssembly
│ │ │ │ ├── MyType.xml
│ │ │ │ └── System
│ │ │ │ └── System.xml
│ │ └── xml_expected
│ │ │ └── MyAssembly
│ │ │ └── MyType.xml
│ └── Remarks_WithEII_WithInterfaceRemarks
│ │ ├── intellisense
│ │ └── MyAssembly
│ │ │ └── MyAssembly.xml
│ │ ├── xml
│ │ └── MyAssembly
│ │ │ ├── MyType.xml
│ │ │ └── System
│ │ │ └── System.xml
│ │ └── xml_expected
│ │ └── MyAssembly
│ │ └── MyType.xml
│ └── tests.csproj
└── PortToTripleSlash
├── PortToTripleSlash.sln
├── src
├── app
│ ├── PortToTripleSlash.cs
│ └── PortToTripleSlash.csproj
└── libraries
│ ├── AllTypesVisitor.cs
│ ├── Configuration.cs
│ ├── Docs
│ ├── APIKind.cs
│ ├── DocsAPI.cs
│ ├── DocsAssemblyInfo.cs
│ ├── DocsAttribute.cs
│ ├── DocsCommentsContainer.cs
│ ├── DocsException.cs
│ ├── DocsMember.cs
│ ├── DocsMemberSignature.cs
│ ├── DocsParam.cs
│ ├── DocsParameter.cs
│ ├── DocsRelated.cs
│ ├── DocsType.cs
│ ├── DocsTypeParam.cs
│ ├── DocsTypeParameter.cs
│ ├── DocsTypeSignature.cs
│ └── IDocsAPI.cs
│ ├── Extensions.cs
│ ├── MSBuildLoader.cs
│ ├── ResolvedLocation.cs
│ ├── ResolvedProject.cs
│ ├── ResolvedWorkspace.cs
│ ├── RoslynTripleSlash
│ ├── DocumentationUpdater.cs
│ └── TripleSlashSyntaxRewriter.cs
│ ├── ToTripleSlashPorter.cs
│ ├── VSLoader.cs
│ ├── XmlHelper.cs
│ └── libraries.csproj
└── tests
├── PortToTripleSlash
├── PortToTripleSlash.FileSystem.Tests.cs
├── PortToTripleSlash.Strings.Tests.cs
├── PortToTripleSlashTestData.cs
├── StringTestData.cs
└── TestData
│ └── Basic
│ ├── MyAssembly.csproj
│ ├── MyDelegate.xml
│ ├── MyEnum.xml
│ ├── MyType.xml
│ ├── SourceExpected.cs
│ └── SourceOriginal.cs
└── tests.csproj
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set default behavior to automatically normalize line endings.
2 | * text=auto eol=lf
3 |
4 | *.doc diff=astextplain
5 | *.DOC diff=astextplain
6 | *.docx diff=astextplain
7 | *.DOCX diff=astextplain
8 | *.dot diff=astextplain
9 | *.DOT diff=astextplain
10 | *.pdf diff=astextplain
11 | *.PDF diff=astextplain
12 | *.rtf diff=astextplain
13 | *.RTF diff=astextplain
14 |
15 | *.jpg binary
16 | *.png binary
17 | *.gif binary
18 |
19 | # Force bash scripts to always use lf line endings so that if a repo is accessed
20 | # in Unix via a file share from Windows, the scripts will work.
21 | *.in text eol=lf
22 | *.sh text eol=lf
23 |
24 | # Likewise, force cmd and batch scripts to always use crlf
25 | *.cmd text eol=crlf
26 | *.bat text eol=crlf
27 |
28 | *.cs text=auto diff=csharp
29 | *.vb text=auto
30 | *.resx text=auto
31 | *.c text=auto
32 | *.cpp text=auto
33 | *.cxx text=auto
34 | *.h text=auto
35 | *.hxx text=auto
36 | *.py text=auto
37 | *.rb text=auto
38 | *.java text=auto
39 | *.html text=auto
40 | *.htm text=auto
41 | *.css text=auto
42 | *.scss text=auto
43 | *.sass text=auto
44 | *.less text=auto
45 | *.js text=auto
46 | *.lisp text=auto
47 | *.clj text=auto
48 | *.sql text=auto
49 | *.php text=auto
50 | *.lua text=auto
51 | *.m text=auto
52 | *.asm text=auto
53 | *.erl text=auto
54 | *.fs text=auto
55 | *.fsx text=auto
56 | *.hs text=auto
57 | *.xml text=auto
58 |
59 | *.csproj text=auto
60 | *.vbproj text=auto
61 | *.fsproj text=auto
62 | *.dbproj text=auto
63 | *.sln text=auto eol=crlf
64 |
65 | # Set linguist language for .h files explicitly based on
66 | # https://github.com/github/linguist/issues/1626#issuecomment-401442069
67 | # this only affects the repo's language statistics
68 | *.h linguist-language=C
69 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: '8.0.x'
20 | - name: Restore dependencies of PortToTripleSlash
21 | run: dotnet restore src/PortToTripleSlash/PortToTripleSlash.sln
22 | - name: Build PortToTripleSlash
23 | run: dotnet build --no-restore src/PortToTripleSlash/PortToTripleSlash.sln
24 | # Re-enable when the msbuild failure is fixed, to prevent skipping the subsequent tasks
25 | - name: Test PortToTripleSlash
26 | run: dotnet test --no-build --verbosity normal src/PortToTripleSlash/PortToTripleSlash.sln
27 | - name: Restore dependencies of PortToDocs
28 | run: dotnet restore src/PortToDocs/PortToDocs.sln
29 | - name: Build PortToDocs
30 | run: dotnet build --no-restore src/PortToDocs/PortToDocs.sln
31 | - name: Test PortToDocs
32 | run: dotnet test --no-build --verbosity normal src/PortToDocs/PortToDocs.sln
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | syntax: glob
2 |
3 | ### VisualStudio ###
4 |
5 | # Tools directory
6 | /[Tt]ools/
7 | .dotnet/
8 | .packages/
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 | launchSettings.json
16 |
17 | # Live Unit Tests
18 | .lutignore
19 | *.lutconfig
20 |
21 | # Build results
22 |
23 | artifacts/
24 | artifacts_stage_1/
25 | [Dd]ebug/
26 | [Rr]elease/
27 | x64/
28 | x86/ !eng/common/cross/x86/
29 | [Bb]in/
30 | [Oo]bj/
31 | msbuild.log
32 | msbuild.err
33 | msbuild.wrn
34 | msbuild.binlog
35 |
36 | # Visual Studio 2015
37 | .vs/
38 |
39 | # Visual Studio 2015 Pre-CTP6
40 | *.sln.ide
41 | *.ide/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | #NUNIT
48 | *.VisualState.xml
49 | TestResult.xml
50 |
51 | # ReSharper is a .NET coding add-in
52 | _ReSharper*/
53 | *.[Rr]e[Ss]harper
54 | *.DotSettings.user
55 |
56 | # DotCover is a Code Coverage Tool
57 | *.dotCover
58 |
59 | # NuGet Packages
60 | *.nuget.props
61 | *.nuget.targets
62 | *.nupkg
63 | **/packages/*
64 |
65 | ### Windows ###
66 |
67 | # Windows image file caches
68 | Thumbs.db
69 | ehthumbs.db
70 |
71 | # Folder config file
72 | Desktop.ini
73 |
74 | # Recycle Bin used on file shares
75 | $RECYCLE.BIN/
76 |
77 | # Windows Installer files
78 | *.cab
79 | *.msi
80 | *.msm
81 | *.msp
82 |
83 | # Windows shortcuts
84 | *.lnk
85 |
86 | ### Linux ###
87 |
88 | *~
89 |
90 | # KDE directory preferences
91 | .directory
92 |
93 | ### OSX ###
94 |
95 | .DS_Store
96 | .AppleDouble
97 | .LSOverride
98 |
99 | # Icon must end with two \r
100 | Icon
101 |
102 | # Thumbnails
103 | ._*
104 |
105 | # Files that might appear on external disk
106 | .Spotlight-V100
107 | .Trashes
108 |
109 | # Directories potentially created on remote AFP share
110 | .AppleDB
111 | .AppleDesktop
112 | Network Trash Folder
113 | Temporary Items
114 | .apdisk
115 |
116 | # vim temporary files
117 | [._]*.s[a-w][a-z]
118 | [._]s[a-w][a-z]
119 | *.un~
120 | Session.vim
121 | .netrwhist
122 | *~
123 |
124 | # Visual Studio Code
125 | .vscode/
126 |
127 | # Private test configuration and binaries.
128 | config.ps1
129 | **/IISApplications
130 |
131 |
132 | # Node.js modules
133 | node_modules/
134 |
135 | # Python Compile Outputs
136 |
137 | *.pyc
138 |
--------------------------------------------------------------------------------
/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This project has adopted the code of conduct defined by the Contributor Covenant
4 | to clarify expected behavior in our community.
5 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) .NET Foundation and Contributors
4 |
5 | All rights reserved.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # API Docs Sync
2 |
3 | This repo contains two tools that allow porting documentation in two directions:
4 |
5 | - IntelliSense xml files to MS Docs xml files. [Instructions](docs/PortToDocs.md).
6 |
7 | - MS Docs xml files to triple slash comments in source code. [Instructions](docs/PortToTripleSlash.md).
8 |
9 | ## Requirements
10 |
11 | - [.NET 8.0 SDK](https://get.dot.net/)
12 | - A local git clone of a dotnet repo with source code whose APIs live in an API docs repo. Examples:
13 | - [dotnet/runtime](https://github.com/dotnet/runtime)
14 | - [dotnet/winforms](https://github.com/dotnet/winforms)
15 | - [dotnet/wpf](https://github.com/dotnet/wpf)
16 | - [dotnet/wcf](https://github.com/dotnet/wcf)
17 | - A local git clone of the API docs repo where the above project hosts its documentation. For example, all the repos listed above host their documentation in the [dotnet-api-docs repo](https://github.com/dotnet/dotnet-api-docs).
18 |
19 | ## Install as dotnet tools
20 |
21 | To install the two tools as global dotnet tools in your `$PATH`, run the `install-as-tool.ps1` script.
22 |
23 | Documentation for global dotnet tools: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-tool-install
24 |
25 | Remember to update the tool periodically to collect the latest changes. Updating instructions: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-tool-update
26 |
--------------------------------------------------------------------------------
/build.proj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/PortToDocs.md:
--------------------------------------------------------------------------------
1 | # PortToDocs
2 |
3 | This tool ports intellisense xml documentation to API docs.
4 |
5 | The way it works is the following:
6 |
7 | - You specify the source dotnet repo (for example: runtime, winforms, wpf, wcf, etc.).
8 | - You specify the API docs target repo (for example: dotnet-api-docs).
9 | - You specify a list of assemblies to port, and optionally, a list of namespaces and/or types.
10 | - The tool will then find all APIs that match the specified filters, both among the intellisense xml files of the dotnet repo and in the xml files of the API docs repo.
11 | - If an API docs xml item is still undocumented (it has the `To be added.` boilerplate message), then the tool will copy all the documentation it can find for that API in its intellisense xml file, and paste it in the API docs xml item.
12 |
13 | ## Instructions
14 |
15 | 1. Clone and build your source code dotnet repo (for example: runtime, winforms, wpf, wcf, etc.).
16 | 2. Clone the API docs repo (for example: dotnet-api-docs). No need to build it.
17 | 3. Clone this repo.
18 | 4. Run the command to port documentation:
19 |
20 | ```cmd
21 | -Docs
22 | -IntelliSense [,,...,]
23 | -IncludedAssemblies [,,...]
24 | -IncludedNamespaces [,,...,]
25 | -Save true
26 | ```
27 |
28 | Example:
29 |
30 | ```cmd
31 | PortToDocs \
32 | -Docs D:\dotnet-api-docs\xml \
33 | -IntelliSense D:\runtime\artifacts\bin\System.IO.FileSystem\ \
34 | -IncludedAssemblies System.IO.FileSystem \
35 | -IncludedNamespaces System.IO \
36 | -Save true
37 | ```
38 |
39 | To view all the available CLI arguments, run:
40 |
41 | ```cmd
42 | PortToDocs -h
43 | ```
44 |
--------------------------------------------------------------------------------
/install-as-tool.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | Function InstallAsTool
4 | {
5 | Param(
6 | [string]
7 | [ValidateNotNullOrEmpty()]
8 | $APP_NAME
9 | )
10 |
11 | Write-Output "Installing '$APP_NAME' as tool..."
12 |
13 | $ARTIFACTS_DIR = "artifacts/$APP_NAME"
14 | $BUILD_CONFIGURATION = "Release"
15 | $EXE_PROJECT = "src/$APP_NAME/src/app/$APP_NAME.csproj"
16 |
17 | Write-Output "Cleaning..."
18 | $COMMAND="dotnet clean -c $BUILD_CONFIGURATION; Remove-Item -Recurse -ErrorAction Ignore $ARTIFACTS_DIR"
19 | Write-Output $COMMAND
20 | Invoke-Expression -Command $COMMAND
21 |
22 | Write-Output "Packing..."
23 | $COMMAND="dotnet pack -c $BUILD_CONFIGURATION -o $ARTIFACTS_DIR $EXE_PROJECT"
24 | Write-Output $COMMAND
25 | Invoke-Expression -Command $COMMAND
26 |
27 | If ($LASTEXITCODE -ne 0)
28 | {
29 | Write-Output "$APP_NAME will not be installed/upgraded."
30 | Exit
31 | }
32 |
33 | Write-Output "Updating tool..."
34 | $COMMAND="dotnet tool update --global --add-source $ARTIFACTS_DIR $APP_NAME"
35 | Write-Output $COMMAND
36 | Invoke-Expression -Command $COMMAND
37 | }
38 |
39 | $ErrorActionPreference = "Stop"
40 | Push-Location $(Split-Path $MyInvocation.MyCommand.Path)
41 |
42 | InstallAsTool "PortToTripleSlash"
43 | InstallAsTool "PortToDocs"
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Common/src/Log.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 |
6 | namespace ApiDocsSync
7 | {
8 | public static class Log
9 | {
10 | public static void Print(bool endline, ConsoleColor foregroundColor, string format, params object[]? args)
11 | {
12 | ConsoleColor originalColor = Console.ForegroundColor;
13 | Console.ForegroundColor = foregroundColor;
14 |
15 | string msg = args != null ? (args.Length > 0 ? string.Format(format, args) : format) : format;
16 | if (endline)
17 | {
18 | Console.WriteLine(msg);
19 | }
20 | else
21 | {
22 | Console.Write(msg);
23 | }
24 | Console.ForegroundColor = originalColor;
25 | }
26 |
27 | public static void Info(string format)
28 | {
29 | Info(format, null);
30 | }
31 |
32 | public static void Info(string format, params object[]? args)
33 | {
34 | Info(true, format, args);
35 | }
36 |
37 | public static void Info(bool endline, string format, params object[]? args)
38 | {
39 | Print(endline, ConsoleColor.White, format, args);
40 | }
41 |
42 | public static void Success(string format)
43 | {
44 | Success(format, null);
45 | }
46 |
47 | public static void Success(string format, params object[]? args)
48 | {
49 | Success(true, format, args);
50 | }
51 |
52 | public static void Success(bool endline, string format, params object[]? args)
53 | {
54 | Print(endline, ConsoleColor.Green, format, args);
55 | }
56 |
57 | public static void Warning(string format)
58 | {
59 | Warning(format, null);
60 | }
61 |
62 | public static void Warning(string format, params object[]? args)
63 | {
64 | Warning(true, format, args);
65 | }
66 |
67 | public static void Warning(bool endline, string format, params object[]? args)
68 | {
69 | Print(endline, ConsoleColor.Yellow, format, args);
70 | }
71 |
72 | public static void Error(string format)
73 | {
74 | Error(format, null);
75 | }
76 |
77 | public static void Error(string format, params object[]? args)
78 | {
79 | Error(true, format, args);
80 | }
81 |
82 | public static void Error(bool endline, string format, params object[]? args)
83 | {
84 | Print(endline, ConsoleColor.Red, format, args);
85 | }
86 |
87 | public static void Cyan(string format)
88 | {
89 | Cyan(format, null);
90 | }
91 |
92 | public static void Cyan(string format, params object[]? args)
93 | {
94 | Cyan(true, format, args);
95 | }
96 |
97 | public static void Cyan(bool endline, string format, params object[]? args)
98 | {
99 | Print(endline, ConsoleColor.Cyan, format, args);
100 | }
101 |
102 | public static void Magenta(bool endline, string format, params object[]? args)
103 | {
104 | Print(endline, ConsoleColor.Magenta, format, args);
105 | }
106 |
107 | public static void Magenta(string format)
108 | {
109 | Magenta(format, null);
110 | }
111 |
112 | public static void Magenta(string format, params object[]? args)
113 | {
114 | Magenta(true, format, args);
115 | }
116 |
117 | public static void DarkYellow(bool endline, string format, params object[]? args)
118 | {
119 | Print(endline, ConsoleColor.DarkYellow, format, args);
120 | }
121 |
122 | public static void DarkYellow(string format)
123 | {
124 | DarkYellow(format, null);
125 | }
126 |
127 | public static void DarkYellow(string format, params object[]? args)
128 | {
129 | DarkYellow(true, format, args);
130 | }
131 |
132 | public static void Assert(bool condition, string format)
133 | {
134 | Assert(true, condition, format, null);
135 | }
136 |
137 | public static void Assert(bool condition, string format, params object[]? args)
138 | {
139 | Assert(true, condition, format, args);
140 | }
141 |
142 | public static void Assert(bool endline, bool condition, string format, params object[]? args)
143 | {
144 | if (condition)
145 | {
146 | Success(endline, format, args);
147 | }
148 | else
149 | {
150 | string msg = args != null ? string.Format(format, args) : format;
151 | throw new Exception(msg);
152 | }
153 | }
154 |
155 | public static void Line()
156 | {
157 | Print(endline: true, Console.ForegroundColor, "", null);
158 | }
159 |
160 | public delegate void PrintHelpFunction();
161 |
162 | public static void ErrorAndExit(string format, params object[]? args)
163 | {
164 | Error(format, args);
165 | Cyan("Use the -h|-help argument to view the usage instructions.");
166 | Environment.Exit(-1);
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/Common/tests/BasePortTests.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using Xunit.Abstractions;
5 |
6 | namespace ApiDocsSync.Tests
7 | {
8 | public abstract class BasePortTests
9 | {
10 | protected ITestOutputHelper Output { get; private set; }
11 |
12 | public BasePortTests(ITestOutputHelper output) => Output = output;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Common/tests/FileTestData.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.IO;
5 |
6 | namespace ApiDocsSync.Tests
7 | {
8 | internal class FileTestData
9 | {
10 | internal const string TestAssembly = "MyAssembly";
11 | internal const string TestNamespace = "MyNamespace";
12 | internal const string TestType = "MyType";
13 | internal const string DocsDirName = "Docs";
14 |
15 | internal string ExpectedFilePath { get; set; }
16 | internal string ActualFilePath { get; set; }
17 | internal DirectoryInfo DocsDir { get; set; }
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Common/tests/TestDirectory.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.IO;
6 | using Xunit;
7 |
8 | namespace ApiDocsSync.Tests
9 | {
10 | public class TestDirectory : IDisposable
11 | {
12 | private readonly DirectoryInfo DirInfo;
13 |
14 | public string FullPath => DirInfo.FullName;
15 |
16 | public TestDirectory()
17 | {
18 | string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
19 | DirInfo = new DirectoryInfo(path);
20 | DirInfo.Create();
21 | Assert.True(DirInfo.Exists, "Verify root test directory exists.");
22 | }
23 |
24 | public DirectoryInfo CreateSubdirectory(string dirName)
25 | {
26 | return DirInfo.CreateSubdirectory(dirName);
27 | }
28 |
29 | public void Dispose()
30 | {
31 | try
32 | {
33 | DirInfo.Delete(recursive: true);
34 | }
35 | catch
36 | {
37 | }
38 | GC.SuppressFinalize(this);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/PortToDocs/PortToDocs.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32220.68
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortToDocs", "src\app\PortToDocs.csproj", "{E92246CD-548D-4C08-BA43-594663E78100}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libraries", "src\libraries\libraries.csproj", "{87BBF4FD-260C-4AC4-802B-7D2B29629C07}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tests", "tests\tests.csproj", "{81FEFEA4-8FF5-482E-A33D-D3F351D3F7B6}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FCF7315B-C7FA-4D89-96A1-AA9081B16D3B}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {E92246CD-548D-4C08-BA43-594663E78100}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {E92246CD-548D-4C08-BA43-594663E78100}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {E92246CD-548D-4C08-BA43-594663E78100}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {E92246CD-548D-4C08-BA43-594663E78100}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {87BBF4FD-260C-4AC4-802B-7D2B29629C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {87BBF4FD-260C-4AC4-802B-7D2B29629C07}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {87BBF4FD-260C-4AC4-802B-7D2B29629C07}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {87BBF4FD-260C-4AC4-802B-7D2B29629C07}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {81FEFEA4-8FF5-482E-A33D-D3F351D3F7B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {81FEFEA4-8FF5-482E-A33D-D3F351D3F7B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {81FEFEA4-8FF5-482E-A33D-D3F351D3F7B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {81FEFEA4-8FF5-482E-A33D-D3F351D3F7B6}.Release|Any CPU.Build.0 = Release|Any CPU
32 | EndGlobalSection
33 | GlobalSection(SolutionProperties) = preSolution
34 | HideSolutionNode = FALSE
35 | EndGlobalSection
36 | GlobalSection(ExtensibilityGlobals) = postSolution
37 | SolutionGuid = {0AE9A370-CB75-4D51-A4A3-B7ADA38970B8}
38 | EndGlobalSection
39 | EndGlobal
40 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/app/PortToDocs.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace ApiDocsSync.PortToDocs
5 | {
6 | class PortToDocs
7 | {
8 | public static void Main(string[] args)
9 | {
10 | Configuration config = Configuration.GetCLIArguments(args);
11 | ToDocsPorter porter = new(config);
12 | porter.CollectFiles();
13 | porter.Start();
14 | porter.SaveToDisk();
15 | porter.PrintSummary();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/app/PortToDocs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | ApiDocsSync.PortToDocs.PortToDocs
7 | enable
8 | true
9 | true
10 | 1.5
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/APIKind.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace ApiDocsSync.PortToDocs.Docs
5 | {
6 | internal enum APIKind
7 | {
8 | Type,
9 | Member
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsAssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Xml.Linq;
7 |
8 | namespace ApiDocsSync.PortToDocs.Docs
9 | {
10 | internal class DocsAssemblyInfo
11 | {
12 | private readonly XElement XEAssemblyInfo;
13 | public string AssemblyName
14 | {
15 | get
16 | {
17 | return XmlHelper.GetChildElementValue(XEAssemblyInfo, "AssemblyName");
18 | }
19 | }
20 |
21 | private List? _assemblyVersions;
22 | public List AssemblyVersions
23 | {
24 | get
25 | {
26 | if (_assemblyVersions == null)
27 | {
28 | _assemblyVersions = XEAssemblyInfo.Elements("AssemblyVersion").Select(x => XmlHelper.GetNodesInPlainText(x)).ToList();
29 | }
30 | return _assemblyVersions;
31 | }
32 | }
33 |
34 | public DocsAssemblyInfo(XElement xeAssemblyInfo)
35 | {
36 | XEAssemblyInfo = xeAssemblyInfo;
37 | }
38 |
39 | public override string ToString() => AssemblyName;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsAttribute.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | internal class DocsAttribute
9 | {
10 | private readonly XElement XEAttribute;
11 |
12 | public string FrameworkAlternate
13 | {
14 | get
15 | {
16 | return XmlHelper.GetAttributeValue(XEAttribute, "FrameworkAlternate");
17 | }
18 | }
19 | public string AttributeName
20 | {
21 | get
22 | {
23 | return XmlHelper.GetChildElementValue(XEAttribute, "AttributeName");
24 | }
25 | }
26 |
27 | public DocsAttribute(XElement xeAttribute)
28 | {
29 | XEAttribute = xeAttribute;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsException.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Xml.Linq;
7 |
8 | namespace ApiDocsSync.PortToDocs.Docs
9 | {
10 | internal class DocsException
11 | {
12 | private readonly XElement XEException;
13 |
14 | public IDocsAPI ParentAPI
15 | {
16 | get; private set;
17 | }
18 |
19 | public string Cref => XmlHelper.GetAttributeValue(XEException, "cref");
20 |
21 | public string Value
22 | {
23 | get => XmlHelper.GetNodesInPlainText(XEException);
24 | private set => XmlHelper.SaveFormattedAsXml(XEException, value);
25 | }
26 |
27 | public string OriginalValue { get; private set; }
28 |
29 | public DocsException(IDocsAPI parentAPI, XElement xException)
30 | {
31 | ParentAPI = parentAPI;
32 | XEException = xException;
33 | OriginalValue = Value;
34 | }
35 |
36 | public void AppendException(string toAppend)
37 | {
38 | XmlHelper.AppendFormattedAsXml(XEException, $"\n\n-or-\n\n{toAppend}", removeUndesiredEndlines: false);
39 | ParentAPI.Changed = true;
40 | }
41 |
42 | public bool WordCountCollidesAboveThreshold(string intelliSenseXmlValue, int threshold)
43 | {
44 | Dictionary hashIntelliSenseXml = GetHash(intelliSenseXmlValue);
45 | Dictionary hashDocs = GetHash(Value);
46 |
47 | int collisions = 0;
48 | // Iterate all the words of the IntelliSense xml exception string
49 | foreach (KeyValuePair word in hashIntelliSenseXml)
50 | {
51 | // Check if the existing Docs string contained that word
52 | if (hashDocs.ContainsKey(word.Key))
53 | {
54 | // If the total found in Docs is >= than the total found in IntelliSense xml
55 | // then consider it a collision
56 | if (hashDocs[word.Key] >= word.Value)
57 | {
58 | collisions++;
59 | }
60 | }
61 | }
62 |
63 | // If the number of word collisions is above the threshold, it probably means
64 | // that part of the original TS string was included in the Docs string
65 | double collisionPercentage = (collisions * 100 / (double)hashIntelliSenseXml.Count);
66 | return collisionPercentage >= threshold;
67 | }
68 |
69 | public override string ToString()
70 | {
71 | return $"{Cref} - {Value}";
72 | }
73 |
74 | // Gets a dictionary with the count of each character found in the string.
75 | private Dictionary GetHash(string value)
76 | {
77 | Dictionary hash = new Dictionary();
78 | string[] words = value.Split(new char[] { ' ', '\'', '"', '\r', '\n', '.', ',', ';', ':' }, StringSplitOptions.RemoveEmptyEntries);
79 |
80 | foreach (string word in words)
81 | {
82 | if (hash.ContainsKey(word))
83 | {
84 | hash[word]++;
85 | }
86 | else
87 | {
88 | hash.Add(word, 1);
89 | }
90 | }
91 | return hash;
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsMember.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Xml.Linq;
8 |
9 | namespace ApiDocsSync.PortToDocs.Docs
10 | {
11 | internal class DocsMember : DocsAPI
12 | {
13 | private string? _memberName;
14 | private List? _memberSignatures;
15 | private List? _exceptions;
16 |
17 | public DocsMember(string filePath, DocsType parentType, XElement xeMember)
18 | : base(xeMember)
19 | {
20 | FilePath = filePath;
21 | ParentType = parentType;
22 | AssemblyInfos.AddRange(XERoot.Elements("AssemblyInfo").Select(x => new DocsAssemblyInfo(x)));
23 | }
24 |
25 | public DocsType ParentType { get; private set; }
26 |
27 | public override bool Changed
28 | {
29 | get => ParentType.Changed;
30 | set => ParentType.Changed |= value;
31 | }
32 | public bool IsProperty => MemberType == "Property";
33 |
34 | public bool IsMethod => MemberType == "Method";
35 |
36 | public string MemberName
37 | {
38 | get
39 | {
40 | if (_memberName == null)
41 | {
42 | _memberName = XmlHelper.GetAttributeValue(XERoot, "MemberName");
43 | }
44 | return _memberName;
45 | }
46 | }
47 |
48 | public List MemberSignatures
49 | {
50 | get
51 | {
52 | if (_memberSignatures == null)
53 | {
54 | _memberSignatures = XERoot.Elements("MemberSignature").Select(x => new DocsMemberSignature(x)).ToList();
55 | }
56 | return _memberSignatures;
57 | }
58 | }
59 |
60 | public string MemberType
61 | {
62 | get
63 | {
64 | return XmlHelper.GetChildElementValue(XERoot, "MemberType");
65 | }
66 | }
67 |
68 | public string ImplementsInterfaceMember
69 | {
70 | get
71 | {
72 | XElement? xeImplements = XERoot.Element("Implements");
73 | return (xeImplements != null) ? XmlHelper.GetChildElementValue(xeImplements, "InterfaceMember") : string.Empty;
74 | }
75 | }
76 |
77 | public override string ReturnType
78 | {
79 | get
80 | {
81 | XElement? xeReturnValue = XERoot.Element("ReturnValue");
82 | if (xeReturnValue != null)
83 | {
84 | return XmlHelper.GetChildElementValue(xeReturnValue, "ReturnType");
85 | }
86 | return string.Empty;
87 | }
88 | }
89 |
90 | public override string Returns
91 | {
92 | get
93 | {
94 | return (ReturnType != "System.Void") ? GetNodesInPlainText("returns") : string.Empty;
95 | }
96 | set
97 | {
98 | if (ReturnType != "System.Void")
99 | {
100 | SaveFormattedAsXml("returns", value, addIfMissing: false);
101 | }
102 | else
103 | {
104 | Log.Warning($"Attempted to save a returns item for a method that returns System.Void: {DocId}");
105 | }
106 | }
107 | }
108 |
109 | public override string Summary
110 | {
111 | get
112 | {
113 | return GetNodesInPlainText("summary");
114 | }
115 | set
116 | {
117 | SaveFormattedAsXml("summary", value, addIfMissing: true);
118 | }
119 | }
120 |
121 | public override string Remarks
122 | {
123 | get
124 | {
125 | return GetNodesInPlainText("remarks");
126 | }
127 | set
128 | {
129 | SaveAsIs("remarks", value, addIfMissing: !value.IsDocsEmpty());
130 | }
131 | }
132 |
133 | public string Value
134 | {
135 | get
136 | {
137 | return (IsProperty) ? GetNodesInPlainText("value") : string.Empty;
138 | }
139 | set
140 | {
141 | if (IsProperty)
142 | {
143 | SaveFormattedAsXml("value", value, addIfMissing: true);
144 | }
145 | else
146 | {
147 | Log.Warning($"Attempted to save a value element for an API that is not a property: {DocId}");
148 | }
149 | }
150 | }
151 |
152 | public List Exceptions
153 | {
154 | get
155 | {
156 | if (_exceptions == null)
157 | {
158 | if (Docs != null)
159 | {
160 | _exceptions = Docs.Elements("exception").Select(x => new DocsException(this, x)).ToList();
161 | }
162 | else
163 | {
164 | _exceptions = new List();
165 | }
166 | }
167 | return _exceptions;
168 | }
169 | }
170 |
171 | public override string ToString()
172 | {
173 | return DocId;
174 | }
175 |
176 | public DocsException AddException(string cref, string value)
177 | {
178 | XElement exception = new XElement("exception");
179 | exception.SetAttributeValue("cref", cref);
180 | XmlHelper.SaveFormattedAsXml(exception, value, removeUndesiredEndlines: false);
181 | Docs.Add(exception);
182 | Changed = true;
183 | return new DocsException(this, exception);
184 | }
185 |
186 | protected override string GetApiSignatureDocId()
187 | {
188 | DocsMemberSignature? dts = MemberSignatures.FirstOrDefault(x => x.Language == "DocId");
189 | if (dts == null)
190 | {
191 | throw new FormatException($"DocId TypeSignature not found for {MemberName}");
192 | }
193 | return dts.Value;
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsMemberSignature.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | internal class DocsMemberSignature
9 | {
10 | private readonly XElement XEMemberSignature;
11 |
12 | public string Language
13 | {
14 | get
15 | {
16 | return XmlHelper.GetAttributeValue(XEMemberSignature, "Language");
17 | }
18 | }
19 |
20 | public string Value
21 | {
22 | get
23 | {
24 | return XmlHelper.GetAttributeValue(XEMemberSignature, "Value");
25 | }
26 | }
27 |
28 | public DocsMemberSignature(XElement xeMemberSignature)
29 | {
30 | XEMemberSignature = xeMemberSignature;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsParam.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | internal class DocsParam
9 | {
10 | private readonly XElement XEDocsParam;
11 | public IDocsAPI ParentAPI
12 | {
13 | get; private set;
14 | }
15 | public string Name
16 | {
17 | get
18 | {
19 | return XmlHelper.GetAttributeValue(XEDocsParam, "name");
20 | }
21 | }
22 | public string Value
23 | {
24 | get
25 | {
26 | return XmlHelper.GetNodesInPlainText(XEDocsParam);
27 | }
28 | set
29 | {
30 | XmlHelper.SaveFormattedAsXml(XEDocsParam, value);
31 | ParentAPI.Changed = true;
32 | }
33 | }
34 | public DocsParam(IDocsAPI parentAPI, XElement xeDocsParam)
35 | {
36 | ParentAPI = parentAPI;
37 | XEDocsParam = xeDocsParam;
38 | }
39 | public override string ToString()
40 | {
41 | return Name;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsParameter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | internal class DocsParameter
9 | {
10 | private readonly XElement XEParameter;
11 | public string Name
12 | {
13 | get
14 | {
15 | return XmlHelper.GetAttributeValue(XEParameter, "Name");
16 | }
17 | }
18 | public string Type
19 | {
20 | get
21 | {
22 | return XmlHelper.GetAttributeValue(XEParameter, "Type");
23 | }
24 | }
25 | public DocsParameter(XElement xeParameter)
26 | {
27 | XEParameter = xeParameter;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsRelated.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | internal class DocsRelated
9 | {
10 | private readonly XElement XERelatedArticle;
11 |
12 | public IDocsAPI ParentAPI
13 | {
14 | get; private set;
15 | }
16 |
17 | public string ArticleType => XmlHelper.GetAttributeValue(XERelatedArticle, "type");
18 |
19 | public string Href => XmlHelper.GetAttributeValue(XERelatedArticle, "href");
20 |
21 | public string Value
22 | {
23 | get => XmlHelper.GetNodesInPlainText(XERelatedArticle);
24 | set
25 | {
26 | XmlHelper.SaveFormattedAsXml(XERelatedArticle, value);
27 | ParentAPI.Changed = true;
28 | }
29 | }
30 |
31 | public DocsRelated(IDocsAPI parentAPI, XElement xeRelatedArticle)
32 | {
33 | ParentAPI = parentAPI;
34 | XERelatedArticle = xeRelatedArticle;
35 | }
36 |
37 | public override string ToString()
38 | {
39 | return Value;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsSeeAlso.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs;
7 |
8 | internal class DocsSeeAlso
9 | {
10 | private readonly XElement XESeeAlso;
11 |
12 | public IDocsAPI ParentAPI
13 | {
14 | get; private set;
15 | }
16 |
17 | public string Cref => XmlHelper.GetAttributeValue(XESeeAlso, "cref");
18 |
19 | public DocsSeeAlso(IDocsAPI parentAPI, XElement xSeeAlso)
20 | {
21 | ParentAPI = parentAPI;
22 | XESeeAlso = xSeeAlso;
23 | }
24 |
25 | public override string ToString() => $"seealso cref={Cref}";
26 | }
27 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsType.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Xml.Linq;
9 |
10 | namespace ApiDocsSync.PortToDocs.Docs
11 | {
12 | ///
13 | /// Represents the root xml element (unique) of a Docs xml file, called Type.
14 | ///
15 | internal class DocsType : DocsAPI
16 | {
17 | private string? _typeName;
18 | private string? _name;
19 | private string? _fullName;
20 | private string? _namespace;
21 | private string? _baseTypeName;
22 | private List? _interfaceNames;
23 | private List? _attributes;
24 | private List? _typesSignatures;
25 |
26 | public DocsType(string filePath, XDocument xDoc, XElement xeRoot, Encoding encoding)
27 | : base(xeRoot)
28 | {
29 | FilePath = filePath;
30 | XDoc = xDoc;
31 | FileEncoding = encoding;
32 | AssemblyInfos.AddRange(XERoot.Elements("AssemblyInfo").Select(x => new DocsAssemblyInfo(x)));
33 | }
34 |
35 | public XDocument XDoc { get; set; }
36 |
37 | public override bool Changed { get; set; }
38 |
39 | public Encoding FileEncoding { get; internal set; }
40 |
41 | public string TypeName
42 | {
43 | get
44 | {
45 | if (_typeName == null)
46 | {
47 | // DocId uses ` notation for generic types, but it uses . for nested types
48 | // Name uses + for nested types, but it uses <T> for generic types
49 | // We need ` notation for generic types and + notation for nested types
50 | // Only filename gives us that format, but we have to prepend the namespace
51 | if (DocId.Contains('`') || Name.Contains('+'))
52 | {
53 | _typeName = Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(FilePath);
54 | }
55 | else
56 | {
57 | _typeName = FullName;
58 | }
59 | }
60 | return _typeName;
61 | }
62 | }
63 |
64 | public string Name
65 | {
66 | get
67 | {
68 | if (_name == null)
69 | {
70 | _name = XmlHelper.GetAttributeValue(XERoot, "Name");
71 | }
72 | return _name;
73 | }
74 | }
75 |
76 | public string FullName
77 | {
78 | get
79 | {
80 | if (_fullName == null)
81 | {
82 | _fullName = XmlHelper.GetAttributeValue(XERoot, "FullName");
83 | }
84 | return _fullName;
85 | }
86 | }
87 |
88 | public string Namespace
89 | {
90 | get
91 | {
92 | if (_namespace == null)
93 | {
94 | int lastDotPosition = FullName.LastIndexOf('.');
95 | _namespace = lastDotPosition < 0 ? FullName : FullName.Substring(0, lastDotPosition);
96 | }
97 | return _namespace;
98 | }
99 | }
100 |
101 | public List TypeSignatures
102 | {
103 | get
104 | {
105 | if (_typesSignatures == null)
106 | {
107 | _typesSignatures = XERoot.Elements("TypeSignature").Select(x => new DocsTypeSignature(x)).ToList();
108 | }
109 | return _typesSignatures;
110 | }
111 | }
112 |
113 | public XElement? Base
114 | {
115 | get
116 | {
117 | return XERoot.Element("Base");
118 | }
119 | }
120 |
121 | public string BaseTypeName
122 | {
123 | get
124 | {
125 | if (Base == null)
126 | {
127 | _baseTypeName = string.Empty;
128 | }
129 | else if (_baseTypeName == null)
130 | {
131 | _baseTypeName = XmlHelper.GetChildElementValue(Base, "BaseTypeName");
132 | }
133 | return _baseTypeName;
134 | }
135 | }
136 |
137 | public XElement? Interfaces
138 | {
139 | get
140 | {
141 | return XERoot.Element("Interfaces");
142 | }
143 | }
144 |
145 | public List InterfaceNames
146 | {
147 | get
148 | {
149 | if (Interfaces == null)
150 | {
151 | _interfaceNames = new List();
152 | }
153 | else if (_interfaceNames == null)
154 | {
155 | _interfaceNames = Interfaces.Elements("Interface").Select(x => XmlHelper.GetChildElementValue(x, "InterfaceName")).ToList();
156 | }
157 | return _interfaceNames;
158 | }
159 | }
160 |
161 | public List Attributes
162 | {
163 | get
164 | {
165 | if (_attributes == null)
166 | {
167 | XElement? e = XERoot.Element("Attributes");
168 | if (e == null)
169 | {
170 | _attributes = new();
171 | }
172 | else
173 | {
174 | _attributes = (e != null) ? e.Elements("Attribute").Select(x => new DocsAttribute(x)).ToList() : new List();
175 | }
176 | }
177 | return _attributes;
178 | }
179 | }
180 |
181 | public override string Summary
182 | {
183 | get
184 | {
185 | return GetNodesInPlainText("summary");
186 | }
187 | set
188 | {
189 | SaveFormattedAsXml("summary", value, addIfMissing: true);
190 | }
191 | }
192 |
193 | ///
194 | /// Only available when the type is a delegate.
195 | ///
196 | public override string ReturnType
197 | {
198 | get
199 | {
200 | XElement? xeReturnValue = XERoot.Element("ReturnValue");
201 | if (xeReturnValue != null)
202 | {
203 | return XmlHelper.GetChildElementValue(xeReturnValue, "ReturnType");
204 | }
205 | return string.Empty;
206 | }
207 | }
208 |
209 | ///
210 | /// Only available when the type is a delegate.
211 | ///
212 | public override string Returns
213 | {
214 | get
215 | {
216 | return (ReturnType != "System.Void") ? GetNodesInPlainText("returns") : string.Empty;
217 | }
218 | set
219 | {
220 | if (ReturnType != "System.Void")
221 | {
222 | SaveFormattedAsXml("returns", value, addIfMissing: false);
223 | }
224 | else
225 | {
226 | Log.Warning($"Attempted to save a returns item for a method that returns System.Void: {DocId}");
227 | }
228 | }
229 | }
230 |
231 | public override string Remarks
232 | {
233 | get
234 | {
235 | return GetNodesInPlainText("remarks");
236 | }
237 | set
238 | {
239 | SaveAsIs("remarks", value, addIfMissing: !value.IsDocsEmpty());
240 | }
241 | }
242 |
243 | public override string ToString()
244 | {
245 | return FullName;
246 | }
247 |
248 | protected override string GetApiSignatureDocId()
249 | {
250 | DocsTypeSignature? dts = TypeSignatures.FirstOrDefault(x => x.Language == "DocId");
251 | if (dts == null)
252 | {
253 | throw new FormatException($"DocId TypeSignature not found for {FullName}");
254 | }
255 | return dts.Value;
256 | }
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsTypeParam.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | ///
9 | /// Each one of these typeparam objects live inside the Docs section inside the Member object.
10 | ///
11 | internal class DocsTypeParam
12 | {
13 | private readonly XElement XEDocsTypeParam;
14 | public IDocsAPI ParentAPI
15 | {
16 | get; private set;
17 | }
18 |
19 | public string Name
20 | {
21 | get
22 | {
23 | return XmlHelper.GetAttributeValue(XEDocsTypeParam, "name");
24 | }
25 | }
26 |
27 | public string Value
28 | {
29 | get
30 | {
31 | return XmlHelper.GetNodesInPlainText(XEDocsTypeParam);
32 | }
33 | set
34 | {
35 | XmlHelper.SaveFormattedAsXml(XEDocsTypeParam, value);
36 | ParentAPI.Changed = true;
37 | }
38 | }
39 |
40 | public DocsTypeParam(IDocsAPI parentAPI, XElement xeDocsTypeParam)
41 | {
42 | ParentAPI = parentAPI;
43 | XEDocsTypeParam = xeDocsTypeParam;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsTypeParameter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Xml.Linq;
7 |
8 | namespace ApiDocsSync.PortToDocs.Docs
9 | {
10 | ///
11 | /// Each one of these TypeParameter objects islocated inside the TypeParameters section inside the Member.
12 | ///
13 | internal class DocsTypeParameter
14 | {
15 | private readonly XElement XETypeParameter;
16 | public string Name
17 | {
18 | get
19 | {
20 | return XmlHelper.GetAttributeValue(XETypeParameter, "Name");
21 | }
22 | }
23 | private XElement? Constraints
24 | {
25 | get
26 | {
27 | return XETypeParameter.Element("Constraints");
28 | }
29 | }
30 | private List? _constraintsParameterAttributes;
31 | public List ConstraintsParameterAttributes
32 | {
33 | get
34 | {
35 | if (_constraintsParameterAttributes == null)
36 | {
37 | if (Constraints != null)
38 | {
39 | _constraintsParameterAttributes = Constraints.Elements("ParameterAttribute").Select(x => XmlHelper.GetNodesInPlainText(x)).ToList();
40 | }
41 | else
42 | {
43 | _constraintsParameterAttributes = new List();
44 | }
45 | }
46 | return _constraintsParameterAttributes;
47 | }
48 | }
49 |
50 | public string ConstraintsBaseTypeName
51 | {
52 | get
53 | {
54 | if (Constraints != null)
55 | {
56 | return XmlHelper.GetChildElementValue(Constraints, "BaseTypeName");
57 | }
58 | return string.Empty;
59 | }
60 | }
61 |
62 | public DocsTypeParameter(XElement xeTypeParameter)
63 | {
64 | XETypeParameter = xeTypeParameter;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/DocsTypeSignature.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.Docs
7 | {
8 | internal class DocsTypeSignature
9 | {
10 | private readonly XElement XETypeSignature;
11 |
12 | public string Language
13 | {
14 | get
15 | {
16 | return XmlHelper.GetAttributeValue(XETypeSignature, "Language");
17 | }
18 | }
19 |
20 | public string Value
21 | {
22 | get
23 | {
24 | return XmlHelper.GetAttributeValue(XETypeSignature, "Value");
25 | }
26 | }
27 |
28 | public DocsTypeSignature(XElement xeTypeSignature)
29 | {
30 | XETypeSignature = xeTypeSignature;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Docs/IDocsAPI.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Xml.Linq;
6 |
7 | namespace ApiDocsSync.PortToDocs.Docs
8 | {
9 | internal interface IDocsAPI
10 | {
11 | public abstract APIKind Kind { get; }
12 | public abstract bool IsUndocumented { get; }
13 | public abstract bool InheritDoc { get; }
14 | public abstract bool Changed { get; set; }
15 | public abstract string FilePath { get; set; }
16 | public abstract string DocId { get; }
17 | public abstract string DocIdUnprefixed { get; }
18 | public abstract string InheritDocCref { get; }
19 | public abstract XElement Docs { get; }
20 | public abstract List Parameters { get; }
21 | public abstract List Params { get; }
22 | public abstract List TypeParameters { get; }
23 | public abstract List TypeParams { get; }
24 | public abstract string Summary { get; set; }
25 | public abstract string ReturnType { get; }
26 | public abstract string Returns { get; set; }
27 | public abstract string Remarks { get; set; }
28 | public abstract DocsParam SaveParam(XElement xeCoreFXParam);
29 | public abstract DocsTypeParam AddTypeParam(string name, string value);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/Extensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace ApiDocsSync.PortToDocs
5 | {
6 | // Provides generic extension methods.
7 | internal static class Extensions
8 | {
9 | // Removes the specified substrings from another string
10 | public static string RemoveSubstrings(this string oldString, params string[] stringsToRemove)
11 | {
12 | string newString = oldString;
13 | foreach (string toRemove in stringsToRemove)
14 | {
15 | if (newString.Contains(toRemove))
16 | {
17 | newString = newString.Replace(toRemove, string.Empty);
18 | }
19 | }
20 | return newString;
21 | }
22 |
23 | public static bool ContainsStrings(this string text, string[] strings)
24 | {
25 | foreach (string str in strings)
26 | {
27 | if (text.Contains(str))
28 | {
29 | return true;
30 | }
31 | }
32 |
33 | return false;
34 | }
35 |
36 | // Some API DocIDs with types contain "{" and "}" to enclose the typeparam, which causes
37 | // an exception to be thrown when trying to embed the string in a formatted string.
38 | public static string AsEscapedDocId(this string docId) =>
39 | docId
40 | .Replace("{", "{{")
41 | .Replace("}", "}}")
42 | .Replace("<", "{{")
43 | .Replace(">", "}}")
44 | .Replace("<", "{{")
45 | .Replace(">", "}}");
46 |
47 | // Checks if the passed string is considered "empty" according to the Docs repo rules.
48 | public static bool IsDocsEmpty(this string? s) =>
49 | string.IsNullOrWhiteSpace(s) || s == Configuration.ToBeAdded;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlCommentsContainer.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics.CodeAnalysis;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Xml.Linq;
10 |
11 | /*
12 | The IntelliSense xml comments files for...
13 | A) Libraries - They are saved in:
14 | /artifacts/bin//net-/.xml
15 | B) coreclr - They saved in:
16 | artifacts/bin/coreclr/../IL/System.Private.CoreLib.xml
17 |
18 | Each xml file represents a namespace.
19 | The files are structured like this:
20 |
21 | root
22 | assembly (1)
23 | name (1)
24 | members (many)
25 | member(0:M)
26 | summary (0:1)
27 | param (0:M)
28 | returns (0:1)
29 | exception (0:M)
30 | Note: The exception value may contain xml nodes.
31 | */
32 | namespace ApiDocsSync.PortToDocs.IntelliSenseXml
33 | {
34 | internal class IntelliSenseXmlCommentsContainer
35 | {
36 | private Configuration Config { get; set; }
37 |
38 | // The IntelliSense xml files do not separate types from members, like ECMA xml files do - Everything is a member.
39 | public Dictionary Members = new();
40 |
41 | public IntelliSenseXmlCommentsContainer(Configuration config) => Config = config;
42 |
43 | internal IEnumerable EnumerateFiles()
44 | {
45 | foreach (DirectoryInfo dirInfo in Config.DirsIntelliSense)
46 | {
47 | // 1) Find all the xml files inside all the subdirectories inside the IntelliSense xml directory
48 | foreach (DirectoryInfo subDir in dirInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly))
49 | {
50 | if (!Configuration.ForbiddenBinSubdirectories.Contains(subDir.Name) &&
51 | !subDir.Name.EndsWith(".Tests") &&
52 | !subDir.Name.StartsWith("microsoft.netcore.app.runtime."))
53 | {
54 | foreach (FileInfo fileInfo in subDir.EnumerateFiles("*.xml", SearchOption.AllDirectories))
55 | {
56 | yield return fileInfo;
57 | }
58 | }
59 | }
60 |
61 | // 2) Find all the xml files in the top directory
62 | foreach (FileInfo fileInfo in dirInfo.EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly))
63 | {
64 | yield return fileInfo;
65 | }
66 | }
67 | }
68 |
69 | internal void LoadIntellisenseXmlFile(XDocument xDoc, string filePath)
70 | {
71 | if (!TryGetAssemblyName(xDoc, filePath, out string? assembly))
72 | {
73 | return;
74 | }
75 |
76 | int totalAdded = 0;
77 | if (XmlHelper.TryGetChildElement(xDoc.Root!, "members", out XElement? xeMembers) && xeMembers != null)
78 | {
79 | foreach (XElement xeMember in xeMembers.Elements("member"))
80 | {
81 | IntelliSenseXmlMember member = new(xeMember, assembly);
82 |
83 | if (Config.IncludedAssemblies.Any(included => member.Assembly.StartsWith(included, StringComparison.InvariantCultureIgnoreCase)) &&
84 | !Config.ExcludedAssemblies.Any(excluded => member.Assembly.StartsWith(excluded, StringComparison.InvariantCultureIgnoreCase)))
85 | {
86 | // No namespaces provided by the user means they want to port everything from that assembly
87 | if (!Config.IncludedNamespaces.Any() ||
88 | (Config.IncludedNamespaces.Any(included => member.Namespace.StartsWith(included, StringComparison.InvariantCultureIgnoreCase)) &&
89 | !Config.ExcludedNamespaces.Any(excluded => member.Namespace.StartsWith(excluded, StringComparison.InvariantCultureIgnoreCase))))
90 | {
91 | totalAdded++;
92 | Members.TryAdd(member.Name, member); // is it OK this encounters duplicates?
93 | }
94 | }
95 | }
96 | }
97 |
98 | if (totalAdded > 0)
99 | {
100 | Log.Success($"{totalAdded} IntelliSense xml member(s) added from xml file '{filePath}'");
101 | }
102 | }
103 |
104 | // Verifies the file is properly formed while attempting to retrieve the assembly name.
105 | private static bool TryGetAssemblyName(XDocument? xDoc, string fileName, [NotNullWhen(returnValue: true)] out string? assembly)
106 | {
107 | assembly = null;
108 |
109 | if (xDoc == null)
110 | {
111 | Log.Error($"The XDocument was null: {fileName}");
112 | return false;
113 | }
114 |
115 | if (xDoc.Root == null)
116 | {
117 | Log.Error($"The IntelliSense xml file does not contain a root element: {fileName}");
118 | return false;
119 | }
120 |
121 | if (xDoc.Root.Name == "linker" || xDoc.Root.Name == "FileList")
122 | {
123 | // This is a linker suppression file or a framework list
124 | return false;
125 | }
126 |
127 | if (xDoc.Root.Name != "doc")
128 | {
129 | Log.Error($"The IntelliSense xml file does not contain a doc element: {fileName}");
130 | return false;
131 | }
132 |
133 | if (!xDoc.Root.HasElements)
134 | {
135 | Log.Error($"The IntelliSense xml file doc element not have any children: {fileName}");
136 | return false;
137 | }
138 |
139 | if (xDoc.Root.Elements("assembly").Count() != 1)
140 | {
141 | Log.Error($"The IntelliSense xml file does not contain exactly 1 'assembly' element: {fileName}");
142 | return false;
143 | }
144 |
145 | if (xDoc.Root.Elements("members").Count() != 1)
146 | {
147 | Log.Error($"The IntelliSense xml file does not contain exactly 1 'members' element: {fileName}");
148 | return false;
149 | }
150 |
151 | XElement? xAssembly = xDoc.Root.Element("assembly");
152 | if (xAssembly == null)
153 | {
154 | Log.Error($"The assembly xElement is null: {fileName}");
155 | return false;
156 | }
157 | if (xAssembly.Elements("name").Count() != 1)
158 | {
159 | Log.Error($"The IntelliSense xml file assembly element does not contain exactly 1 'name' element: {fileName}");
160 | return false;
161 | }
162 |
163 | assembly = xAssembly.Element("name")!.Value;
164 | if (string.IsNullOrEmpty(assembly))
165 | {
166 | Log.Error($"The IntelliSense xml file assembly string is null or empty: {fileName}");
167 | return false;
168 | }
169 |
170 | // The System.Private.CoreLib xml file should be mapped to the System.Runtime assembly
171 | if (assembly.ToUpperInvariant() == "SYSTEM.PRIVATE.CORELIB")
172 | {
173 | assembly = "System.Runtime";
174 | }
175 |
176 | return true;
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlException.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.IntelliSenseXml
7 | {
8 | internal class IntelliSenseXmlException
9 | {
10 | public XElement XEException
11 | {
12 | get;
13 | private set;
14 | }
15 |
16 | private string _cref = string.Empty;
17 | public string Cref
18 | {
19 | get
20 | {
21 | if (string.IsNullOrWhiteSpace(_cref))
22 | {
23 | _cref = XmlHelper.GetAttributeValue(XEException, "cref");
24 | }
25 | return _cref;
26 | }
27 | }
28 |
29 | private string _value = string.Empty;
30 | public string Value
31 | {
32 | get
33 | {
34 | if (string.IsNullOrWhiteSpace(_value))
35 | {
36 | _value = XmlHelper.GetNodesInPlainText(XEException);
37 | }
38 | return _value;
39 | }
40 | }
41 |
42 | public IntelliSenseXmlException(XElement xeException)
43 | {
44 | XEException = xeException;
45 | }
46 |
47 | public override string ToString()
48 | {
49 | return $"{Cref} - {Value}";
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlMember.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Xml.Linq;
8 |
9 | namespace ApiDocsSync.PortToDocs.IntelliSenseXml
10 | {
11 | internal class IntelliSenseXmlMember
12 | {
13 | private readonly XElement XEMember;
14 |
15 | private XElement? _xInheritDoc = null;
16 | private XElement? XInheritDoc => _xInheritDoc ??= XEMember.Elements("inheritdoc").FirstOrDefault();
17 |
18 | public string Assembly { get; private set; }
19 |
20 | private string? _inheritDocCref = null;
21 | public string InheritDocCref
22 | {
23 | get
24 | {
25 | if (_inheritDocCref == null)
26 | {
27 | _inheritDocCref = string.Empty;
28 | if (InheritDoc && XInheritDoc != null)
29 | {
30 | XAttribute? xInheritDocCref = XInheritDoc.Attribute("cref");
31 | if (xInheritDocCref != null)
32 | {
33 | _inheritDocCref = xInheritDocCref.Value;
34 | }
35 | }
36 | }
37 | return _inheritDocCref;
38 | }
39 | }
40 |
41 | public bool InheritDoc
42 | {
43 | get => XInheritDoc != null;
44 | }
45 |
46 | private string _namespace = string.Empty;
47 | public string Namespace
48 | {
49 | get
50 | {
51 | if (string.IsNullOrWhiteSpace(_namespace))
52 | {
53 | string[] splittedParenthesis = Name.Split('(', StringSplitOptions.RemoveEmptyEntries);
54 | string withoutParenthesisAndPrefix = splittedParenthesis[0][2..]; // Exclude the "X:" prefix
55 | string[] splittedDots = withoutParenthesisAndPrefix.Split('.', StringSplitOptions.RemoveEmptyEntries);
56 |
57 | _namespace = string.Join('.', splittedDots.Take(splittedDots.Length - 1));
58 | }
59 |
60 | return _namespace;
61 | }
62 | }
63 |
64 | private string? _name;
65 |
66 | ///
67 | /// The API DocId.
68 | ///
69 | public string Name => _name ??= XmlHelper.GetAttributeValue(XEMember, "name");
70 |
71 | private List? _params;
72 | public List Params
73 | {
74 | get
75 | {
76 | if (_params == null)
77 | {
78 | _params = XEMember.Elements("param").Select(x => new IntelliSenseXmlParam(x)).ToList();
79 | }
80 | return _params;
81 | }
82 | }
83 |
84 | private List? _typeParams;
85 | public List TypeParams
86 | {
87 | get
88 | {
89 | if (_typeParams == null)
90 | {
91 | _typeParams = XEMember.Elements("typeparam").Select(x => new IntelliSenseXmlTypeParam(x)).ToList();
92 | }
93 | return _typeParams;
94 | }
95 | }
96 |
97 | private List? _exceptions;
98 | public IEnumerable Exceptions
99 | {
100 | get
101 | {
102 | if (_exceptions == null)
103 | {
104 | _exceptions = XEMember.Elements("exception").Select(x => new IntelliSenseXmlException(x)).ToList();
105 | }
106 | return _exceptions;
107 | }
108 | }
109 |
110 | private List? _seeAlsos;
111 | public IEnumerable SeeAlsos
112 | {
113 | get
114 | {
115 | if (_seeAlsos == null)
116 | {
117 | _seeAlsos = XEMember.Elements("seealso").Select(x => new IntelliSenseXmlSeeAlso(x)).ToList();
118 | }
119 | return _seeAlsos;
120 | }
121 | }
122 |
123 | private string? _summary;
124 | public string Summary
125 | {
126 | get
127 | {
128 | if (_summary == null)
129 | {
130 | XElement? xElement = XEMember.Element("summary");
131 | _summary = (xElement != null) ? XmlHelper.GetNodesInPlainText(xElement) : string.Empty;
132 | _summary = XmlHelper.ReplaceSeeAlsos(_summary);
133 | }
134 | return _summary;
135 | }
136 | }
137 |
138 | public string? _value;
139 | public string Value
140 | {
141 | get
142 | {
143 | if (_value == null)
144 | {
145 | XElement? xElement = XEMember.Element("value");
146 | _value = (xElement != null) ? XmlHelper.GetNodesInPlainText(xElement) : string.Empty;
147 | }
148 | return _value;
149 | }
150 | }
151 |
152 | private string? _returns;
153 | public string Returns
154 | {
155 | get
156 | {
157 | if (_returns == null)
158 | {
159 | XElement? xElement = XEMember.Element("returns");
160 | _returns = (xElement != null) ? XmlHelper.GetNodesInPlainText(xElement) : string.Empty;
161 | }
162 | return _returns;
163 | }
164 | }
165 |
166 | private string? _remarks;
167 | public string Remarks
168 | {
169 | get
170 | {
171 | if (_remarks == null)
172 | {
173 | XElement? xElement = XEMember.Element("remarks");
174 | _remarks = (xElement != null) ? XmlHelper.GetNodesInPlainText(xElement) : string.Empty;
175 | }
176 | return _remarks;
177 | }
178 | }
179 |
180 | public IntelliSenseXmlMember(XElement xeMember, string assembly)
181 | {
182 | if (string.IsNullOrEmpty(assembly))
183 | {
184 | throw new ArgumentNullException(nameof(assembly));
185 | }
186 |
187 | XEMember = xeMember ?? throw new ArgumentNullException(nameof(xeMember));
188 | Assembly = assembly.Trim();
189 | }
190 |
191 | public override string ToString()
192 | {
193 | return Name;
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlParam.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.IntelliSenseXml
7 | {
8 | internal class IntelliSenseXmlParam
9 | {
10 | public XElement XEParam
11 | {
12 | get;
13 | private set;
14 | }
15 |
16 | private string _name = string.Empty;
17 | public string Name
18 | {
19 | get
20 | {
21 | if (string.IsNullOrWhiteSpace(_name))
22 | {
23 | _name = XmlHelper.GetAttributeValue(XEParam, "name");
24 | }
25 | return _name;
26 | }
27 | }
28 |
29 | private string _value = string.Empty;
30 | public string Value
31 | {
32 | get
33 | {
34 | if (string.IsNullOrWhiteSpace(_value))
35 | {
36 | _value = XmlHelper.GetNodesInPlainText(XEParam);
37 | }
38 | return _value;
39 | }
40 | }
41 |
42 | public IntelliSenseXmlParam(XElement xeParam)
43 | {
44 | XEParam = xeParam;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlSeeAlso.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.IntelliSenseXml;
7 |
8 | internal class IntelliSenseXmlSeeAlso(XElement xeSeeAlso)
9 | {
10 | public XElement XESeeAlso
11 | {
12 | get;
13 | private set;
14 | } = xeSeeAlso;
15 |
16 | private string _cref = string.Empty;
17 | public string Cref
18 | {
19 | get
20 | {
21 | if (string.IsNullOrWhiteSpace(_cref))
22 | {
23 | _cref = XmlHelper.GetAttributeValue(XESeeAlso, "cref");
24 | }
25 | return _cref;
26 | }
27 | }
28 |
29 | public override string ToString() => $"SeeAlso cref={Cref}";
30 | }
31 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlTypeParam.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToDocs.IntelliSenseXml
7 | {
8 | internal class IntelliSenseXmlTypeParam
9 | {
10 | public XElement XETypeParam;
11 |
12 | private string _name = string.Empty;
13 | public string Name
14 | {
15 | get
16 | {
17 | if (string.IsNullOrWhiteSpace(_name))
18 | {
19 | _name = XmlHelper.GetAttributeValue(XETypeParam, "name");
20 | }
21 | return _name;
22 | }
23 | }
24 |
25 | private string _value = string.Empty;
26 | public string Value
27 | {
28 | get
29 | {
30 | if (string.IsNullOrWhiteSpace(_value))
31 | {
32 | _value = XmlHelper.GetNodesInPlainText(XETypeParam);
33 | }
34 | return _value;
35 | }
36 | }
37 |
38 | public IntelliSenseXmlTypeParam(XElement xeTypeParam)
39 | {
40 | XETypeParam = xeTypeParam;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/PortToDocs/src/libraries/libraries.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net8.0
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/StringTestData.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.IO;
5 | using System.Text;
6 | using System.Xml;
7 | using System.Xml.Linq;
8 |
9 | namespace ApiDocsSync.PortToDocs.Tests
10 | {
11 | internal class StringTestData
12 | {
13 | public StringTestData(string original, string expected)
14 | {
15 | Original = original;
16 | Expected = expected;
17 | XDoc = XDocument.Parse(original);
18 | }
19 |
20 | public string Original { get; }
21 | public string Expected { get; }
22 | public XDocument XDoc { get; }
23 | public string Actual
24 | {
25 | get
26 | {
27 | XmlWriterSettings xws = new()
28 | {
29 | Encoding = Encoding.UTF8,
30 | OmitXmlDeclaration = true,
31 | Indent = true,
32 | CheckCharacters = true,
33 | NewLineChars = Configuration.NewLine,
34 | NewLineHandling = NewLineHandling.Replace
35 | };
36 | using MemoryStream ms = new();
37 | using (XmlWriter xw = XmlWriter.Create(ms, xws))
38 | {
39 | XDoc.Save(xw);
40 | }
41 | ms.Position = 0;
42 | using StreamReader sr = new(ms, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
43 | return sr.ReadToEnd();
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/AssemblyAndNamespaceDifferent/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the summary of MyNamespace.MyType. The namespace is not the same as the assembly.
9 |
10 |
11 | This is the summary of MyNamespace.MyMethod. The namespace is not the same as the assembly.
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/AssemblyAndNamespaceDifferent/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | To be added.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/AssemblyAndNamespaceDifferent/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the summary of MyNamespace.MyType. The namespace is not the same as the assembly.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | This is the summary of MyNamespace.MyMethod. The namespace is not the same as the assembly.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/AssemblyAndNamespaceSame/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the summary of MyAssembly.MyType. The namespace is the same as the assembly.
9 |
10 |
11 | This is the summary of MyAssembly.MyMethod. The namespace is the same as the assembly.
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/AssemblyAndNamespaceSame/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | To be added.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/AssemblyAndNamespaceSame/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the summary of MyAssembly.MyType. The namespace is the same as the assembly.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | This is the summary of MyAssembly.MyMethod. The namespace is the same as the assembly.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Basic/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the first Type param value (like with delegates).
9 | This is the second Type param value (like with delegates).
10 | This is the first Type typeparam value.
11 | This is the second Type typeparam value.
12 | This is the type summary. It has a reference to . It contains the word null which should be transformed.
13 |
14 |
15 | This is the first Method param value.
16 | This is the second Method param value.
17 | This is the first Method typeparam.
18 | This is the second Method typeparam.
19 | This is the method summary. It has a reference to .
20 | This is the return value of MyMethod.
21 | This is the original text of ArgumentNullException thrown for MyMethod.
22 | This is the original text of IndexOutOfRangeException thrown for MyMethod.
23 |
24 |
25 | This is the property summary.
26 | This is the property value.
27 |
28 |
29 | The typeparam of MyTypeParamMethod.
30 | An element of type .
31 | The equality comparer of type .
32 | The signature of this method would be: public void Add<TValue> (TValue value, System.Collections.Generic.IEqualityComparer<TValue> comparer);
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Basic/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 | To be added.
15 | To be added.
16 | To be added.
17 | To be added.
18 |
19 |
20 |
21 |
22 | Method
23 |
24 |
25 | MyAssembly
26 | 4.0.0.0
27 |
28 |
29 | System.Int32
30 |
31 |
32 |
33 | To be added.
34 | To be added.
35 | To be added.
36 | To be added.
37 | To be added.
38 | To be added.
39 | To be added.
40 |
41 |
42 |
43 |
44 | Property
45 |
46 | MyAssembly
47 | 4.0.0.0
48 |
49 |
50 | System.Int32
51 |
52 |
53 | To be added.
54 | To be added.
55 | To be added.
56 |
57 |
58 |
59 |
60 | Method
61 |
62 | MyAssembly
63 | 4.0.0.0
64 |
65 |
66 | System.Void
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | To be added.
77 | To be added.
78 | To be added.
79 | To be added.
80 | To be added.
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Basic/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the type summary. It has a reference to . It contains the word which should be transformed.
13 | This is the first Type param value (like with delegates).
14 | This is the second Type param value (like with delegates).
15 | This is the first Type typeparam value.
16 | This is the second Type typeparam value.
17 | To be added.
18 |
19 |
20 |
21 |
22 | Method
23 |
24 |
25 | MyAssembly
26 | 4.0.0.0
27 |
28 |
29 | System.Int32
30 |
31 |
32 |
33 | This is the first Method param value.
34 | This is the second Method param value.
35 | This is the first Method typeparam.
36 | This is the second Method typeparam.
37 | This is the method summary. It has a reference to .
38 | This is the return value of MyMethod.
39 | To be added.
40 | This is the original text of ArgumentNullException thrown for MyMethod.
41 | This is the original text of IndexOutOfRangeException thrown for MyMethod.
42 |
43 |
44 |
45 |
46 | Property
47 |
48 | MyAssembly
49 | 4.0.0.0
50 |
51 |
52 | System.Int32
53 |
54 |
55 | This is the property summary.
56 | This is the property value.
57 | To be added.
58 |
59 |
60 |
61 |
62 | Method
63 |
64 | MyAssembly
65 | 4.0.0.0
66 |
67 |
68 | System.Void
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | The typeparam of MyTypeParamMethod.
79 | An element of type .
80 | The equality comparer of type .
81 | The signature of this method would be: public void Add<TValue> (TValue value, System.Collections.Generic.IEqualityComparer<TValue> comparer);
82 | To be added.
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/DontAddMissingRemarks/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the enum type summary.
9 | This is the enum type remark.
10 |
11 |
12 | This is the first option of MyEnum. Notice it has no remark.
13 |
14 |
15 | This is the second option of MyEnum. Notice it has a remark.
16 | This is the second option remark.
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/DontAddMissingRemarks/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Field
19 |
20 | MyNamespace.MyEnum
21 |
22 | 0
23 |
24 | To be added.
25 |
26 |
27 |
28 |
29 | Field
30 |
31 | MyNamespace.MyEnum
32 |
33 | 1
34 |
35 | To be added.
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/DontAddMissingRemarks/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the enum type summary.
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 | Field
27 |
28 | MyNamespace.MyEnum
29 |
30 | 0
31 |
32 | This is the first option of MyEnum. Notice it has no remark.
33 |
34 |
35 |
36 |
37 | Field
38 |
39 | MyNamespace.MyEnum
40 |
41 | 1
42 |
43 | This is the second option of MyEnum. Notice it has a remark.
44 |
45 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/EnumRemarks/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | The summary of MyEnum.
9 | These are the enum remarks and it's fine if they are ported.
10 |
11 |
12 | The summary of MyEnum.MyField.
13 | These are field enum remarks that should not be ported.
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/EnumRemarks/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Enum
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Field
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | MyNamespace.MyEnum
26 |
27 | 0
28 |
29 |
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/EnumRemarks/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Enum
9 |
10 |
11 |
12 | The summary of MyEnum.
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 | Field
27 |
28 |
29 | MyAssembly
30 | 4.0.0.0
31 |
32 |
33 | MyNamespace.MyEnum
34 |
35 | 0
36 |
37 |
38 | The summary of MyEnum.MyField.
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Exception_ExistingCref/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the type summary.
9 |
10 |
11 | This is the method summary.
12 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9 Word10.
13 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9 Word10.
14 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9 Word10.
15 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9 Word10.
16 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9 Word10.
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Exception_ExistingCref/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the type summary.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | For this test, the exceptions should be ported and appended if the threshold is below 60%.
30 | To be added.
31 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9.
32 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8.
33 | Word1 Word2 Word3 Word4 Word5 Word6 Word7.
34 | Word1 Word2 Word3 Word4 Word5 Word6.
35 | Word1 Word2 Word3 Word4 Word5.
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Exception_ExistingCref/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the type summary.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | For this test, the exceptions should be ported and appended if the threshold is below 60%.
30 | To be added.
31 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9.
32 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8.
33 | Word1 Word2 Word3 Word4 Word5 Word6 Word7.
34 | Word1 Word2 Word3 Word4 Word5 Word6.
35 |
36 | Word1 Word2 Word3 Word4 Word5.
37 | -or-
38 | Word1 Word2 Word3 Word4 Word5 Word6 Word7 Word8 Word9 Word10.
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Exceptions/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the type summary.
9 |
10 |
11 | This is the method summary.
12 | This is the original text of ArgumentNullException thrown for MyMethod.
13 | This is the original text of IndexOutOfRangeException thrown for MyMethod.
14 |
15 | -or-
16 |
17 | A proper alternative. - or - An improper alternative.
18 |
19 | -or-
20 |
21 | A somewhat proper alternative.
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Exceptions/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | To be added.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Exceptions/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the type summary.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | This is the method summary.
30 | To be added.
31 | This is the original text of ArgumentNullException thrown for MyMethod.
32 |
33 | This is the original text of IndexOutOfRangeException thrown for MyMethod.
34 | -or-
35 | A proper alternative.
36 | -or-
37 | An improper alternative.
38 | -or-
39 | A somewhat proper alternative.
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/InheritDoc/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/InheritDoc/intellisense/System/System.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System
5 |
6 |
7 |
8 | This is the summary of the MyParentType class.
9 | These are the remarks of the MyParentType class.
10 |
11 |
12 | This is the summary of the MyParentType.MyMethod method.
13 | These are the remarks of the MyParentType.MyMethod method.
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/InheritDoc/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.MyParentType
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | To be added.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/InheritDoc/xml/System/MyParentType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System
5 | 4.0.0.0
6 |
7 |
8 | System.MyParentType
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | System
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | To be added.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/InheritDoc/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.MyParentType
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 |
19 | Method
20 |
21 |
22 | MyAssembly
23 | 4.0.0.0
24 |
25 |
26 | System.Void
27 |
28 |
29 |
30 | To be added.
31 | To be added.
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/InheritDoc/xml_expected/System/MyParentType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System
5 | 4.0.0.0
6 |
7 |
8 | System.MyParentType
9 |
10 |
11 |
12 | This is the summary of the MyParentType class.
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 | Method
27 |
28 |
29 | System
30 | 4.0.0.0
31 |
32 |
33 | System.Void
34 |
35 |
36 |
37 | This is the summary of the MyParentType.MyMethod method.
38 |
39 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_NoEII_NoInterfaceRemarks/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the type summary.
9 | These are the type remarks. They also have a cref link: .
10 |
11 |
12 | This is the method summary.
13 | These are the method remarks. They are pointing to a param: .
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_NoEII_NoInterfaceRemarks/intellisense/System/System.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.Runtime
5 | 4.0.0.0
6 |
7 |
8 |
9 |
10 | Original interface type summary.
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 | Method
25 |
26 | System.Runtime
27 |
28 |
29 | System.MyReturnType
30 |
31 |
32 |
33 | Original interface method summary.
34 | Original interface method returns.
35 |
36 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_NoEII_NoInterfaceRemarks/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | To be added.
13 | To be added.
14 |
15 |
16 |
17 |
18 | Method
19 |
20 |
21 | MyAssembly
22 | 4.0.0.0
23 |
24 |
25 | System.Void
26 |
27 |
28 |
29 | To be added.
30 | To be added.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_NoEII_NoInterfaceRemarks/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | This is the type summary.
13 |
14 | .
19 |
20 | ]]>
21 |
22 |
23 |
24 |
25 |
26 | Method
27 |
28 |
29 | MyAssembly
30 | 4.0.0.0
31 |
32 |
33 | System.Void
34 |
35 |
36 |
37 | This is the method summary.
38 |
39 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_NoInterfaceRemarks/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the type summary.
9 | These are the type remarks. They also have a cref link: .
10 |
11 |
12 | This is the method summary.
13 | These are the method remarks. They are pointing to a param: .
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_NoInterfaceRemarks/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | System.IMyInterface
13 |
14 |
15 |
16 | To be added.
17 | To be added.
18 |
19 |
20 |
21 |
22 | Method
23 |
24 |
25 | MyAssembly
26 | 4.0.0.0
27 |
28 |
29 | System.Void
30 |
31 |
32 |
33 | To be added.
34 | To be added.
35 |
36 |
37 |
38 |
39 | Method
40 |
41 | M:System.IMyInterface.MyInterfaceMethod
42 |
43 |
44 | MyAssembly
45 |
46 |
47 | System.MyReturnType
48 |
49 |
50 |
51 | To be added.
52 | To be added.
53 | To be added.
54 |
55 |
56 |
57 |
58 | Method
59 |
60 | M:System.IMyInterface.MyInterfaceMethod
61 |
62 |
63 | MyAssembly
64 | 4.0.0.0
65 |
66 |
67 | System.MyReturnType
68 |
69 |
70 |
71 | To be added.
72 | To be added.
73 | To be added.
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_NoInterfaceRemarks/xml/MyAssembly/System/System.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.Runtime
5 | 4.0.0.0
6 |
7 |
8 |
9 |
10 | Original interface type summary.
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 | Method
25 |
26 | System.Runtime
27 |
28 |
29 | System.MyReturnType
30 |
31 |
32 |
33 | Original interface method summary.
34 | Original interface method returns.
35 |
36 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_NoInterfaceRemarks/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | System.IMyInterface
13 |
14 |
15 |
16 | This is the type summary.
17 |
18 | .
23 |
24 | ]]>
25 |
26 |
27 |
28 |
29 |
30 | Method
31 |
32 |
33 | MyAssembly
34 | 4.0.0.0
35 |
36 |
37 | System.Void
38 |
39 |
40 |
41 | This is the method summary.
42 |
43 |
50 |
51 |
52 |
53 |
54 |
55 | Method
56 |
57 | M:System.IMyInterface.MyInterfaceMethod
58 |
59 |
60 | MyAssembly
61 |
62 |
63 | System.MyReturnType
64 |
65 |
66 |
67 | Original interface method summary.
68 | Original interface method returns.
69 | To be added.
70 |
71 |
72 |
73 |
74 | Method
75 |
76 | M:System.IMyInterface.MyInterfaceMethod
77 |
78 |
79 | MyAssembly
80 | 4.0.0.0
81 |
82 |
83 | System.MyReturnType
84 |
85 |
86 |
87 | Original interface method summary.
88 | Original interface method returns.
89 |
90 | instance is cast to an interface.
95 |
96 | ]]>
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_WithInterfaceRemarks/intellisense/MyAssembly/MyAssembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 |
8 | This is the type summary.
9 | These are the type remarks. They also have a cref link: .
10 |
11 |
12 | This is the method summary.
13 | These are the method remarks. They are pointing to a param: .
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_WithInterfaceRemarks/xml/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | System.IMyInterface
13 |
14 |
15 |
16 | To be added.
17 | To be added.
18 |
19 |
20 |
21 |
22 | Method
23 |
24 |
25 | MyAssembly
26 | 4.0.0.0
27 |
28 |
29 | System.Void
30 |
31 |
32 |
33 | To be added.
34 | To be added.
35 |
36 |
37 |
38 |
39 | Method
40 |
41 | M:System.IMyInterface.MyInterfaceMethod
42 |
43 |
44 | MyAssembly
45 |
46 |
47 | System.MyReturnType
48 |
49 |
50 |
51 | To be added.
52 | To be added.
53 | To be added.
54 |
55 |
56 |
57 |
58 | Method
59 |
60 | M:System.IMyInterface.MyInterfaceMethod
61 |
62 |
63 | MyAssembly
64 | 4.0.0.0
65 |
66 |
67 | System.MyReturnType
68 |
69 |
70 |
71 | To be added.
72 | To be added.
73 | To be added.
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_WithInterfaceRemarks/xml/MyAssembly/System/System.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.Runtime
5 | 4.0.0.0
6 |
7 |
8 |
9 |
10 | Original interface type summary.
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 | Method
25 |
26 | System.Runtime
27 |
28 |
29 | System.MyReturnType
30 |
31 |
32 |
33 | Original interface method summary.
34 | Original interface method returns.
35 |
36 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/TestData/Remarks_WithEII_WithInterfaceRemarks/xml_expected/MyAssembly/MyType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 | 4.0.0.0
6 |
7 |
8 | System.Object
9 |
10 |
11 |
12 | System.IMyInterface
13 |
14 |
15 |
16 | This is the type summary.
17 |
18 | .
23 |
24 | ]]>
25 |
26 |
27 |
28 |
29 |
30 | Method
31 |
32 |
33 | MyAssembly
34 | 4.0.0.0
35 |
36 |
37 | System.Void
38 |
39 |
40 |
41 | This is the method summary.
42 |
43 |
50 |
51 |
52 |
53 |
54 |
55 | Method
56 |
57 | M:System.IMyInterface.MyInterfaceMethod
58 |
59 |
60 | MyAssembly
61 |
62 |
63 | System.MyReturnType
64 |
65 |
66 |
67 | Original interface method summary.
68 | Original interface method returns.
69 | To be added.
70 |
71 |
72 |
73 |
74 | Method
75 |
76 | M:System.IMyInterface.MyInterfaceMethod
77 |
78 |
79 | MyAssembly
80 | 4.0.0.0
81 |
82 |
83 | System.MyReturnType
84 |
85 |
86 |
87 | Original interface method summary.
88 | Original interface method returns.
89 |
90 | instance is cast to an interface.
95 |
96 | Original interface method remarks that should show up in interface implementations if -skipInterfaceRemarks is set to `false`.
97 |
98 | ]]>
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/src/PortToDocs/tests/tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | all
23 | runtime; build; native; contentfiles; analyzers; buildtransitive
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/PortToTripleSlash.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32220.68
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortToTripleSlash", "src\app\PortToTripleSlash.csproj", "{59FE1032-97B5-48BE-BB5A-A0428916271F}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libraries", "src\libraries\libraries.csproj", "{4E3F11D4-4661-4E71-B19D-6EFA898E14D5}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tests", "tests\tests.csproj", "{63E78F91-1824-4E2D-BD73-9A0ED9C7B570}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{14364EF5-DFAA-40FA-A313-4C89088FEA3D}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {59FE1032-97B5-48BE-BB5A-A0428916271F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {59FE1032-97B5-48BE-BB5A-A0428916271F}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {59FE1032-97B5-48BE-BB5A-A0428916271F}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {59FE1032-97B5-48BE-BB5A-A0428916271F}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {4E3F11D4-4661-4E71-B19D-6EFA898E14D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {4E3F11D4-4661-4E71-B19D-6EFA898E14D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {4E3F11D4-4661-4E71-B19D-6EFA898E14D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {4E3F11D4-4661-4E71-B19D-6EFA898E14D5}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {63E78F91-1824-4E2D-BD73-9A0ED9C7B570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {63E78F91-1824-4E2D-BD73-9A0ED9C7B570}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {63E78F91-1824-4E2D-BD73-9A0ED9C7B570}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {63E78F91-1824-4E2D-BD73-9A0ED9C7B570}.Release|Any CPU.Build.0 = Release|Any CPU
32 | EndGlobalSection
33 | GlobalSection(SolutionProperties) = preSolution
34 | HideSolutionNode = FALSE
35 | EndGlobalSection
36 | GlobalSection(ExtensibilityGlobals) = postSolution
37 | SolutionGuid = {E1DDEAA8-4441-4EE3-80A7-C791C517C245}
38 | EndGlobalSection
39 | EndGlobal
40 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/app/PortToTripleSlash.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApiDocsSync.PortToTripleSlash
8 | {
9 | public class PortToTripleSlash
10 | {
11 | public static async Task Main(string[] args)
12 | {
13 | Configuration config = Configuration.GetCLIArguments(args);
14 |
15 | VSLoader.LoadVSInstance();
16 |
17 | CancellationTokenSource cts = new();
18 | config.Loader = new MSBuildLoader(config.BinLogPath);
19 | await config.Loader.LoadMainProjectAsync(config.CsProj, config.IsMono, cts.Token).ConfigureAwait(false);
20 |
21 | ToTripleSlashPorter porter = new(config);
22 | await porter.StartAsync(cts.Token).ConfigureAwait(false);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/app/PortToTripleSlash.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | ApiDocsSync.PortToTripleSlash.PortToTripleSlash
7 | enable
8 | true
9 | true
10 | 1.3
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/AllTypesVisitor.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Microsoft.CodeAnalysis;
7 |
8 | namespace ApiDocsSync.PortToTripleSlash
9 | {
10 |
11 | internal class AllTypesVisitor : SymbolVisitor
12 | {
13 | public readonly List AllTypesSymbols = new();
14 | public override void VisitNamedType(INamedTypeSymbol symbol)
15 | {
16 | if (symbol.DeclaredAccessibility != Accessibility.Protected && symbol.DeclaredAccessibility != Accessibility.Public && symbol.DeclaredAccessibility != Accessibility.NotApplicable)
17 | {
18 | return;
19 | }
20 |
21 | AllTypesSymbols.Add(symbol);
22 | // Visit all nested types too, including delegates
23 | foreach (INamedTypeSymbol typeMember in symbol.GetTypeMembers())
24 | {
25 | Visit(typeMember);
26 | }
27 | }
28 | public override void VisitNamespace(INamespaceSymbol symbol)
29 | {
30 | foreach (INamespaceOrTypeSymbol s in symbol.GetMembers())
31 | {
32 | s.Accept(this);
33 | }
34 | }
35 | public override void VisitDynamicType(IDynamicTypeSymbol symbol) => AllTypesSymbols.Add(symbol);
36 | public override void VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) => AllTypesSymbols.Add(symbol);
37 | public override void VisitAlias(IAliasSymbol symbol) => AllTypesSymbols.Add(symbol);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/APIKind.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace ApiDocsSync.PortToTripleSlash.Docs
5 | {
6 | internal enum APIKind
7 | {
8 | Type,
9 | Member
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsAPI.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics.CodeAnalysis;
7 | using System.Linq;
8 | using System.Xml.Linq;
9 |
10 | namespace ApiDocsSync.PortToTripleSlash.Docs
11 | {
12 | internal abstract class DocsAPI : IDocsAPI
13 | {
14 | private string? _docId;
15 | private string? _docIdUnprefixed;
16 | private List? _params;
17 | private List? _parameters;
18 | private List? _typeParameters;
19 | private List? _typeParams;
20 | private List? _assemblyInfos;
21 | private List? _seeAlsoCrefs;
22 | private List? _altMemberCrefs;
23 | private List? _relateds;
24 |
25 | protected readonly XElement XERoot;
26 |
27 | protected DocsAPI(XElement xeRoot) => XERoot = xeRoot;
28 |
29 | public bool IsUndocumented =>
30 | Summary.IsDocsEmpty() ||
31 | Returns.IsDocsEmpty() ||
32 | Params.Any(p => p.Value.IsDocsEmpty()) ||
33 | TypeParams.Any(tp => tp.Value.IsDocsEmpty());
34 |
35 | public string FilePath { get; set; } = string.Empty;
36 |
37 | public string DocId => _docId ??= GetApiSignatureDocId();
38 |
39 | public string DocIdUnprefixed => _docIdUnprefixed ??= DocId[2..];
40 |
41 | ///
42 | /// The Parameter elements found inside the Parameters section.
43 | ///
44 | public List Parameters
45 | {
46 | get
47 | {
48 | if (_parameters == null)
49 | {
50 | XElement? xeParameters = XERoot.Element("Parameters");
51 | _parameters = xeParameters == null ? (List)new() : xeParameters.Elements("Parameter").Select(x => new DocsParameter(x)).ToList();
52 | }
53 | return _parameters;
54 | }
55 | }
56 |
57 | ///
58 | /// The TypeParameter elements found inside the TypeParameters section.
59 | ///
60 | public List TypeParameters
61 | {
62 | get
63 | {
64 | if (_typeParameters == null)
65 | {
66 | XElement? xeTypeParameters = XERoot.Element("TypeParameters");
67 | _typeParameters = xeTypeParameters == null ? (List)new() : xeTypeParameters.Elements("TypeParameter").Select(x => new DocsTypeParameter(x)).ToList();
68 | }
69 | return _typeParameters;
70 | }
71 | }
72 |
73 | public XElement Docs => XERoot.Element("Docs") ?? throw new NullReferenceException($"Docs section was null in {FilePath}");
74 |
75 | ///
76 | /// The param elements found inside the Docs section.
77 | ///
78 | public List Params => _params ??= Docs != null ? Docs.Elements("param").Select(x => new DocsParam(this, x)).ToList() : new List();
79 |
80 | ///
81 | /// The typeparam elements found inside the Docs section.
82 | ///
83 | public List TypeParams => _typeParams ??= Docs != null ? Docs.Elements("typeparam").Select(x => new DocsTypeParam(this, x)).ToList() : (List)new();
84 |
85 | public List SeeAlsoCrefs => _seeAlsoCrefs ??= Docs != null ? Docs.Elements("seealso").Select(x => XmlHelper.GetAttributeValue(x, "cref").DocIdEscaped()).ToList() : (List)new();
86 |
87 | public List AltMembers => _altMemberCrefs ??= Docs != null ? Docs.Elements("altmember").Select(x => XmlHelper.GetAttributeValue(x, "cref").DocIdEscaped()).ToList() : (List)new();
88 |
89 | public List Relateds => _relateds ??= Docs != null ? Docs.Elements("related").Select(x => new DocsRelated(this, x)).ToList() : (List)new();
90 |
91 | public abstract string Summary { get; }
92 |
93 | public abstract string Value { get; }
94 |
95 | public abstract string ReturnType { get; }
96 |
97 | public abstract string Returns { get; }
98 |
99 | public abstract string Remarks { get; }
100 |
101 | public abstract List Exceptions { get; }
102 |
103 | public List AssemblyInfos => _assemblyInfos ??= new List();
104 |
105 | public APIKind Kind => this switch
106 | {
107 | DocsMember _ => APIKind.Member,
108 | DocsType _ => APIKind.Type,
109 | _ => throw new ArgumentException("Unrecognized IDocsAPI object")
110 | };
111 |
112 | // For Types, these elements are called TypeSignature.
113 | // For Members, these elements are called MemberSignature.
114 | protected abstract string GetApiSignatureDocId();
115 |
116 | protected string GetNodesInPlainText(string name) => TryGetElement(name, out XElement? element) ? XmlHelper.GetNodesInPlainText(name, element) : string.Empty;
117 |
118 | // Returns true if the element existed or had to be created with "To be added." as value. Returns false the element was not found and a new one was not created.
119 | private bool TryGetElement(string name, [NotNullWhen(returnValue: true)] out XElement? element)
120 | {
121 | element = null;
122 |
123 | if (Docs == null)
124 | {
125 | return false;
126 | }
127 |
128 | element = Docs.Element(name);
129 |
130 | return element != null;
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsAssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Xml.Linq;
7 |
8 | namespace ApiDocsSync.PortToTripleSlash.Docs
9 | {
10 | internal class DocsAssemblyInfo
11 | {
12 | private readonly XElement XEAssemblyInfo;
13 |
14 | public string AssemblyName => XmlHelper.GetChildElementValue(XEAssemblyInfo, "AssemblyName");
15 |
16 | private List? _assemblyVersions;
17 | public List AssemblyVersions => _assemblyVersions ??= XEAssemblyInfo.Elements("AssemblyVersion").Select(x => XmlHelper.GetNodesInPlainText("AssemblyVersion", x)).ToList();
18 |
19 | public DocsAssemblyInfo(XElement xeAssemblyInfo) => XEAssemblyInfo = xeAssemblyInfo;
20 |
21 | public override string ToString() => AssemblyName;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsAttribute.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsAttribute
9 | {
10 | private readonly XElement XEAttribute;
11 |
12 | public string FrameworkAlternate => XmlHelper.GetAttributeValue(XEAttribute, "FrameworkAlternate");
13 |
14 | public string AttributeName => XmlHelper.GetChildElementValue(XEAttribute, "AttributeName");
15 |
16 | public DocsAttribute(XElement xeAttribute) => XEAttribute = xeAttribute;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsException.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsException
9 | {
10 | private readonly XElement XEException;
11 |
12 | public IDocsAPI ParentAPI { get; }
13 |
14 | public string Cref => XmlHelper.GetAttributeValue(XEException, "cref").DocIdEscaped();
15 |
16 | public string Value => XmlHelper.GetNodesInPlainText("exception", XEException);
17 |
18 | public string OriginalValue { get; private set; }
19 |
20 | public DocsException(IDocsAPI parentAPI, XElement xException)
21 | {
22 | ParentAPI = parentAPI;
23 | XEException = xException;
24 | OriginalValue = Value;
25 | }
26 |
27 | public override string ToString() => $"{Cref} - {Value}";
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsMember.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Xml.Linq;
8 |
9 | namespace ApiDocsSync.PortToTripleSlash.Docs
10 | {
11 | internal class DocsMember : DocsAPI
12 | {
13 | private string? _memberName;
14 | private List? _memberSignatures;
15 | private List? _exceptions;
16 |
17 | public DocsMember(string filePath, DocsType parentType, XElement xeMember)
18 | : base(xeMember)
19 | {
20 | FilePath = filePath;
21 | ParentType = parentType;
22 | AssemblyInfos.AddRange(XERoot.Elements("AssemblyInfo").Select(x => new DocsAssemblyInfo(x)));
23 | }
24 |
25 | public DocsType ParentType { get; private set; }
26 |
27 | public string MemberName => _memberName ??= XmlHelper.GetAttributeValue(XERoot, "MemberName");
28 |
29 | public List MemberSignatures => _memberSignatures ??= XERoot.Elements("MemberSignature").Select(x => new DocsMemberSignature(x)).ToList();
30 |
31 | public string MemberType => XmlHelper.GetChildElementValue(XERoot, "MemberType");
32 |
33 | public string ImplementsInterfaceMember
34 | {
35 | get
36 | {
37 | XElement? xeImplements = XERoot.Element("Implements");
38 | return (xeImplements != null) ? XmlHelper.GetChildElementValue(xeImplements, "InterfaceMember") : string.Empty;
39 | }
40 | }
41 |
42 | public override string ReturnType
43 | {
44 | get
45 | {
46 | XElement? xeReturnValue = XERoot.Element("ReturnValue");
47 | return xeReturnValue != null ? XmlHelper.GetChildElementValue(xeReturnValue, "ReturnType") : string.Empty;
48 | }
49 | }
50 |
51 | public override string Returns => (ReturnType != "System.Void") ? GetNodesInPlainText("returns") : string.Empty;
52 |
53 | public override string Summary => GetNodesInPlainText("summary");
54 |
55 | public override string Remarks => GetNodesInPlainText("remarks");
56 |
57 | public override string Value => (MemberType == "Property") ? GetNodesInPlainText("value") : string.Empty;
58 |
59 | public override List Exceptions
60 | {
61 | get
62 | {
63 | if (_exceptions == null)
64 | {
65 | if (Docs != null)
66 | {
67 | _exceptions = Docs.Elements("exception").Select(x => new DocsException(this, x)).ToList();
68 | }
69 | else
70 | {
71 | _exceptions = new List();
72 | }
73 | }
74 | return _exceptions;
75 | }
76 | }
77 |
78 | public override string ToString() => DocId;
79 |
80 | protected override string GetApiSignatureDocId()
81 | {
82 | DocsMemberSignature? dts = MemberSignatures.FirstOrDefault(x => x.Language == "DocId");
83 | return dts != null ? dts.Value : throw new FormatException($"DocId TypeSignature not found for {MemberName}");
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsMemberSignature.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsMemberSignature
9 | {
10 | private readonly XElement XEMemberSignature;
11 |
12 | public string Language => XmlHelper.GetAttributeValue(XEMemberSignature, "Language");
13 |
14 | public string Value => XmlHelper.GetAttributeValue(XEMemberSignature, "Value");
15 |
16 | public DocsMemberSignature(XElement xeMemberSignature) => XEMemberSignature = xeMemberSignature;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsParam.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsParam
9 | {
10 | private readonly XElement XEDocsParam;
11 |
12 | public IDocsAPI ParentAPI { get; }
13 |
14 | public string Name => XmlHelper.GetAttributeValue(XEDocsParam, "name");
15 |
16 | public string Value => XmlHelper.GetNodesInPlainText("param", XEDocsParam);
17 |
18 | public DocsParam(IDocsAPI parentAPI, XElement xeDocsParam)
19 | {
20 | ParentAPI = parentAPI;
21 | XEDocsParam = xeDocsParam;
22 | }
23 |
24 | public override string ToString() => Name;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsParameter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsParameter
9 | {
10 | private readonly XElement XEParameter;
11 |
12 | public string Name => XmlHelper.GetAttributeValue(XEParameter, "Name");
13 |
14 | public string Type => XmlHelper.GetAttributeValue(XEParameter, "Type");
15 |
16 | public DocsParameter(XElement xeParameter) => XEParameter = xeParameter;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsRelated.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsRelated
9 | {
10 | private readonly XElement XERelatedArticle;
11 |
12 | public IDocsAPI ParentAPI { get; }
13 |
14 | public string ArticleType => XmlHelper.GetAttributeValue(XERelatedArticle, "type");
15 |
16 | public string Href => XmlHelper.GetAttributeValue(XERelatedArticle, "href");
17 |
18 | public string Value => XmlHelper.GetNodesInPlainText("related", XERelatedArticle);
19 |
20 | public DocsRelated(IDocsAPI parentAPI, XElement xeRelatedArticle)
21 | {
22 | ParentAPI = parentAPI;
23 | XERelatedArticle = xeRelatedArticle;
24 | }
25 |
26 | public override string ToString() => Value;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsType.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Xml.Linq;
9 | using Microsoft.CodeAnalysis;
10 |
11 | namespace ApiDocsSync.PortToTripleSlash.Docs
12 | {
13 | ///
14 | /// Represents the root xml element (unique) of a Docs xml file, called Type.
15 | ///
16 | internal class DocsType : DocsAPI
17 | {
18 | private string? _typeName;
19 | private string? _name;
20 | private string? _fullName;
21 | private string? _namespace;
22 | private string? _baseTypeName;
23 | private List? _interfaceNames;
24 | private List? _attributes;
25 | private List? _typesSignatures;
26 |
27 | public DocsType(string filePath, XDocument xDoc, XElement xeRoot, Encoding encoding)
28 | : base(xeRoot)
29 | {
30 | FilePath = filePath;
31 | XDoc = xDoc;
32 | FileEncoding = encoding;
33 | AssemblyInfos.AddRange(XERoot.Elements("AssemblyInfo").Select(x => new DocsAssemblyInfo(x)));
34 | }
35 |
36 | private List? _symbolLocations;
37 | public List SymbolLocations => _symbolLocations ??= new();
38 |
39 | public XDocument XDoc { get; }
40 |
41 | public Encoding FileEncoding { get; }
42 |
43 | public string TypeName
44 | {
45 | get
46 | {
47 | if (_typeName == null)
48 | {
49 | // DocId uses ` notation for generic types, but it uses . for nested types
50 | // Name uses + for nested types, but it uses <T> for generic types
51 | // We need ` notation for generic types and + notation for nested types
52 | // Only filename gives us that format, but we have to prepend the namespace
53 | if (DocId.Contains('`') || Name.Contains('+'))
54 | {
55 | _typeName = Namespace + "." + System.IO.Path.GetFileNameWithoutExtension(FilePath);
56 | }
57 | else
58 | {
59 | _typeName = FullName;
60 | }
61 | }
62 | return _typeName;
63 | }
64 | }
65 |
66 | public string Name => _name ??= XmlHelper.GetAttributeValue(XERoot, "Name");
67 |
68 | public string FullName => _fullName ??= XmlHelper.GetAttributeValue(XERoot, "FullName");
69 |
70 | public string Namespace
71 | {
72 | get
73 | {
74 | if (_namespace == null)
75 | {
76 | int lastDotPosition = FullName.LastIndexOf('.');
77 | _namespace = lastDotPosition < 0 ? FullName : FullName.Substring(0, lastDotPosition);
78 | }
79 | return _namespace;
80 | }
81 | }
82 |
83 | public List TypeSignatures => _typesSignatures ??= XERoot.Elements("TypeSignature").Select(x => new DocsTypeSignature(x)).ToList();
84 |
85 | public XElement? Base => XERoot.Element("Base");
86 |
87 | public string BaseTypeName
88 | {
89 | get
90 | {
91 | if (Base == null)
92 | {
93 | _baseTypeName = string.Empty;
94 | }
95 | else if (_baseTypeName == null)
96 | {
97 | _baseTypeName = XmlHelper.GetChildElementValue(Base, "BaseTypeName");
98 | }
99 | return _baseTypeName;
100 | }
101 | }
102 |
103 | public XElement? Interfaces => XERoot.Element("Interfaces");
104 |
105 | public List InterfaceNames
106 | {
107 | get
108 | {
109 | if (Interfaces == null)
110 | {
111 | _interfaceNames = new();
112 | }
113 | else if (_interfaceNames == null)
114 | {
115 | _interfaceNames = Interfaces.Elements("Interface").Select(x => XmlHelper.GetChildElementValue(x, "InterfaceName")).ToList();
116 | }
117 | return _interfaceNames;
118 | }
119 | }
120 |
121 | public List Attributes
122 | {
123 | get
124 | {
125 | if (_attributes == null)
126 | {
127 | XElement? e = XERoot.Element("Attributes");
128 | if (e == null)
129 | {
130 | _attributes = new();
131 | }
132 | else
133 | {
134 | _attributes = (e != null) ? e.Elements("Attribute").Select(x => new DocsAttribute(x)).ToList() : new List();
135 | }
136 | }
137 | return _attributes;
138 | }
139 | }
140 |
141 | public override string Summary => GetNodesInPlainText("summary");
142 |
143 | public override string Value => string.Empty;
144 |
145 | ///
146 | /// Only available when the type is a delegate.
147 | ///
148 | public override string ReturnType
149 | {
150 | get
151 | {
152 | XElement? xeReturnValue = XERoot.Element("ReturnValue");
153 | if (xeReturnValue != null)
154 | {
155 | return XmlHelper.GetChildElementValue(xeReturnValue, "ReturnType");
156 | }
157 | return string.Empty;
158 | }
159 | }
160 |
161 | ///
162 | /// Only available when the type is a delegate.
163 | ///
164 | public override string Returns => (ReturnType != "System.Void") ? GetNodesInPlainText("returns") : string.Empty;
165 |
166 | public override string Remarks => GetNodesInPlainText("remarks");
167 |
168 | public override List Exceptions { get; } = new();
169 |
170 | public override string ToString() => FullName;
171 |
172 | protected override string GetApiSignatureDocId()
173 | {
174 | DocsTypeSignature? dts = TypeSignatures.FirstOrDefault(x => x.Language == "DocId");
175 | return dts != null ? dts.Value : throw new FormatException($"DocId TypeSignature not found for {FullName}");
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsTypeParam.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | ///
9 | /// Each one of these typeparam objects live inside the Docs section inside the Member object.
10 | ///
11 | internal class DocsTypeParam
12 | {
13 | private readonly XElement XEDocsTypeParam;
14 |
15 | public IDocsAPI ParentAPI { get; }
16 |
17 | public string Name => XmlHelper.GetAttributeValue(XEDocsTypeParam, "name");
18 |
19 | public string Value => XmlHelper.GetNodesInPlainText("typeparam", XEDocsTypeParam);
20 |
21 | public DocsTypeParam(IDocsAPI parentAPI, XElement xeDocsTypeParam)
22 | {
23 | ParentAPI = parentAPI;
24 | XEDocsTypeParam = xeDocsTypeParam;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsTypeParameter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Xml.Linq;
7 |
8 | namespace ApiDocsSync.PortToTripleSlash.Docs
9 | {
10 | ///
11 | /// Each one of these TypeParameter objects islocated inside the TypeParameters section inside the Member.
12 | ///
13 | internal class DocsTypeParameter
14 | {
15 | private readonly XElement XETypeParameter;
16 |
17 | public string Name => XmlHelper.GetAttributeValue(XETypeParameter, "Name");
18 |
19 | private XElement? Constraints => XETypeParameter.Element("Constraints");
20 |
21 | private List? _constraintsParameterAttributes;
22 | public List ConstraintsParameterAttributes => _constraintsParameterAttributes ??= Constraints != null
23 | ? Constraints.Elements("ParameterAttribute").Select(x => XmlHelper.GetNodesInPlainText("ParameterAttribute", x)).ToList()
24 | : new List();
25 |
26 | public string ConstraintsBaseTypeName => Constraints != null ? XmlHelper.GetChildElementValue(Constraints, "BaseTypeName") : string.Empty;
27 |
28 | public DocsTypeParameter(XElement xeTypeParameter) => XETypeParameter = xeTypeParameter;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/DocsTypeSignature.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Xml.Linq;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash.Docs
7 | {
8 | internal class DocsTypeSignature
9 | {
10 | private readonly XElement XETypeSignature;
11 |
12 | public string Language => XmlHelper.GetAttributeValue(XETypeSignature, "Language");
13 |
14 | public string Value => XmlHelper.GetAttributeValue(XETypeSignature, "Value");
15 |
16 | public DocsTypeSignature(XElement xeTypeSignature) => XETypeSignature = xeTypeSignature;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Docs/IDocsAPI.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Xml.Linq;
6 |
7 | namespace ApiDocsSync.PortToTripleSlash.Docs
8 | {
9 | internal interface IDocsAPI
10 | {
11 | public abstract APIKind Kind { get; }
12 | public abstract bool IsUndocumented { get; }
13 | public abstract string FilePath { get; set; }
14 | public abstract string DocId { get; }
15 | public abstract string DocIdUnprefixed { get; }
16 | public abstract XElement Docs { get; }
17 | public abstract List Parameters { get; }
18 | public abstract List Params { get; }
19 | public abstract List TypeParameters { get; }
20 | public abstract List TypeParams { get; }
21 | public abstract string Summary { get; }
22 | public abstract string Value { get; }
23 | public abstract string ReturnType { get; }
24 | public abstract string Returns { get; }
25 | public abstract string Remarks { get; }
26 | public abstract List Exceptions { get; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/Extensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Linq;
6 |
7 | namespace ApiDocsSync.PortToTripleSlash
8 | {
9 | // Provides generic extension methods.
10 | internal static class Extensions
11 | {
12 | // Adds a string to a list of strings if the element is not there yet. The method makes sure to escape unexpected curly brackets to prevent formatting exceptions.
13 | public static void AddIfNotExists(this List list, string element)
14 | {
15 | string cleanedElement = element.DocIdEscaped();
16 | if (!list.Contains(cleanedElement))
17 | {
18 | list.Add(cleanedElement);
19 | }
20 | }
21 |
22 | // Removes the specified substrings from another string
23 | public static string RemoveSubstrings(this string oldString, params string[] stringsToRemove)
24 | {
25 | string newString = oldString;
26 | foreach (string toRemove in stringsToRemove)
27 | {
28 | if (newString.Contains(toRemove))
29 | {
30 | newString = newString.Replace(toRemove, string.Empty);
31 | }
32 | }
33 | return newString;
34 | }
35 |
36 | public static bool ContainsStrings(this string text, string[] strings)
37 | {
38 | foreach (string str in strings)
39 | {
40 | if (text.Contains(str))
41 | {
42 | return true;
43 | }
44 | }
45 |
46 | return false;
47 | }
48 |
49 | // Some API DocIDs with types contain "{" and "}" to enclose the typeparam, which causes
50 | // an exception to be thrown when trying to embed the string in a formatted string.
51 | public static string DocIdEscaped(this string docId) =>
52 | docId
53 | .Replace("{", "{{")
54 | .Replace("}", "}}")
55 | .Replace("<", "{{")
56 | .Replace(">", "}}")
57 | .Replace("<", "{{")
58 | .Replace(">", "}}");
59 |
60 | // Checks if the passed string is considered "empty" according to the Docs repo rules.
61 | public static bool IsDocsEmpty(this string? s) =>
62 | string.IsNullOrWhiteSpace(s) || s == Configuration.ToBeAdded;
63 |
64 | public static bool HasItems(this IEnumerable src) => src?.Any() ?? false;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/ResolvedLocation.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using Microsoft.CodeAnalysis;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash
7 | {
8 | public class ResolvedLocation
9 | {
10 | public string TypeName { get; }
11 | public Compilation Compilation { get; }
12 | public Location Location { get; }
13 | public SyntaxTree Tree { get; }
14 | public SemanticModel Model { get; }
15 | public SyntaxNode? NewNode { get; set; }
16 |
17 | public ResolvedLocation(string typeName, Compilation compilation, Location location, SyntaxTree tree)
18 | {
19 | TypeName = typeName;
20 | Compilation = compilation;
21 | Location = location;
22 | Tree = tree;
23 | Model = Compilation.GetSemanticModel(Tree);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/ResolvedProject.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using Microsoft.CodeAnalysis;
5 |
6 | namespace ApiDocsSync.PortToTripleSlash
7 | {
8 | public class ResolvedProject
9 | {
10 | public ResolvedWorkspace ResolvedWorkspace { get; }
11 | public Project Project { get; }
12 | public Compilation Compilation { get; }
13 | public string ProjectPath { get; }
14 |
15 | public ResolvedProject(ResolvedWorkspace resolvedWorkspace, string projectPath, Project project, Compilation compilation)
16 | {
17 | ResolvedWorkspace = resolvedWorkspace;
18 | Project = project;
19 | Compilation = compilation;
20 | ProjectPath = projectPath;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/ResolvedWorkspace.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using Microsoft.CodeAnalysis;
6 | using Microsoft.CodeAnalysis.Editing;
7 | using Microsoft.CodeAnalysis.MSBuild;
8 |
9 | namespace ApiDocsSync.PortToTripleSlash
10 | {
11 | public class ResolvedWorkspace
12 | {
13 | public MSBuildWorkspace Workspace { get; }
14 | public List ResolvedProjects { get; }
15 | public SyntaxGenerator Generator { get; }
16 |
17 | public ResolvedWorkspace(MSBuildWorkspace workspace)
18 | {
19 | Workspace = workspace;
20 | ResolvedProjects = new List();
21 | Generator = SyntaxGenerator.GetGenerator(workspace, LanguageNames.CSharp);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/VSLoader.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics.CodeAnalysis;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Reflection;
10 | using System.Runtime.Loader;
11 | using Microsoft.Build.Locator;
12 |
13 | namespace ApiDocsSync.PortToTripleSlash
14 | {
15 | // Per the documentation: https://docs.microsoft.com/en-us/visualstudio/msbuild/updating-an-existing-application
16 | // Do not call any of these APIs from the same context where Microsoft.Build APIs are being called.
17 | public static class VSLoader
18 | {
19 | private static readonly string[] s_candidateExtensions = new[] { "ni.dll", "ni.exe", "dll", "exe" };
20 | private static readonly Dictionary s_pathsToAssemblies = new(StringComparer.OrdinalIgnoreCase);
21 | private static readonly Dictionary s_namesToAssemblies = new();
22 | private static readonly object s_guard = new();
23 |
24 | public static VisualStudioInstance? VSInstance { get; private set; }
25 |
26 | // Per the documentation: https://docs.microsoft.com/en-us/visualstudio/msbuild/updating-an-existing-application
27 | // Cannot reference any MSBuild types (from Microsoft.Build namespace) in the same method that calls MSBuildLocator.
28 | public static void LoadVSInstance()
29 | {
30 | Log.Info("Querying for all Visual Studio instances...");
31 | IEnumerable vsBuildInstances = MSBuildLocator.QueryVisualStudioInstances();
32 |
33 | if (!vsBuildInstances.Any())
34 | {
35 | throw new Exception("No VS instances found.");
36 | }
37 |
38 | Log.Info("Looking for the latest stable instance of Visual Studio, if there is one...");
39 | VSInstance = vsBuildInstances.Where(b => !b.MSBuildPath.Contains("-preview"))
40 | .OrderByDescending(b => b.Version)
41 | .FirstOrDefault() ??
42 | vsBuildInstances.First();
43 | Log.Success($"Selected instance:{Environment.NewLine} - MSBuildPath: {VSInstance.MSBuildPath}{Environment.NewLine} - Version: {VSInstance.Version}");
44 |
45 | // Unit tests execute this multiple times, ensure we only register once
46 | if (MSBuildLocator.CanRegister)
47 | {
48 | Log.Info("Attempting to register assembly loader...");
49 | RegisterAssemblyLoader(VSInstance.MSBuildPath);
50 | Log.Info("Attempting to register Visual Studio instance");
51 | MSBuildLocator.RegisterInstance(VSInstance);
52 | Log.Success("Successful Visual Studio load!");
53 | }
54 | else
55 | {
56 | Log.Error("Could not register the Visual Studio instance (CanRegister=false).");
57 | }
58 | }
59 |
60 | // Register an assembly loader that will load assemblies with higher version than what was requested.
61 | private static void RegisterAssemblyLoader(string searchPath)
62 | {
63 | AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext context, AssemblyName assemblyName) =>
64 | {
65 | lock (s_guard)
66 | {
67 | if (s_namesToAssemblies.TryGetValue(assemblyName.FullName, out Assembly? cachedAssembly))
68 | {
69 | return cachedAssembly;
70 | }
71 |
72 | if (TryResolveAssemblyFromPaths(context, assemblyName, searchPath, out Assembly? assembly))
73 | {
74 | // Cache assembly
75 | string? name = assembly.FullName;
76 | if (name is null)
77 | {
78 | throw new Exception($"Could not get name for assembly '{assembly}'");
79 | }
80 |
81 | s_pathsToAssemblies[assembly.Location] = assembly;
82 | s_namesToAssemblies[name] = assembly;
83 |
84 | return assembly;
85 | }
86 |
87 | return null;
88 | }
89 | };
90 | }
91 |
92 | // Tries to find and return the specified assembly by looking in all the known locations where it could be found.
93 | private static bool TryResolveAssemblyFromPaths(AssemblyLoadContext context, AssemblyName assemblyName, string searchPath, [NotNullWhen(returnValue: true)] out Assembly? resolvedAssembly)
94 | {
95 | resolvedAssembly = null;
96 | foreach (string cultureSubfolder in GetCultureSubfolders(assemblyName))
97 | {
98 | foreach (string extension in s_candidateExtensions)
99 | {
100 | string candidatePath = Path.Combine(searchPath, cultureSubfolder, $"{assemblyName.Name}.{extension}");
101 | if (s_pathsToAssemblies.ContainsKey(candidatePath) || !File.Exists(candidatePath))
102 | {
103 | continue;
104 | }
105 |
106 | AssemblyName candidateAssemblyName = AssemblyLoadContext.GetAssemblyName(candidatePath);
107 | if (candidateAssemblyName.Version < assemblyName.Version)
108 | {
109 | continue;
110 | }
111 |
112 | try
113 | {
114 | resolvedAssembly = context.LoadFromAssemblyPath(candidatePath);
115 | return resolvedAssembly != null;
116 | }
117 | catch
118 | {
119 | if (assemblyName.Name != null)
120 | {
121 | // We were unable to load the assembly from the file path. It is likely that
122 | // a different version of the assembly has already been loaded into the context.
123 | // Be forgiving and attempt to load assembly by name without specifying a version.
124 | resolvedAssembly = context.LoadFromAssemblyName(new AssemblyName(assemblyName.Name));
125 | return resolvedAssembly != null;
126 | }
127 | }
128 | }
129 | }
130 |
131 | return false;
132 | }
133 |
134 | private static IEnumerable GetCultureSubfolders(AssemblyName assemblyName)
135 | {
136 | if (!string.IsNullOrEmpty(assemblyName.CultureName))
137 | {
138 | // Search for satellite assemblies in culture subdirectories of the assembly search
139 | // directories, but fall back to the bare search directory if that fails.
140 | yield return assemblyName.CultureName;
141 | }
142 | // If no culture is specified, attempt to load directly from the known dependency paths.
143 | yield return string.Empty;
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/XmlHelper.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Text.RegularExpressions;
8 | using System.Xml;
9 | using System.Xml.Linq;
10 |
11 | namespace ApiDocsSync.PortToTripleSlash
12 | {
13 | internal class XmlHelper
14 | {
15 | private static readonly (string, string)[] ReplaceableMarkdownPatterns = new[]
16 | {
17 | (@"\s*\s*", ""),
19 | (@"\s*##\s*Remarks\s*", ""),
20 | (@"`(?'keyword'null|false|true)`", ""),
21 | (@"(?'keyword'null|false|true)", ""),
22 | (@"\?\,]+)>", ""),
23 | (@"%601", "{T}")
24 | };
25 |
26 | public static string GetAttributeValue(XElement parent, string name)
27 | {
28 | if (parent == null)
29 | {
30 | throw new Exception($"A null parent was passed when attempting to get attribute '{name}'");
31 | }
32 | else
33 | {
34 | XAttribute? attr = parent.Attribute(name);
35 | if (attr != null)
36 | {
37 | return attr.Value.Trim();
38 | }
39 | }
40 | return string.Empty;
41 | }
42 |
43 | public static bool TryGetChildElement(XElement parent, string name, out XElement? child)
44 | {
45 | child = null;
46 |
47 | if (parent == null || string.IsNullOrWhiteSpace(name))
48 | return false;
49 |
50 | child = parent.Element(name);
51 |
52 | return child != null;
53 | }
54 |
55 | public static string GetChildElementValue(XElement parent, string childName)
56 | {
57 | XElement? child = parent.Element(childName);
58 |
59 | if (child != null)
60 | {
61 | return GetNodesInPlainText(childName, child);
62 | }
63 |
64 | return string.Empty;
65 | }
66 |
67 | public static string GetNodesInPlainText(string name, XElement element)
68 | {
69 | if (element == null)
70 | {
71 | throw new Exception("A null element was passed when attempting to retrieve the nodes in plain text.");
72 | }
73 |
74 | if (name == "remarks")
75 | {
76 | XElement? formatElement = element.Element("format");
77 | if (formatElement != null)
78 | {
79 | element = formatElement;
80 | }
81 | }
82 | // string.Join("", element.Nodes()) is very slow.
83 | //
84 | // The following is twice as fast (although still slow)
85 | // but does not produce the same spacing. That may be OK.
86 | //
87 | using XmlReader reader = element.CreateReader();
88 | reader.MoveToContent();
89 | string actualValue = reader.ReadInnerXml().Trim();
90 |
91 | if (name == "remarks")
92 | {
93 | actualValue = ReplaceMarkdown(actualValue);
94 | }
95 |
96 | return actualValue.IsDocsEmpty() ? string.Empty : actualValue;
97 | }
98 |
99 | private static string ReplaceMarkdown(string value)
100 | {
101 | foreach ((string bad, string good) in ReplaceableMarkdownPatterns)
102 | {
103 | value = Regex.Replace(value, bad, good);
104 | }
105 |
106 | return string.Join(Environment.NewLine, value.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/src/libraries/libraries.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net8.0
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/PortToTripleSlash.FileSystem.Tests.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.IO;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using ApiDocsSync.Tests;
8 | using Xunit;
9 | using Xunit.Abstractions;
10 |
11 | namespace ApiDocsSync.PortToTripleSlash.Tests
12 | {
13 | public class PortToTripleSlash_FileSystem_Tests : BasePortTests
14 | {
15 | public PortToTripleSlash_FileSystem_Tests(ITestOutputHelper output) : base(output)
16 | {
17 | }
18 |
19 | //[Fact]
20 | // TODO: Need to fix the remark conversion from markdown to xml.
21 | private Task Port_Basic() => PortToTripleSlashAsync("Basic");
22 |
23 | private static async Task PortToTripleSlashAsync(
24 | string testDataDir,
25 | bool skipInterfaceImplementations = true,
26 | string assemblyName = FileTestData.TestAssembly,
27 | string namespaceName = FileTestData.TestNamespace)
28 | {
29 | using TestDirectory tempDir = new();
30 |
31 | PortToTripleSlashTestData testData = new(
32 | tempDir,
33 | testDataDir,
34 | assemblyName,
35 | namespaceName);
36 |
37 | Configuration c = new()
38 | {
39 | CsProj = Path.GetFullPath(testData.ProjectFilePath),
40 | SkipInterfaceImplementations = skipInterfaceImplementations,
41 | BinLogPath = testData.BinLogPath,
42 | SkipRemarks = false
43 | };
44 |
45 | c.IncludedAssemblies.Add(assemblyName);
46 |
47 | if (!string.IsNullOrEmpty(namespaceName))
48 | {
49 | c.IncludedNamespaces.Add(namespaceName);
50 | }
51 |
52 | c.DirsDocsXml.Add(testData.DocsDir);
53 |
54 | CancellationTokenSource cts = new();
55 |
56 | VSLoader.LoadVSInstance();
57 | c.Loader = new MSBuildLoader(c.BinLogPath);
58 |
59 | await c.Loader.LoadMainProjectAsync(c.CsProj, c.IsMono, cts.Token);
60 |
61 | ToTripleSlashPorter porter = new(c);
62 | porter.CollectFiles();
63 |
64 | await porter.MatchSymbolsAsync(c.Loader.MainProject.Compilation, isMSBuildProject: true, cts.Token);
65 | await porter.PortAsync(isMSBuildProject: true, cts.Token);
66 |
67 | Verify(testData);
68 | }
69 |
70 | private static void Verify(PortToTripleSlashTestData testData)
71 | {
72 | string[] expectedLines = File.ReadAllLines(testData.ExpectedFilePath);
73 | string[] actualLines = File.ReadAllLines(testData.ActualFilePath);
74 |
75 | for (int i = 0; i < expectedLines.Length; i++)
76 | {
77 | string expectedLine = expectedLines[i];
78 | string actualLine = actualLines[i];
79 | if (System.Diagnostics.Debugger.IsAttached)
80 | {
81 | if (expectedLine != actualLine)
82 | {
83 | System.Diagnostics.Debugger.Break();
84 | }
85 | }
86 | Assert.Equal(expectedLine, actualLine);
87 | }
88 |
89 | Assert.Equal(expectedLines.Length, actualLines.Length);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/PortToTripleSlashTestData.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.IO;
5 | using ApiDocsSync.Tests;
6 | using Xunit;
7 |
8 | namespace ApiDocsSync.PortToTripleSlash.Tests
9 | {
10 | internal class PortToTripleSlashTestData : FileTestData
11 | {
12 | private const string BinLogFileName = "output.binlog";
13 | private const string SourceOriginal = "SourceOriginal.cs";
14 | private const string SourceExpected = "SourceExpected.cs";
15 | private const string ProjectDirName = "Project";
16 | private const string TestDataRootDirPath = @"../../../PortToTripleSlash/TestData";
17 |
18 | private DirectoryInfo ProjectDir { get; set; }
19 | internal string ProjectFilePath { get; set; }
20 | internal string BinLogPath { get; set; }
21 |
22 | internal PortToTripleSlashTestData(
23 | TestDirectory tempDir,
24 | string testDataDir,
25 | string assemblyName,
26 | string namespaceName)
27 | {
28 | Assert.False(string.IsNullOrWhiteSpace(assemblyName));
29 |
30 | namespaceName = string.IsNullOrEmpty(namespaceName) ? assemblyName : namespaceName;
31 |
32 | ProjectDir = tempDir.CreateSubdirectory(ProjectDirName);
33 |
34 | DocsDir = tempDir.CreateSubdirectory(DocsDirName);
35 | DirectoryInfo docsAssemblyDir = DocsDir.CreateSubdirectory(namespaceName);
36 |
37 | string testDataPath = Path.Combine(TestDataRootDirPath, testDataDir);
38 |
39 | foreach (string origin in Directory.EnumerateFiles(testDataPath, "*.xml"))
40 | {
41 | string fileName = Path.GetFileName(origin);
42 | string destination = Path.Combine(docsAssemblyDir.FullName, fileName);
43 | File.Copy(origin, destination);
44 | }
45 |
46 | string originCsOriginal = Path.Combine(testDataPath, SourceOriginal);
47 | ActualFilePath = Path.Combine(ProjectDir.FullName, SourceOriginal);
48 | File.Copy(originCsOriginal, ActualFilePath);
49 |
50 | string originCsExpected = Path.Combine(testDataPath, SourceExpected);
51 | ExpectedFilePath = Path.Combine(tempDir.FullPath, SourceExpected);
52 | File.Copy(originCsExpected, ExpectedFilePath);
53 |
54 | string originCsproj = Path.Combine(testDataPath, $"{assemblyName}.csproj");
55 | ProjectFilePath = Path.Combine(ProjectDir.FullName, $"{assemblyName}.csproj");
56 | File.Copy(originCsproj, ProjectFilePath);
57 |
58 | BinLogPath = Path.Combine(ProjectDir.FullName, BinLogFileName);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/StringTestData.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Collections.Generic;
5 | using System.Xml.Linq;
6 |
7 | namespace ApiDocsSync.PortToTripleSlash.Tests;
8 |
9 | internal class StringTestData
10 | {
11 | public StringTestData(IEnumerable docFiles, IEnumerable originalCodeFiles, Dictionary expectedCodeFiles, bool addMsCorLibReferences)
12 | {
13 | OriginalCodeFiles = originalCodeFiles;
14 | ExpectedCodeFiles = expectedCodeFiles;
15 | XDocs = new List();
16 | foreach (string docFile in docFiles)
17 | {
18 | XDocs.Add(XDocument.Parse(docFile));
19 | }
20 | AddMsCorLibReferences = addMsCorLibReferences;
21 | }
22 | public bool AddMsCorLibReferences { get; }
23 | public List XDocs { get; }
24 | public IEnumerable OriginalCodeFiles { get; }
25 | public Dictionary ExpectedCodeFiles { get; }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/TestData/Basic/MyAssembly.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | This is MyNamespace description.
6 | net7.0
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/TestData/Basic/MyDelegate.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 | This is the sender parameter.
8 | This is the MyDelegate summary.
9 |
10 |
11 | remarks. There is a code example, which should be moved to its own examples section:
16 |
17 | ## Examples
18 |
19 | Here is some text in the examples section. There is an that should be converted to xml.
20 |
21 | The snippet links below should be inserted in markdown.
22 |
23 | [!code-csharp[MyExample#1](~/samples/snippets/example.cs)]
24 | [!code-vb[MyExample#2](~/samples/snippets/example.vb)]
25 | [!code-cpp[MyExample#3](~/samples/snippets/example.cpp)]
26 |
27 | This text should be outside the cdata in xml: .
28 |
29 | ]]>
30 |
31 |
32 |
33 | The .NET Runtime repo.
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/TestData/Basic/MyEnum.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MyAssembly
5 |
6 |
7 | This is the MyEnum enum summary.
8 |
9 |
10 | enum remarks. They contain an [!INCLUDE[MyInclude](~/includes/MyInclude.md)] which should prevent converting markdown to xml.
15 |
16 | URL entities: %23%28%2C%29 must remain unconverted.
17 |
18 | ]]>
19 |
20 |
21 |
22 |
23 |
24 | Field
25 |
26 | MyAssembly
27 |
28 |
29 | MyNamespace.MyEnum
30 |
31 | 0
32 |
33 | This is the MyEnumValue0 member summary. There is no public modifier.
34 |
35 |
36 |
37 |
38 | Field
39 |
40 | MyAssembly
41 |
42 |
43 | MyNamespace.MyEnum
44 |
45 | 1
46 |
47 | This is the MyEnumValue1 member summary. There is no public modifier.
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/PortToTripleSlash/TestData/Basic/SourceOriginal.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MyNamespace
4 | {
5 | // Original MyEnum enum comments with information for maintainers, must stay.
6 | public enum MyEnum
7 | {
8 | MyEnumValue0 = 0,
9 |
10 | MyEnumValue1 = 1
11 | }
12 |
13 | // Original MyType class comments with information for maintainers, must stay.
14 | public class MyType
15 | {
16 | // Original MyType constructor double slash comments on top of triple slash, with information for maintainers, must stay but after triple slash.
17 | ///
18 | /// Original triple slash comments. They should be replaced.
19 | ///
20 | // Original MyType constructor double slash comments on bottom of triple slash, with information for maintainers, must stay.
21 | public MyType()
22 | {
23 | } /* Trailing comments should remain untouched */
24 |
25 | // Original double slash comments, must stay (internal method).
26 | internal MyType(int myProperty)
27 | {
28 | _myProperty = myProperty;
29 | } // Trailing comments should remain untouched
30 |
31 | ///
32 | /// Triple slash comments above private members should remain untouched.
33 | ///
34 | private int _otherProperty;
35 |
36 | // Double slash comments above private members should remain untouched.
37 | private int _myProperty;
38 |
39 | ///
40 | /// Original triple slash comments. They should be replaced.
41 | ///
42 | // Original MyProperty property double slash comments with information for maintainers, must stay.
43 | // This particular example has two rows of double slash comments and both should stay.
44 | public int MyProperty
45 | {
46 | get { return _myProperty; /* Internal comments should remain untouched. */ }
47 | set { _myProperty = value; } // Internal comments should remain untouched
48 | }
49 |
50 | public int MyField = 1;
51 |
52 | public int MyIntMethod(int param1, int param2)
53 | {
54 | // Internal comments should remain untouched.
55 | return MyField + param1 + param2;
56 | }
57 |
58 | public void MyVoidMethod()
59 | {
60 | }
61 |
62 | ///
63 | /// This method simulates a newly added API that did not have documentation in the docs xml.
64 | /// The developer added the documentation in triple slash comments, so they should be preserved
65 | /// and considered the source of truth.
66 | ///
67 | ///
68 | /// These remarks are the source of truth.
69 | ///
70 | public void UndocumentedMethod()
71 | {
72 | // Set MyEvent to a method of the shape of MyDelegate
73 | MyEvent = (object sender) => { if (sender is int i) { _otherProperty = i; } }; // Use _otherProperty to remove the unused warning
74 | if (MyEvent == null) { } // Use MyEvent to remove the unused warning
75 | }
76 |
77 | public void MyTypeParamMethod(int param1)
78 | {
79 | }
80 |
81 | // Original MyDelegate delegate comments with information for maintainers, must stay.
82 | public delegate void MyDelegate(object sender);
83 |
84 | public event MyDelegate MyEvent;
85 |
86 | // Original operator + method comments with information for maintainers, must stay.
87 | public static MyType operator +(MyType value1, MyType value2) => value1;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/PortToTripleSlash/tests/tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | all
33 | runtime; build; native; contentfiles; analyzers; buildtransitive
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------