diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index a873b6b..be28e25 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"docfx": {
- "version": "2.67.5",
+ "version": "2.78.3",
"commands": [
"docfx"
]
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..16e1a86
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,201 @@
+# editorconfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Default settings:
+# A newline ending every file
+# Use 4 spaces as indentation
+[*]
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+
+# Specify UTF-8 without byte-order mark
+[*.{csproj,locproj,nativeproj,proj,resx,slnx,vbproj}]
+charset = utf-8
+
+# Generated code
+[*{_AssemblyInfo.cs,.notsupported.cs,AsmOffsets.cs}]
+generated_code = true
+
+# C# files
+[*.cs]
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = false
+csharp_indent_switch_labels = true
+csharp_indent_labels = one_less_than_current
+
+# Modifier preferences
+csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion
+
+# avoid this. unless absolutely necessary
+dotnet_style_qualification_for_field = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+
+# Types: use keywords instead of BCL types, and permit var only when the type is clear
+csharp_style_var_for_built_in_types = false:suggestion
+csharp_style_var_when_type_is_apparent = false:none
+csharp_style_var_elsewhere = false:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# name all constant fields using PascalCase
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
+dotnet_naming_symbols.constant_fields.applicable_kinds = field
+dotnet_naming_symbols.constant_fields.required_modifiers = const
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# static fields should have s_ prefix
+dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
+dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
+dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
+dotnet_naming_symbols.static_fields.applicable_kinds = field
+dotnet_naming_symbols.static_fields.required_modifiers = static
+dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
+dotnet_naming_style.static_prefix_style.required_prefix = s_
+dotnet_naming_style.static_prefix_style.capitalization = camel_case
+
+# internal and private fields should be _camelCase
+dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
+dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
+dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
+dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
+dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
+dotnet_naming_style.camel_case_underscore_style.required_prefix = _
+dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
+
+# Code style defaults
+csharp_using_directive_placement = outside_namespace:suggestion
+dotnet_sort_system_directives_first = true
+csharp_prefer_braces = true:silent
+csharp_preserve_single_line_blocks = true:none
+csharp_preserve_single_line_statements = false:none
+csharp_prefer_static_local_function = true:suggestion
+csharp_prefer_simple_using_statement = false:none
+csharp_style_prefer_switch_expression = true:suggestion
+dotnet_style_readonly_field = true:suggestion
+
+# Expression-level preferences
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_collection_expression = when_types_exactly_match
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_auto_properties = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+csharp_prefer_simple_default_expression = true:suggestion
+
+# Expression-bodied members
+csharp_style_expression_bodied_methods = true:silent
+csharp_style_expression_bodied_constructors = true:silent
+csharp_style_expression_bodied_operators = true:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = true:silent
+
+# Pattern matching
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+
+# Null checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Other features
+csharp_style_prefer_index_operator = false:none
+csharp_style_prefer_range_operator = false:none
+csharp_style_pattern_local_over_anonymous_function = false:none
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = do_not_ignore
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# License header
+file_header_template =
+
+[src/libraries/System.Net.Http/src/System/Net/Http/{SocketsHttpHandler/Http3RequestStream.cs,BrowserHttpHandler/BrowserHttpHandler.cs}]
+# disable CA2025, the analyzer throws a NullReferenceException when processing this file: https://github.com/dotnet/roslyn-analyzers/issues/7652
+dotnet_diagnostic.CA2025.severity = none
+
+# C++ Files
+[*.{cpp,h,in}]
+curly_bracket_next_line = true
+indent_brace_style = Allman
+
+# Xml project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
+indent_size = 2
+
+# Xml build files
+[*.builds]
+indent_size = 2
+
+# Xml files
+[*.{resx,ruleset,slnx,stylecop,xml}]
+indent_size = 2
+
+# Xml resource files
+[*.resx]
+# match Visual Studio behavior
+insert_final_newline = false
+trim_trailing_whitespace = false
+
+# Xml config files
+[*.{props,targets,config,nuspec}]
+indent_size = 2
+
+# Data serialization
+[*.{json,yaml,yml}]
+indent_size = 2
+
+# Shell scripts
+[*.sh]
+end_of_line = lf
+[*.{cmd,bat}]
+end_of_line = crlf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..ab74a5b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,22 @@
+---
+name: ci
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+
+ - name: Install DocFX
+ run: dotnet tool restore
+
+ - name: Build & test (Release)
+ run: dotnet test -c Release
diff --git a/.github/workflows/tool.yml b/.github/workflows/tool.yml
new file mode 100644
index 0000000..bb18d7a
--- /dev/null
+++ b/.github/workflows/tool.yml
@@ -0,0 +1,52 @@
+---
+name: tool
+
+on:
+ push:
+ branches:
+ - main
+ tags:
+ - '*'
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+
+ - name: Should Deploy?
+ if: ${{ success() && github.event_name == 'push' }}
+ shell: pwsh
+ run: |
+ if ("${{github.ref}}" -match "^refs/tags/([0-9]+\.[0-9]+\.[0-9]+)")
+ {
+ $version = $Matches[1]
+
+ echo "UNITY_XREF_MAPS_DEPLOY=1" >> $env:GITHUB_ENV
+ echo "UNITY_XREF_MAPS_VERSION=$version" >> $env:GITHUB_ENV
+ }
+
+ - name: Pack
+ if: ${{ success() && env.UNITY_XREF_MAPS_DEPLOY != 1 }}
+ run: dotnet pack UnityXrefMaps/UnityXrefMaps.csproj -c Release -o ${{ runner.temp }}
+
+ - name: Pack (Release)
+ if: ${{ success() && env.UNITY_XREF_MAPS_DEPLOY == 1 }}
+ run: dotnet pack UnityXrefMaps/UnityXrefMaps.csproj -c Release -p:PackageVersion=$UNITY_XREF_MAPS_VERSION -o ${{ runner.temp }}
+
+ - name: NuGet login
+ if: ${{ success() && env.UNITY_XREF_MAPS_DEPLOY == 1 }}
+ uses: NuGet/login@v1
+ id: login
+ with:
+ user: ${{ secrets.NUGET_USER }}
+
+ - name: Publish (Release)
+ if: ${{ success() && env.UNITY_XREF_MAPS_DEPLOY == 1 }}
+ run: |
+ dotnet nuget push ${{ runner.temp }}/UnityXrefMaps.${{ env.UNITY_XREF_MAPS_VERSION }}.nupkg \
+ --source https://api.nuget.org/v3/index.json \
+ --api-key ${{ steps.login.outputs.NUGET_API_KEY }}
diff --git a/.github/workflows/unity-xref-maps.yml b/.github/workflows/unity-xref-maps.yml
index 2dcda65..6f416f1 100644
--- a/.github/workflows/unity-xref-maps.yml
+++ b/.github/workflows/unity-xref-maps.yml
@@ -1,3 +1,4 @@
+---
name: Unity xref maps
on:
@@ -10,25 +11,29 @@ on:
jobs:
build:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
+
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v5
- name: Install DocFX
run: dotnet tool restore
- - name: Cache UnityCsReference
- uses: actions/cache@v3
- with:
- path: UnityCsReference
- key: unitycsreference
+ - name: Restore
+ run: dotnet restore
+ working-directory: UnityXrefMaps
+
+ - name: Build
+ run: dotnet build --no-restore --configuration Release --output ${{ runner.temp }}/UnityXrefMaps
+ working-directory: UnityXrefMaps
- name: Run
- run: dotnet run
+ run: ${{ runner.temp }}/UnityXrefMaps/UnityXrefMaps.dll
+ working-directory: UnityXrefMaps
- name: Deploy
- uses: peaceiris/actions-gh-pages@v3
+ uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: _site
diff --git a/.gitignore b/.gitignore
index c58b5fd..ba7a514 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,428 @@
-.vscode/
-_site/
-bin/
-gh-pages/
-obj/
-Temp/
-UnityCsReference/
-*.cache
\ No newline at end of file
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+*.env
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+
+[Dd]ebug/x64/
+[Dd]ebugPublic/x64/
+[Rr]elease/x64/
+[Rr]eleases/x64/
+bin/x64/
+obj/x64/
+
+[Dd]ebug/x86/
+[Dd]ebugPublic/x86/
+[Rr]elease/x86/
+[Rr]eleases/x86/
+bin/x86/
+obj/x86/
+
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+[Aa][Rr][Mm]64[Ee][Cc]/
+bld/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Build results on 'Bin' directories
+**/[Bb]in/*
+# Uncomment if you have tasks that rely on *.refresh files to move binaries
+# (https://github.com/github/gitignore/pull/3736)
+#!**/[Bb]in/*.refresh
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+*.trx
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Approval Tests result files
+*.received.*
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.idb
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+# but not Directory.Build.rsp, as it configures directory-level build defaults
+!Directory.Build.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+**/.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+**/.fake/
+
+# CodeRush personal settings
+**/.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+**/__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+#tools/**
+#!tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+MSBuild_Logs/
+
+# AWS SAM Build and Temporary Artifacts folder
+.aws-sam
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+**/.mfractor/
+
+# Local History for Visual Studio
+**/.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+**/.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
\ No newline at end of file
diff --git a/Git.cs b/Git.cs
deleted file mode 100644
index 628e837..0000000
--- a/Git.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using System.IO;
-using LibGit2Sharp;
-
-namespace DocFxForUnity
-{
- public sealed class Git
- {
- ///
- /// Fetches changes and hard resets the specified repository to the latest commit of a specified branch. If no
- /// repository is found, it will be cloned before.
- ///
- /// The url of the repository.
- /// The directory path where to find/clone the repository.
- /// The branch use on the repository.
- /// The synced repository on the latest commit of the specified branch.
- public static Repository GetSyncRepository(string sourceUrl, string path, string branch = "main")
- {
- // Clone this repository to the specified branch if it doesn't exist
- bool clone = !Directory.Exists(path);
- if (clone)
- {
- Console.WriteLine($"Cloning {sourceUrl} to {path}");
-
- var options = new CloneOptions() { BranchName = branch };
- Repository.Clone(sourceUrl, path, options);
- }
-
- var repository = new Repository(path);
-
- // Otherwise fetch changes and checkout to the specified branch
- if (!clone)
- {
- Console.WriteLine($"Hard reset '{path}' to HEAD");
- repository.Reset(ResetMode.Hard);
- repository.RemoveUntrackedFiles();
-
- Console.WriteLine($"Fetching changes from 'origin' in '{path}'");
- var remote = repository.Network.Remotes["origin"];
- Commands.Fetch(repository, remote.Name, Array.Empty(), null, null); // WTF is this API libgit2sharp?
-
- Console.WriteLine($"Checking out '{path}' to '{branch}' branch");
- var remoteBranch = $"origin/{branch}";
- Commands.Checkout(repository, remoteBranch);
- }
-
- Console.WriteLine();
-
- return repository;
- }
- }
-}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE.txt
similarity index 100%
rename from LICENSE
rename to LICENSE.txt
diff --git a/Program.cs b/Program.cs
deleted file mode 100644
index 66b2c59..0000000
--- a/Program.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using LibGit2Sharp;
-
-namespace DocFxForUnity
-{
- ///
- /// Generates the xref maps of the APIs of all the Unity versions.
- ///
- /// Usage: Generate
- ///
- ///
- ///
- /// [.NET](https://dotnet.microsoft.com) >= 7.0 and [DocFX](https://dotnet.github.io/docfx/) must be installed
- /// on your system.
- ///
- partial class Program
- {
- ///
- /// The path where the documentation of the Unity repository will be generated.
- ///
- private const string GeneratedDocsPath = $"{UnityRepoPath}/_site";
-
- ///
- /// The path of the xref map generated by DocFX.
- ///
- private static readonly string GeneratedXrefMapPath = Path.Combine(GeneratedDocsPath, XrefMapFileName);
-
- ///
- /// The path of the default xref map, pointing at .
- ///
- private static readonly string DefaultXrefMapPath = Path.Combine(XrefMapsPath, XrefMapFileName);
-
- ///
- /// Gets the URL of the online API documentation of Unity.
- ///
- private const string UnityApiUrl = "https://docs.unity3d.com/ScriptReference/";
-
- [GeneratedRegex("\\d{4}\\.\\d")]
- private static partial Regex UnityVersionRegex();
-
- ///
- /// The path of the Unity repository.
- ///
- private const string UnityRepoPath = "UnityCsReference";
-
- ///
- /// The URL of the Unity repository.
- ///
- private const string UnityRepoUrl = "https://github.com/Unity-Technologies/UnityCsReference.git";
-
- ///
- /// The xref map filename.
- ///
- private const string XrefMapFileName = "xrefmap.yml";
-
- ///
- /// The path where to copy the xref maps.
- ///
- private const string XrefMapsPath = "_site";
-
- ///
- /// Entry point of this program.
- ///
- public static void Main()
- {
- Console.WriteLine($"Sync the Unity repository in '{UnityRepoPath}'");
- using var unityRepo = Git.GetSyncRepository(UnityRepoUrl, UnityRepoPath, branch: "master");
-
- var versions = GetLatestVersions(unityRepo);
- var latestVersion = versions
- .OrderByDescending(version => version.name)
- .First(version => version.release.Contains('f'));
-
- foreach (var version in versions)
- {
- Console.WriteLine($"Generating Unity '{version.name}' xref map");
- unityRepo.HardReset(version.release);
- string xrefMapPath = Path.Combine(XrefMapsPath, version.name, XrefMapFileName); // .//xrefmap.yml
-
- Console.WriteLine($"Running DocFX on '{version.release}'");
- Utils.RunCommand("dotnet", "docfx", Console.WriteLine, Console.WriteLine);
-
- if (!File.Exists(GeneratedXrefMapPath))
- {
- Console.WriteLine($"Error: '{GeneratedXrefMapPath}' for Unity '{version.name}' not generated");
- Console.WriteLine("\n");
- continue;
- }
-
- Console.WriteLine($"Fixing hrefs in '{xrefMapPath}'");
- Utils.CopyFile(GeneratedXrefMapPath, xrefMapPath);
- var xrefMap = XrefMap.Load(xrefMapPath);
- xrefMap.FixHrefs(apiUrl: $"https://docs.unity3d.com/{version.name}/Documentation/ScriptReference/");
- xrefMap.Save(xrefMapPath);
-
- // Set the last version's xref map as the default one
- if (version == latestVersion)
- {
- Console.WriteLine($"Fixing hrefs in '{DefaultXrefMapPath}'");
- Utils.CopyFile(GeneratedXrefMapPath, DefaultXrefMapPath);
- xrefMap = XrefMap.Load(DefaultXrefMapPath);
- xrefMap.FixHrefs(UnityApiUrl);
- xrefMap.Save(DefaultXrefMapPath);
- }
-
- Console.WriteLine("\n");
- }
- }
-
- ///
- /// Returns a collection of the latest versions of a specified repository of Unity.
- ///
- /// The repository of Unity to use.
- /// The latest versions.
- private static IEnumerable<(string name, string release)> GetLatestVersions(Repository unityRepository)
- {
- return unityRepository
- .GetTags()
- .Select(release => (name: UnityVersionRegex().Match(release).Value, release))
- .GroupBy(version => version.name)
- .Select(version => version.First());
- }
- }
-}
diff --git a/README.md b/README.md
index 75a83a0..13c105c 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
> Automatically add clickable links to the Unity API on a DocFX documentation
Generates references of the Unity API to use with DocFX (the
-[cross reference maps](https://dotnet.github.io/docfx/tutorial/links_and_cross_references.html#cross-reference-between-projects)).
+[cross reference maps](https://dotnet.github.io/docfx/docs/links-and-cross-references.html#cross-reference-to-net-basic-class-library)).
DocFX will set clickable all the references of the Unity API on your documentation.
## Usage
@@ -54,7 +54,7 @@ DocFX will set clickable all the references of the Unity API on your documentati
- To run this program:
1. Install Visual Studio 2022.
- 2. Install [.NET 7.0](https://dotnet.microsoft.com/download/dotnet) SDK.
+ 2. Install [.NET 9.0](https://dotnet.microsoft.com/download/dotnet) SDK.
3. Clone this repository on your computer.
4. Open a terminal on the cloned repository and run:
diff --git a/RepositoryExtensions.cs b/RepositoryExtensions.cs
deleted file mode 100644
index 8eb8b10..0000000
--- a/RepositoryExtensions.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using LibGit2Sharp;
-
-namespace DocFxForUnity;
-
-///
-/// Extension methods for .
-///
-public static class RepositoryExtensions
-{
- ///
- /// Returns a collection of the latest tags of a specified .
- ///
- /// The to use.
- /// The collection of tags.
- public static IEnumerable GetTags(this Repository repository)
- {
- return repository.Tags
- .OrderByDescending(tag => (tag.Target as Commit).Author.When)
- .Select(tag => tag.FriendlyName);
- }
-
- ///
- /// Hard resets the specified to the specified commit.
- ///
- /// The to hard reset to .
- /// The name of the commit where to reset .
- public static void HardReset(this Repository repository, string commit)
- {
- repository.Reset(ResetMode.Hard, commit);
-
- try
- {
- repository.RemoveUntrackedFiles();
- }
- catch (System.Exception) { }
- }
-}
\ No newline at end of file
diff --git a/UnityXrefMaps.Tests/CommandTests.cs b/UnityXrefMaps.Tests/CommandTests.cs
new file mode 100644
index 0000000..2101d20
--- /dev/null
+++ b/UnityXrefMaps.Tests/CommandTests.cs
@@ -0,0 +1,384 @@
+using Meziantou.Extensions.Logging.Xunit.v3;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Testing;
+using System;
+using System.Collections.Generic;
+using System.CommandLine;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using UnityXrefMaps.Commands;
+
+namespace UnityXrefMaps.Tests
+{
+ public class CommandTests : IAsyncLifetime, IAsyncDisposable
+ {
+ private string? _repositoryDirectoryPath;
+ private string? _xrefDirectoryPath;
+ private string? _docFxFilePath;
+ private string? _docFxFilterFilePath;
+
+ private class CustomStringWriter : StringWriter
+ {
+ private readonly ILogger logger;
+ private readonly LogLevel logLevel;
+
+ public CustomStringWriter(ILogger logger, LogLevel logLevel)
+ {
+ this.logger = logger;
+ this.logLevel = logLevel;
+ }
+
+ public override void Write(string? value)
+ {
+ base.Write(value);
+
+ logger.Log(logLevel, "{Message}", value);
+ }
+ }
+
+ private readonly ITestOutputHelper output;
+
+ public CommandTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+
+ [Fact]
+ public async Task UnityEditor_BuildTest_Success()
+ {
+ string docFxFileContent = await File.ReadAllTextAsync("docfx.json", TestContext.Current.CancellationToken);
+
+ docFxFileContent = docFxFileContent.Replace("UnityCsReference/", _repositoryDirectoryPath + '/');
+ docFxFileContent = docFxFileContent.Replace("filterConfig.yml", _docFxFilterFilePath);
+
+ await File.WriteAllTextAsync(_docFxFilePath!, docFxFileContent, TestContext.Current.CancellationToken);
+
+ string docFxFilterConfigContent = """
+### YamlMime:ManagedReference
+---
+apiRules:
+ - include:
+ uidRegex: ^UnityEngine\.Vector2$
+ - include:
+ uidRegex: ^UnityEngine\.Vector3$
+ - exclude:
+ uidRegex: .*
+""";
+
+ await File.WriteAllTextAsync(_docFxFilterFilePath!, docFxFilterConfigContent, TestContext.Current.CancellationToken);
+
+ var serviceCollection = new ServiceCollection();
+
+ serviceCollection.AddLogging(builder =>
+ {
+ builder.SetMinimumLevel(LogLevel.Trace);
+ builder.AddFakeLogging();
+ builder.Services.AddSingleton(new XUnitLoggerProvider(output, appendScope: false));
+ });
+
+ await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
+
+ FakeLogCollector fakeLogCollector = serviceProvider.GetFakeLogCollector();
+
+ ILoggerFactory loggerFactory = serviceProvider.GetRequiredService();
+
+ ILogger logger = loggerFactory.CreateLogger();
+
+ InvocationConfiguration invocationConfiguration = new()
+ {
+ Error = new CustomStringWriter(logger, LogLevel.Error),
+ Output = new CustomStringWriter(logger, LogLevel.Information),
+ };
+
+ string[] testedVersions = ["6000.0.1f1", "6000.1.1f1"];
+
+ BuildCommand buildCommand = new(loggerFactory.CreateLogger());
+
+ string xrefDirectoryName = "test";
+ string xrefFileName = "test2.yml";
+
+ string[] buildArgs = [
+ "--repositoryPath",
+ _repositoryDirectoryPath!,
+ "--docFxConfigurationFilePath",
+ _docFxFilePath!,
+ "--xrefMapsPath",
+ $"{_xrefDirectoryPath}/{xrefDirectoryName}/{{0}}/{xrefFileName}",
+ "--trimNamespaces",
+ "UnityEngine"
+ ];
+
+ buildArgs = [.. buildArgs, .. testedVersions.SelectMany(v => new string[] { "--repositoryTags", v })];
+
+ Assert.Equal(
+ 0,
+ await buildCommand
+ .Parse(buildArgs)
+ .InvokeAsync(
+ invocationConfiguration,
+ TestContext.Current.CancellationToken));
+
+ IReadOnlyList logRecords = fakeLogCollector.GetSnapshot();
+
+ Assert.Equal(2, logRecords.Count(l => l.Message.Contains("XRef map exported.", StringComparison.OrdinalIgnoreCase)));
+
+ foreach (string testedVersion in testedVersions)
+ {
+ string xrefFilePath = $"{_xrefDirectoryPath}/{xrefDirectoryName}/{testedVersion}/{xrefFileName}";
+
+ Assert.True(File.Exists(xrefFilePath));
+
+ string xrefFileContent = await File.ReadAllTextAsync(xrefFilePath, TestContext.Current.CancellationToken);
+
+ logger.LogInformation("{FilePath}:\n\n{FileContent}", xrefFilePath, xrefFileContent);
+ }
+
+ TestCommand testCommand = new(loggerFactory.CreateLogger());
+
+ foreach (string testedVersion in testedVersions)
+ {
+ fakeLogCollector.Clear();
+
+ string xrefFilePath = $"{_xrefDirectoryPath}/{xrefDirectoryName}/{testedVersion}/{xrefFileName}";
+
+ XrefMap xrefMap = await XrefMap.Load(xrefFilePath, TestContext.Current.CancellationToken);
+
+ Assert.Equal(3, xrefMap.References!.Length);
+
+ Assert.Equal("UnityEngine", xrefMap.References[0].Uid);
+ Assert.Equal("UnityEngine.Vector2", xrefMap.References[1].Uid);
+ Assert.Equal("UnityEngine.Vector3", xrefMap.References[2].Uid);
+
+ string[] testArgs = [
+ "--xrefPath",
+ xrefFilePath
+ ];
+
+ Assert.Equal(
+ 0,
+ await testCommand
+ .Parse(testArgs)
+ .InvokeAsync(
+ invocationConfiguration,
+ TestContext.Current.CancellationToken));
+
+ Assert.Equal(0, fakeLogCollector.Count);
+ }
+ }
+
+ [Fact]
+ public async Task UnityPackage_BuildTest_Success()
+ {
+ string docFxFileContent = await File.ReadAllTextAsync("docfx.json", TestContext.Current.CancellationToken);
+
+ docFxFileContent = docFxFileContent.Replace("UnityCsReference/Projects/CSharp/*.csproj", "UnityCsReference/InputSystem/**/*.cs");
+ docFxFileContent = docFxFileContent.Replace("UnityCsReference/", _repositoryDirectoryPath + '/');
+ docFxFileContent = docFxFileContent.Replace("filterConfig.yml", _docFxFilterFilePath);
+
+ await File.WriteAllTextAsync(_docFxFilePath!, docFxFileContent, TestContext.Current.CancellationToken);
+
+ string docFxFilterConfigContent = """
+### YamlMime:ManagedReference
+---
+apiRules:
+ - include:
+ uidRegex: ^UnityEngine\.InputSystem\.InputSystem$
+ - include:
+ uidRegex: ^UnityEngine\.InputSystem\.InputActionAsset$
+ - exclude:
+ uidRegex: .*
+""";
+
+ await File.WriteAllTextAsync(_docFxFilterFilePath!, docFxFilterConfigContent, TestContext.Current.CancellationToken);
+
+ var serviceCollection = new ServiceCollection();
+
+ serviceCollection.AddLogging(builder =>
+ {
+ builder.SetMinimumLevel(LogLevel.Trace);
+ builder.AddFakeLogging();
+ builder.Services.AddSingleton(new XUnitLoggerProvider(output, appendScope: false));
+ });
+
+ await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
+
+ FakeLogCollector fakeLogCollector = serviceProvider.GetFakeLogCollector();
+
+ ILoggerFactory loggerFactory = serviceProvider.GetRequiredService();
+
+ ILogger logger = loggerFactory.CreateLogger();
+
+ InvocationConfiguration invocationConfiguration = new()
+ {
+ Error = new CustomStringWriter(logger, LogLevel.Error),
+ Output = new CustomStringWriter(logger, LogLevel.Information),
+ };
+
+ string[] testedVersions = ["1.14.0", "1.14.2"];
+
+ BuildCommand buildCommand = new(loggerFactory.CreateLogger());
+
+ string xrefDirectoryName = "test";
+ string xrefFileName = "test2.yml";
+
+ string[] buildArgs = [
+ "--repositoryUrl",
+ "https://github.com/needle-mirror/com.unity.inputsystem.git",
+ "--repositoryPath",
+ _repositoryDirectoryPath!,
+ "--apiUrl",
+ "https://docs.unity3d.com/Packages/com.unity.inputsystem@{0}/api/",
+ "--docFxConfigurationFilePath",
+ _docFxFilePath!,
+ "--xrefMapsPath",
+ $"{_xrefDirectoryPath}/{xrefDirectoryName}/{{0}}/{xrefFileName}"
+ ];
+
+ buildArgs = [.. buildArgs, .. testedVersions.SelectMany(v => new string[] { "--repositoryTags", v })];
+
+ Assert.Equal(
+ 0,
+ await buildCommand
+ .Parse(buildArgs)
+ .InvokeAsync(
+ invocationConfiguration,
+ TestContext.Current.CancellationToken));
+
+ IReadOnlyList logRecords = fakeLogCollector.GetSnapshot();
+
+ Assert.Equal(2, logRecords.Count(l => l.Message.Contains("XRef map exported.", StringComparison.OrdinalIgnoreCase)));
+
+ foreach (string testedVersion in testedVersions)
+ {
+ string xrefFilePath = $"{_xrefDirectoryPath}/{xrefDirectoryName}/{testedVersion}/{xrefFileName}";
+
+ Assert.True(File.Exists(xrefFilePath));
+
+ string xrefFileContent = await File.ReadAllTextAsync(xrefFilePath, TestContext.Current.CancellationToken);
+
+ logger.LogInformation("{FilePath}:\n\n{FileContent}", xrefFilePath, xrefFileContent);
+ }
+
+ TestCommand testCommand = new(loggerFactory.CreateLogger());
+
+ foreach (string testedVersion in testedVersions)
+ {
+ fakeLogCollector.Clear();
+
+ string xrefFilePath = $"{_xrefDirectoryPath}/{xrefDirectoryName}/{testedVersion}/{xrefFileName}";
+
+ XrefMap xrefMap = await XrefMap.Load(xrefFilePath, TestContext.Current.CancellationToken);
+
+ Assert.Equal(3, xrefMap.References!.Length);
+
+ Assert.Equal("UnityEngine.InputSystem", xrefMap.References[0].Uid);
+ Assert.Equal("UnityEngine.InputSystem.InputActionAsset", xrefMap.References[1].Uid);
+ Assert.Equal("UnityEngine.InputSystem.InputSystem", xrefMap.References[2].Uid);
+
+ string[] testArgs = [
+ "--xrefPath",
+ xrefFilePath
+ ];
+
+ Assert.Equal(
+ 0,
+ await testCommand
+ .Parse(testArgs)
+ .InvokeAsync(
+ invocationConfiguration,
+ TestContext.Current.CancellationToken));
+
+ Assert.Equal(0, fakeLogCollector.Count);
+ }
+ }
+
+ // https://stackoverflow.com/a/1702920
+ private static void DeleteDirectory(string targetDir)
+ {
+ File.SetAttributes(targetDir, FileAttributes.Normal);
+
+ string[] files = Directory.GetFiles(targetDir);
+ string[] dirs = Directory.GetDirectories(targetDir);
+
+ foreach (string file in files)
+ {
+ File.SetAttributes(file, FileAttributes.Normal);
+ File.Delete(file);
+ }
+
+ foreach (string dir in dirs)
+ {
+ DeleteDirectory(dir);
+ }
+
+ Directory.Delete(targetDir, false);
+ }
+
+ public ValueTask InitializeAsync()
+ {
+ _repositoryDirectoryPath = Guid.NewGuid().ToString();
+ _xrefDirectoryPath = Guid.NewGuid().ToString();
+ _docFxFilePath = Guid.NewGuid().ToString() + "_config.json";
+ _docFxFilterFilePath = Guid.NewGuid().ToString() + "_filter_config.yml";
+
+ return ValueTask.CompletedTask;
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeAsyncCore().ConfigureAwait(false);
+
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual async ValueTask DisposeAsyncCore()
+ {
+ File.Delete(_docFxFilePath!);
+ File.Delete(_docFxFilterFilePath!);
+
+ const int maxRetries = 3;
+ const int delay = 500;
+
+ await DeleteDirectoryWithRetries(_repositoryDirectoryPath!, maxRetries, delay);
+ await DeleteDirectoryWithRetries(_xrefDirectoryPath!, maxRetries, delay);
+ }
+
+ private async Task DeleteDirectoryWithRetries(string directoryPath, int maxRetries, int delay)
+ {
+ int retries = 0;
+
+ while (retries < maxRetries)
+ {
+ try
+ {
+ output.WriteLine($"Trying to delete directory: {directoryPath}");
+
+ DeleteDirectory(directoryPath);
+
+ output.WriteLine($"Directory deleted: {directoryPath}");
+
+ break;
+ }
+ catch (Exception e)
+ {
+ output.WriteLine($"Error deleting directory: {directoryPath}. Error: {e}");
+
+ retries++;
+
+ if (retries < maxRetries)
+ {
+ output.WriteLine($"Retrying in {delay}ms...");
+
+ await Task.Delay(delay);
+ }
+ else
+ {
+ output.WriteLine("Retry limit reached.");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/UnityXrefMaps.Tests/UnityXrefMaps.Tests.csproj b/UnityXrefMaps.Tests/UnityXrefMaps.Tests.csproj
new file mode 100644
index 0000000..fc52459
--- /dev/null
+++ b/UnityXrefMaps.Tests/UnityXrefMaps.Tests.csproj
@@ -0,0 +1,39 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ false
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnityXrefMaps.csproj b/UnityXrefMaps.csproj
deleted file mode 100644
index 4dca7f2..0000000
--- a/UnityXrefMaps.csproj
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- Exe
- net7.0
- $(DefaultItemExcludes);UnityCsReference*\**
-
-
-
-
-
-
-
-
diff --git a/UnityXrefMaps.sln b/UnityXrefMaps.sln
new file mode 100644
index 0000000..ae261f7
--- /dev/null
+++ b/UnityXrefMaps.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36511.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityXrefMaps", "UnityXrefMaps\UnityXrefMaps.csproj", "{97BE34CD-6988-1F05-D1B2-EBF906DAA098}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityXrefMaps.Tests", "UnityXrefMaps.Tests\UnityXrefMaps.Tests.csproj", "{2A7A5BA2-A0E4-D775-C22B-0C5A6B68260B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {97BE34CD-6988-1F05-D1B2-EBF906DAA098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {97BE34CD-6988-1F05-D1B2-EBF906DAA098}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {97BE34CD-6988-1F05-D1B2-EBF906DAA098}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {97BE34CD-6988-1F05-D1B2-EBF906DAA098}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2A7A5BA2-A0E4-D775-C22B-0C5A6B68260B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A7A5BA2-A0E4-D775-C22B-0C5A6B68260B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A7A5BA2-A0E4-D775-C22B-0C5A6B68260B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A7A5BA2-A0E4-D775-C22B-0C5A6B68260B}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FCDA8159-7FB5-4653-8EBE-A68917137BBC}
+ EndGlobalSection
+EndGlobal
diff --git a/UnityXrefMaps/AssemblyInfo.cs b/UnityXrefMaps/AssemblyInfo.cs
new file mode 100644
index 0000000..08d26de
--- /dev/null
+++ b/UnityXrefMaps/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("UnityXrefMaps.Tests")]
diff --git a/UnityXrefMaps/Commands/BuildCommand.cs b/UnityXrefMaps/Commands/BuildCommand.cs
new file mode 100644
index 0000000..0eea3fe
--- /dev/null
+++ b/UnityXrefMaps/Commands/BuildCommand.cs
@@ -0,0 +1,152 @@
+using System.CommandLine;
+using System.IO;
+using System.Text.Json;
+using System.Text.RegularExpressions;
+using LibGit2Sharp;
+using Microsoft.Extensions.Logging;
+using UnityXrefMaps.DocFX;
+
+namespace UnityXrefMaps.Commands;
+
+internal sealed partial class BuildCommand : RootCommand
+{
+ public BuildCommand(ILogger logger)
+ {
+ Option repositoryUrlOption = new("--repositoryUrl")
+ {
+ Description = "The Git repository url.",
+ DefaultValueFactory = _ => Constants.DefaultUnityRepositoryUrl
+ };
+ Option repositoryBranchOption = new("--repositoryBranch")
+ {
+ Description = "The Git repository branch.",
+ DefaultValueFactory = _ => Constants.DefaultUnityRepositoryBranch
+ };
+ Option repositoryPathOption = new("--repositoryPath")
+ {
+ Description = "The Git repository path to git clone. " +
+ "If the clone has already been made, it will reset so that the clone can be reused.",
+ DefaultValueFactory = _ => Constants.DefaultUnityRepositoryPath
+ };
+ Option repositoryTagsOption = new("--repositoryTags")
+ {
+ Description = "The repository tags to use to generate the documentation. " +
+ "That is, the versions of the Unity editor (6000.0.1f1, 6000.1.1f1) or the versions of the Unity package (1.0.0, 1.1.0).",
+ Required = true
+ };
+ Option apiUrlOption = new("--apiUrl")
+ {
+ Description = "The root path of the Unity editor API documentation or the Unity package. " +
+ "{0} is replaced with the Unity editor short version (example: https://docs.unity3d.com/6000.0/Documentation/ScriptReference/) or " +
+ "the Unity package short version (example: https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/api/)}) in the case of a package.",
+ DefaultValueFactory = _ => Constants.DefaultUnityApiUrl
+ };
+ Option docFxConfigurationFilePathOption = new("--docFxConfigurationFilePath")
+ {
+ Description = "The path to the DocFX configuration file.",
+ DefaultValueFactory = _ => Constants.DefaultDocFxConfigurationFilePath
+ };
+ Option xrefMapsPathOption = new("--xrefMapsPath")
+ {
+ Description = $"The path where the final {Constants.DefaultXrefMapFileName} files will be generated. " +
+ $"{{0}} is replaced with the Unity editor version (example: {string.Format(Constants.DefaultXrefMapsPath, "6000.0.1f1")}) or " +
+ $"the Unity package version (example: {string.Format(Constants.DefaultXrefMapsPath, "1.0.0")}) in the case of a package.",
+ DefaultValueFactory = _ => Constants.DefaultXrefMapsPath
+ };
+ Option trimNamespacesOption = new("--trimNamespaces")
+ {
+ Description = "Namespaces for trimming."
+ };
+
+ Options.Add(repositoryUrlOption);
+ Options.Add(repositoryBranchOption);
+ Options.Add(repositoryPathOption);
+ Options.Add(repositoryTagsOption);
+ Options.Add(apiUrlOption);
+ Options.Add(docFxConfigurationFilePathOption);
+ Options.Add(xrefMapsPathOption);
+ Options.Add(trimNamespacesOption);
+
+ SetAction(async (parseResult, cancellationToken) =>
+ {
+ bool result = true;
+
+ string? repositoryUrl = parseResult.GetValue(repositoryUrlOption);
+ string? repositoryBranch = parseResult.GetValue(repositoryBranchOption);
+ string? repositoryPath = parseResult.GetValue(repositoryPathOption);
+ string[]? repositoryTags = parseResult.GetValue(repositoryTagsOption);
+ string? apiUrl = parseResult.GetValue(apiUrlOption);
+ string? docFxFilePath = parseResult.GetValue(docFxConfigurationFilePathOption);
+ string? xrefMapsPath = parseResult.GetValue(xrefMapsPathOption);
+ string[]? trimNamespaces = parseResult.GetValue(trimNamespacesOption);
+
+ using Stream docFxStream = File.OpenRead(docFxFilePath!);
+
+ DocFxConfiguration? docFxConfiguration = await JsonSerializer.DeserializeAsync(docFxStream, cancellationToken: cancellationToken);
+
+ string generatedDocsPath = docFxConfiguration!.Build!.Destination!;
+ string generatedXrefMapPath = Path.Combine(generatedDocsPath, Constants.DefaultXrefMapFileName!);
+
+ logger.LogInformation("Sync the Unity repository in '{RepositoryPath}'", Path.GetFullPath(repositoryPath!));
+
+ using Repository repository = Git.GetSyncRepository(repositoryUrl!, repositoryPath!, repositoryBranch!, logger);
+
+ foreach (string repositoryTag in repositoryTags!)
+ {
+ Match versionMatch = VersionRegex().Match(repositoryTag);
+
+ string shortVersion = $"{versionMatch.Groups["majorVersion"].Value}.{versionMatch.Groups["minorVersion"].Value}";
+
+ logger.LogInformation("Generating Unity '{ShortVersion}' xref map", shortVersion);
+
+ repository.HardReset(repositoryTag, logger);
+
+ string xrefMapPath = string.Format(xrefMapsPath!, repositoryTag); // .//xrefmap.yml
+
+ logger.LogInformation("Running DocFX on '{RepositoryTag}'", repositoryTag);
+
+ await Utils.RunCommand(
+ "dotnet", $"docfx {docFxFilePath}",
+ value =>
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ logger.LogInformation("{Message}", value);
+ }
+ },
+ value =>
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ logger.LogError("{Message}", value);
+ }
+ },
+ cancellationToken);
+
+ if (!File.Exists(generatedXrefMapPath))
+ {
+ result = false;
+
+ logger.LogError("Error: '{XrefMapFilePath}' for Unity '{RepositoryTag}' not generated", generatedXrefMapPath, repositoryTag);
+
+ continue;
+ }
+
+ logger.LogInformation("Fixing hrefs in '{XrefMapFilePath}'", Path.GetFullPath(xrefMapPath));
+
+ await Utils.CopyFile(generatedXrefMapPath, xrefMapPath, cancellationToken);
+
+ XrefMap xrefMap = await XrefMap.Load(xrefMapPath, cancellationToken);
+
+ xrefMap.FixHrefs(string.Format(apiUrl!, shortVersion), trimNamespaces!);
+
+ await xrefMap.Save(xrefMapPath, cancellationToken);
+ }
+
+ return result ? 0 : 1;
+ });
+ }
+
+ [GeneratedRegex(@"(?\d+)\.(?\d+)\.(?\d+)")]
+ private static partial Regex VersionRegex();
+}
diff --git a/UnityXrefMaps/Commands/TestCommand.cs b/UnityXrefMaps/Commands/TestCommand.cs
new file mode 100644
index 0000000..0ffe91d
--- /dev/null
+++ b/UnityXrefMaps/Commands/TestCommand.cs
@@ -0,0 +1,39 @@
+using System.CommandLine;
+using Microsoft.Extensions.Logging;
+
+namespace UnityXrefMaps.Commands;
+
+internal sealed class TestCommand : Command
+{
+ public TestCommand(ILogger logger) : base("test", $"Check that the links in the {Constants.DefaultXrefMapFileName} file are valid.")
+ {
+ Option xrefPathOption = new("--xrefPath")
+ {
+ Description = $"The path to the {Constants.DefaultXrefMapFileName} file.",
+ Required = true
+ };
+
+ Options.Add(xrefPathOption);
+
+ SetAction(async (parseResult, cancellationToken) =>
+ {
+ bool result = true;
+
+ string? xrefPath = parseResult.GetValue(xrefPathOption);
+
+ XrefMap xrefMap = await XrefMap.Load(xrefPath!, cancellationToken);
+
+ foreach (XrefMapReference reference in xrefMap.References!)
+ {
+ if (!await Utils.TestUriExists(reference.Href, logger, cancellationToken))
+ {
+ result = false;
+
+ logger.LogWarning("Invalid URL {Href} for {Uid} uid", reference.Href, reference.Uid);
+ }
+ }
+
+ return result ? 0 : 1;
+ });
+ }
+}
diff --git a/UnityXrefMaps/Constants.cs b/UnityXrefMaps/Constants.cs
new file mode 100644
index 0000000..d6af748
--- /dev/null
+++ b/UnityXrefMaps/Constants.cs
@@ -0,0 +1,40 @@
+namespace UnityXrefMaps;
+
+internal static class Constants
+{
+ ///
+ /// Gets the default URL of the online API documentation of Unity.
+ ///
+ public const string DefaultUnityApiUrl = "https://docs.unity3d.com/{0}/Documentation/ScriptReference/";
+
+ ///
+ /// The default path of the Unity repository.
+ ///
+ public const string DefaultUnityRepositoryPath = "UnityCsReference";
+
+ ///
+ /// The default URL of the Unity repository.
+ ///
+ public const string DefaultUnityRepositoryUrl = "https://github.com/Unity-Technologies/UnityCsReference.git";
+
+ ///
+ /// The default branch of the Unity repository.
+ ///
+ public const string DefaultUnityRepositoryBranch = "master";
+
+ // https://github.com/dotnet/docfx/blob/1c4e9ff4a2d236206eee04066847a98343c6a3f7/src/Docfx.Build/XRefMaps/XRefArchive.cs#L14
+ ///
+ /// The default xref map filename.
+ ///
+ public const string DefaultXrefMapFileName = "xrefmap.yml";
+
+ ///
+ /// The default path where to copy the xref maps.
+ ///
+ public const string DefaultXrefMapsPath = $"_site/{{0}}/{DefaultXrefMapFileName}";
+
+ ///
+ /// The default DocFX config file path.
+ ///
+ public const string DefaultDocFxConfigurationFilePath = "docfx.json";
+}
diff --git a/UnityXrefMaps/DocFX/DocFxConfiguration.cs b/UnityXrefMaps/DocFX/DocFxConfiguration.cs
new file mode 100644
index 0000000..8ce9db5
--- /dev/null
+++ b/UnityXrefMaps/DocFX/DocFxConfiguration.cs
@@ -0,0 +1,10 @@
+using System.Text.Json.Serialization;
+
+namespace UnityXrefMaps.DocFX;
+
+// https://github.com/dotnet/docfx/blob/main/src/Docfx.App/Config/DocfxConfig.cs
+public class DocFxConfiguration
+{
+ [JsonPropertyName("build")]
+ public DocFxConfigurationBuild? Build { get; set; }
+}
diff --git a/UnityXrefMaps/DocFX/DocFxConfigurationBuild.cs b/UnityXrefMaps/DocFX/DocFxConfigurationBuild.cs
new file mode 100644
index 0000000..455e495
--- /dev/null
+++ b/UnityXrefMaps/DocFX/DocFxConfigurationBuild.cs
@@ -0,0 +1,10 @@
+using System.Text.Json.Serialization;
+
+namespace UnityXrefMaps.DocFX;
+
+// https://github.com/dotnet/docfx/blob/main/src/Docfx.App/Config/BuildJsonConfig.cs
+public class DocFxConfigurationBuild
+{
+ [JsonPropertyName("dest")]
+ public string? Destination { get; set; }
+}
diff --git a/UnityXrefMaps/Git.cs b/UnityXrefMaps/Git.cs
new file mode 100644
index 0000000..1852aa6
--- /dev/null
+++ b/UnityXrefMaps/Git.cs
@@ -0,0 +1,49 @@
+using System.IO;
+using LibGit2Sharp;
+using Microsoft.Extensions.Logging;
+
+namespace UnityXrefMaps;
+
+internal static class Git
+{
+ ///
+ /// Fetches changes and hard resets the specified repository to the latest commit of a specified branch. If no
+ /// repository is found, it will be cloned before.
+ ///
+ /// The url of the repository.
+ /// The directory path where to find/clone the repository.
+ /// The branch use on the repository.
+ /// The synced repository on the latest commit of the specified branch.
+ public static Repository GetSyncRepository(string sourceUrl, string path, string branch, ILogger logger)
+ {
+ // Clone this repository to the specified branch if it doesn't exist
+ bool clone = !Directory.Exists(path);
+ if (clone)
+ {
+ logger.LogInformation("Cloning {SourceUrl} to {Path}", sourceUrl, path);
+
+ var options = new CloneOptions() { BranchName = branch };
+ Repository.Clone(sourceUrl, path, options);
+ }
+
+ var repository = new Repository(path);
+
+ // Otherwise fetch changes and checkout to the specified branch
+ if (!clone)
+ {
+ logger.LogInformation("Hard reset '{Path}' to HEAD", path);
+ repository.Reset(ResetMode.Hard);
+ repository.RemoveUntrackedFiles();
+
+ logger.LogInformation("Fetching changes from 'origin' in '{Path}'", path);
+ Remote remote = repository.Network.Remotes["origin"];
+ LibGit2Sharp.Commands.Fetch(repository, remote.Name, [], null, null); // WTF is this API libgit2sharp?
+
+ logger.LogInformation("Checking out '{Path}' to '{Branch}' branch", path, branch);
+ string remoteBranch = $"origin/{branch}";
+ LibGit2Sharp.Commands.Checkout(repository, remoteBranch);
+ }
+
+ return repository;
+ }
+}
diff --git a/UnityXrefMaps/Program.cs b/UnityXrefMaps/Program.cs
new file mode 100644
index 0000000..d1d809a
--- /dev/null
+++ b/UnityXrefMaps/Program.cs
@@ -0,0 +1,13 @@
+using System.CommandLine;
+using Microsoft.Extensions.Logging;
+using UnityXrefMaps.Commands;
+
+ILoggerFactory factory = LoggerFactory.Create(builder =>
+{
+ builder.AddConsole();
+});
+
+RootCommand rootCommand = new BuildCommand(factory.CreateLogger());
+rootCommand.Subcommands.Add(new TestCommand(factory.CreateLogger()));
+
+await rootCommand.Parse(args).InvokeAsync();
diff --git a/UnityXrefMaps/Properties/launchSettings.json b/UnityXrefMaps/Properties/launchSettings.json
new file mode 100644
index 0000000..34c8bae
--- /dev/null
+++ b/UnityXrefMaps/Properties/launchSettings.json
@@ -0,0 +1,9 @@
+{
+ "profiles": {
+ "DocFxForUnity": {
+ "commandName": "Project",
+ "commandLineArgs": "--repositoryTags 6000.0.1f1 --trimNamespaces UnityEditor --trimNamespaces UnityEngine"
+ }
+ },
+ "$schema": "http://json.schemastore.org/launchsettings.json"
+}
diff --git a/UnityXrefMaps/RepositoryExtensions.cs b/UnityXrefMaps/RepositoryExtensions.cs
new file mode 100644
index 0000000..67a42ab
--- /dev/null
+++ b/UnityXrefMaps/RepositoryExtensions.cs
@@ -0,0 +1,31 @@
+using System;
+using LibGit2Sharp;
+using Microsoft.Extensions.Logging;
+
+namespace UnityXrefMaps;
+
+///
+/// Extension methods for .
+///
+internal static class RepositoryExtensions
+{
+ ///
+ /// Hard resets the specified to the specified commit.
+ ///
+ /// The to hard reset to .
+ /// The name of the commit where to reset .
+ public static void HardReset(this Repository repository, string commit, ILogger logger)
+ {
+ logger.LogInformation("Hard reset to {Commit}", commit);
+
+ repository.Reset(ResetMode.Hard, commit);
+
+ try
+ {
+ logger.LogInformation($"Removing untracked files");
+
+ repository.RemoveUntrackedFiles();
+ }
+ catch (Exception) { }
+ }
+}
diff --git a/UnityXrefMaps/UnityXrefMaps.csproj b/UnityXrefMaps/UnityXrefMaps.csproj
new file mode 100644
index 0000000..d116153
--- /dev/null
+++ b/UnityXrefMaps/UnityXrefMaps.csproj
@@ -0,0 +1,36 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ true
+ unityXrefMaps
+ LICENSE.txt
+ README.md
+ https://github.com/NormandErwan/UnityXrefMaps
+ $(DefaultItemExcludes);UnityCsReference*\**
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
diff --git a/UnityXrefMaps/Utils.cs b/UnityXrefMaps/Utils.cs
new file mode 100644
index 0000000..8b88a27
--- /dev/null
+++ b/UnityXrefMaps/Utils.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace UnityXrefMaps;
+
+internal static class Utils
+{
+ ///
+ /// Client for send HTTP requests and receiving HTTP responses.
+ ///
+ private static readonly HttpClient s_httpClient = new();
+
+ ///
+ /// Copy a source file to a destination file. Intermediate folders will be automatically created.
+ ///
+ /// The path of the source file to copy.
+ /// The destination path of the copied file.
+ public static async Task CopyFile(string sourcePath, string destPath, CancellationToken cancellationToken = default)
+ {
+ string? destDirectoryPath = Path.GetDirectoryName(destPath);
+
+ Directory.CreateDirectory(destDirectoryPath!);
+
+ using Stream source = File.OpenRead(sourcePath);
+ using Stream destination = File.Create(destPath);
+
+ await source.CopyToAsync(destination, cancellationToken);
+ }
+
+ ///
+ /// Run a command in a hidden window and returns its output.
+ ///
+ /// The command to run.
+ /// The arguments of the command.
+ /// The function to call with the output data of the command.
+ /// The function to call with the error data of the command.
+ public static async Task RunCommand(string command, string arguments, Action output, Action error, CancellationToken cancellationToken = default)
+ {
+ using var process = new Process();
+ process.StartInfo = new ProcessStartInfo(command, arguments)
+ {
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ };
+
+ process.OutputDataReceived += (sender, args) => output(args.Data);
+ process.ErrorDataReceived += (sender, args) => error(args.Data);
+
+ process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
+ await process.WaitForExitAsync(cancellationToken);
+ }
+
+ ///
+ /// Requests the specified URI with and returns if the response status code is in the
+ /// range 200-299.
+ ///
+ /// The URI to request.
+ /// true if the response status code is in the range 200-299.
+ public static async Task TestUriExists(string? uri, ILogger logger, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ HttpResponseMessage response = await s_httpClient.SendAsync(new(HttpMethod.Head, uri), cancellationToken);
+
+ if (!response.IsSuccessStatusCode && response.StatusCode != System.Net.HttpStatusCode.NotFound)
+ {
+ logger.LogError("HTTP response code on {Uri} is {StatusCode}", uri, response.StatusCode);
+ }
+
+ return response.IsSuccessStatusCode;
+ }
+ catch (HttpRequestException e)
+ {
+ logger.LogError(e, "Exception on {Uri}", uri);
+
+ return false;
+ }
+ }
+}
diff --git a/UnityXrefMaps/XrefMap.cs b/UnityXrefMaps/XrefMap.cs
new file mode 100644
index 0000000..a253920
--- /dev/null
+++ b/UnityXrefMaps/XrefMap.cs
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using YamlDotNet.Serialization;
+
+namespace UnityXrefMaps;
+
+///
+/// Represents a xref map file of Unity.
+///
+public sealed partial class XrefMap
+{
+ private static readonly Deserializer s_deserializer = new();
+ private static readonly Serializer s_serializer = new();
+
+ [YamlMember(Alias = "sorted")]
+ public bool Sorted { get; set; }
+
+ [YamlMember(Alias = "references")]
+ public XrefMapReference[]? References { get; set; }
+
+ ///
+ /// Loads a from a file.
+ ///
+ /// The path of the file.
+ /// The loaded from .
+ public static async Task Load(string filePath, CancellationToken cancellationToken = default)
+ {
+ string xrefMapText = await File.ReadAllTextAsync(filePath, cancellationToken);
+
+ // Remove `0:` strings on the xrefmap that make crash Deserializer
+ xrefMapText = ZeroStringsRegex().Replace(xrefMapText, "$1");
+
+ return s_deserializer.Deserialize(xrefMapText);
+ }
+
+ ///
+ /// Fix the of of this .
+ ///
+ /// The URL of the online API documentation of Unity.
+ public void FixHrefs(string apiUrl, IEnumerable hrefNamespacesToTrim)
+ {
+ var fixedReferences = new List();
+
+ foreach (XrefMapReference reference in References!)
+ {
+ if (!reference.IsValid)
+ {
+ continue;
+ }
+
+ reference.FixHref(apiUrl, hrefNamespacesToTrim);
+ fixedReferences.Add(reference);
+ }
+
+ References = [.. fixedReferences];
+ }
+
+ ///
+ /// Saves this to a file.
+ ///
+ /// The path of the file.
+ public async Task Save(string filePath, CancellationToken cancellationToken = default)
+ {
+ string xrefMapText = "### YamlMime:XRefMap\n" + s_serializer.Serialize(this);
+
+ await File.WriteAllTextAsync(filePath, xrefMapText, cancellationToken);
+ }
+
+ [GeneratedRegex(@"(\d):")]
+ private static partial Regex ZeroStringsRegex();
+}
diff --git a/UnityXrefMaps/XrefMapReference.cs b/UnityXrefMaps/XrefMapReference.cs
new file mode 100644
index 0000000..330f12d
--- /dev/null
+++ b/UnityXrefMaps/XrefMapReference.cs
@@ -0,0 +1,113 @@
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using YamlDotNet.Serialization;
+
+namespace UnityXrefMaps;
+
+///
+/// Represents a reference item on a .
+///
+public sealed partial class XrefMapReference
+{
+ [YamlMember(Alias = "uid")]
+ public string? Uid { get; set; }
+
+ [YamlMember(Alias = "name")]
+ public string? Name { get; set; }
+
+ [YamlMember(Alias = "name.vb")]
+ public string? NameVb { get; set; }
+
+ [YamlMember(Alias = "href")]
+ public string? Href { get; set; }
+
+ [YamlMember(Alias = "commentId")]
+ public string? CommentId { get; set; }
+
+ [YamlMember(Alias = "isSpec")]
+ public string? IsSpec { get; set; }
+
+ [YamlMember(Alias = "fullName")]
+ public string? FullName { get; set; }
+
+ [YamlMember(Alias = "fullName.vb")]
+ public string? FullNameVb { get; set; }
+
+ [YamlMember(Alias = "nameWithType")]
+ public string? NameWithType { get; set; }
+
+ [YamlMember(Alias = "nameWithType.vb")]
+ public string? NameWithTypeVb { get; set; }
+
+ ///
+ /// Gets if this is valid or not.
+ ///
+ [YamlIgnore]
+ public bool IsValid => !CommentId!.Contains("Overload:");
+
+ ///
+ /// Sets to link to the online API documentation of Unity.
+ ///
+ /// The URL of the online API documentation of Unity.
+ public void FixHref(string apiUrl, IEnumerable hrefNamespacesToTrim)
+ {
+ // Namespaces point to documentation index
+ if (CommentId!.StartsWith("N:"))
+ {
+ Href = "index";
+ }
+ else
+ {
+ Href = Uid;
+
+ foreach (string hrefNamespaceToTrim in hrefNamespacesToTrim)
+ {
+ Href = Href!.Replace(hrefNamespaceToTrim + ".", string.Empty);
+ }
+
+ // Fix href of constructors
+ Href = Href!.Replace(".#ctor", "-ctor");
+
+ // Fix href of generics
+ Href = GenericHrefRegex().Replace(Href!, string.Empty);
+ Href = Href.Replace("`", "_");
+
+ // Fix href of methods
+ Href = MethodHrefPointerRegex().Replace(Href, string.Empty);
+ Href = MethodHrefRegex().Replace(Href, string.Empty);
+
+ // Fix href of operator
+ if (CommentId.StartsWith("M:") && CommentId.Contains(".op_"))
+ {
+ Href = Href.Replace(".op_", ".operator_");
+
+ Href = Href.Replace(".operator_Subtraction", ".operator_subtract");
+ Href = Href.Replace(".operator_Multiply", ".operator_multiply");
+ Href = Href.Replace(".operator_Division", ".operator_divide");
+ Href = Href.Replace(".operator_Addition", ".operator_add");
+ Href = Href.Replace(".operator_Equality", ".operator_eq");
+ Href = Href.Replace(".operator_Implicit~", ".operator_");
+ }
+
+ // Fix href of properties
+ if (CommentId.StartsWith("F:") || CommentId.StartsWith("M:") || CommentId.StartsWith("P:"))
+ {
+ Href = PropertyHrefRegex().Replace(Href, "-$1");
+ }
+ }
+
+ Href = apiUrl + Href + ".html";
+ }
+
+ [GeneratedRegex(@"`{2}\d")]
+ private static partial Regex GenericHrefRegex();
+
+ [GeneratedRegex(@"\*$")]
+ private static partial Regex MethodHrefPointerRegex();
+
+ [GeneratedRegex(@"\(.*\)")]
+ private static partial Regex MethodHrefRegex();
+
+ [GeneratedRegex(@"\.([a-z].*)$")]
+ private static partial Regex PropertyHrefRegex();
+}
diff --git a/docfx.json b/UnityXrefMaps/docfx.json
similarity index 70%
rename from docfx.json
rename to UnityXrefMaps/docfx.json
index ca2924d..eefbc5e 100644
--- a/docfx.json
+++ b/UnityXrefMaps/docfx.json
@@ -8,12 +8,14 @@
],
"filter": "filterConfig.yml",
"dest": "UnityCsReference/_api",
- "disableGitFeatures": true
+ "disableGitFeatures": true,
+ "allowCompilationErrors": true
}
],
- "build":
- {
- "xrefService": [ "https://xref.docs.microsoft.com/query?uid={uid}" ],
+ "build": {
+ "xref": [
+ "https://learn.microsoft.com/en-us/dotnet/.xrefmap.json"
+ ],
"content": [
{
"src": "UnityCsReference/_api",
@@ -23,4 +25,4 @@
],
"dest": "UnityCsReference/_site"
}
-}
\ No newline at end of file
+}
diff --git a/UnityXrefMaps/filterConfig.yml b/UnityXrefMaps/filterConfig.yml
new file mode 100644
index 0000000..b70045a
--- /dev/null
+++ b/UnityXrefMaps/filterConfig.yml
@@ -0,0 +1,24 @@
+### YamlMime:ManagedReference
+---
+apiRules:
+ - exclude:
+ uidRegex: ^AOT
+ - exclude:
+ uidRegex: ^JetBrains
+ - exclude:
+ uidRegex: ^TreeEditor
+ - exclude:
+ uidRegex: ^Unity\.CodeEditor
+ - exclude:
+ uidRegex: ^UnityEditorInternal
+ - exclude:
+ uidRegex: ^UnityEditor\.InspectorMode
+ - exclude:
+ uidRegex: ^UnityEngineInternal
+ - exclude:
+ uidRegex: ^UnityEngine.Internal
+ - exclude:
+ uidRegex: Finalize$
+ - exclude:
+ hasAttribute:
+ uid: UnityEngine.Internal.ExcludeFromDocsAttribute
diff --git a/Utils.cs b/Utils.cs
deleted file mode 100644
index b4ba405..0000000
--- a/Utils.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Net.Http;
-using System.Threading.Tasks;
-
-namespace DocFxForUnity
-{
- public sealed class Utils
- {
- ///
- /// Client for send HTTP requests and receiving HTTP responses.
- ///
- private static readonly HttpClient httpClient = new();
-
- ///
- /// Copy a source file to a destination file. Intermediate folders will be automatically created.
- ///
- /// The path of the source file to copy.
- /// The destination path of the copied file.
- public static void CopyFile(string sourcePath, string destPath)
- {
- var destDirectoryPath = Path.GetDirectoryName(destPath);
- Directory.CreateDirectory(destDirectoryPath);
-
- File.Copy(sourcePath, destPath, overwrite: true);
- }
-
- ///
- /// Deletes the specified directories if they exist.
- ///
- /// The path of the directories to delete.
- public static void DeleteDirectories(params string[] paths)
- {
- foreach (var path in paths)
- {
- if (Directory.Exists(path))
- {
- Directory.Delete(path, recursive: true);
- }
- }
- }
-
- ///
- /// Run a command in a hidden window and returns its output.
- ///
- /// The command to run.
- /// The arguments of the command.
- /// The function to call with the output data of the command.
- /// The function to call with the error data of the command.
- public static void RunCommand(string command, string arguments, Action output, Action error)
- {
- using var process = new Process();
- process.StartInfo = new ProcessStartInfo(command, arguments)
- {
- UseShellExecute = false,
- CreateNoWindow = true,
- RedirectStandardOutput = true,
- RedirectStandardError = true
- };
-
- process.OutputDataReceived += (sender, args) => output(args.Data);
- process.ErrorDataReceived += (sender, args) => error(args.Data);
-
- process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
-
- process.WaitForExit();
- }
-
- ///
- /// Requests the specified URI with and returns if the response status code is in the
- /// range 200-299.
- ///
- /// The URI to request.
- /// true if the response status code is in the range 200-299.
- public static async Task TestUriExists(string uri)
- {
- try
- {
- var headRequest = new HttpRequestMessage(HttpMethod.Head, uri);
- var response = await httpClient.SendAsync(headRequest);
- if (!response.IsSuccessStatusCode && response.StatusCode != System.Net.HttpStatusCode.NotFound)
- {
- Console.Error.WriteLine($"Error: HTTP response code on {uri} is {response.StatusCode}");
- }
- return response.IsSuccessStatusCode;
- }
- catch (HttpRequestException e)
- {
- Console.WriteLine($"Exception on {uri}: {e.Message}");
- return false;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/XrefMap.cs b/XrefMap.cs
deleted file mode 100644
index dfb6338..0000000
--- a/XrefMap.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text.RegularExpressions;
-using YamlDotNet.Serialization;
-
-namespace DocFxForUnity
-{
- ///
- /// Represents a xref map file of Unity.
- ///
- public sealed partial class XrefMap
- {
- private static readonly Deserializer Deserializer = new();
- private static readonly Serializer Serializer = new();
-
- [GeneratedRegex("(\\d):")]
- private static partial Regex ZeroStringsRegex();
-
- public bool sorted { get; set; }
-
- public XrefMapReference[] references { get; set; }
-
- ///
- /// Loads a from a file.
- ///
- /// The path of the file.
- /// The loaded from .
- public static XrefMap Load(string filePath)
- {
- string xrefMapText = File.ReadAllText(filePath);
-
- // Remove `0:` strings on the xrefmap that make crash Deserializer
- xrefMapText = ZeroStringsRegex().Replace(xrefMapText, "$1");
-
- return Deserializer.Deserialize(xrefMapText);
- }
-
- ///
- /// Fix the of of this .
- ///
- /// The URL of the online API documentation of Unity.
- public void FixHrefs(string apiUrl, bool testUrls = false)
- {
- var fixedReferences = new List();
- foreach (var reference in references)
- {
- if (!reference.IsValid)
- {
- continue;
- }
-
- reference.FixHref(apiUrl);
- fixedReferences.Add(reference);
-
- if (testUrls && !Utils.TestUriExists(reference.href).Result)
- {
- Console.WriteLine("Warning: invalid URL " + reference.href + " for " + reference.uid + " uid");
- }
- }
- references = fixedReferences.ToArray();
- }
-
- ///
- /// Saves this to a file.
- ///
- /// The path of the file.
- public void Save(string filePath)
- {
- string xrefMapText = "### YamlMime:XRefMap\n" + Serializer.Serialize(this);
- File.WriteAllText(filePath, xrefMapText);
- }
- }
-}
\ No newline at end of file
diff --git a/XrefMapReference.cs b/XrefMapReference.cs
deleted file mode 100644
index 7f8acf0..0000000
--- a/XrefMapReference.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System.Collections.Generic;
-using System.Text.RegularExpressions;
-using YamlDotNet.Serialization;
-
-namespace DocFxForUnity
-{
- ///
- /// Represents a reference item on a .
- ///
- public sealed partial class XrefMapReference
- {
- ///
- /// The online API documentation of Unity doesn't show some namespaces.
- ///
- private static readonly List HrefNamespacesToTrim = new() { "UnityEditor", "UnityEngine" };
-
- [GeneratedRegex("`{2}\\d")]
- private static partial Regex GenericHrefRegex();
-
- [GeneratedRegex("\\*$")]
- private static partial Regex MethodHrefPointerRegex();
-
- [GeneratedRegex("\\(.*\\)")]
- private static partial Regex MethodHrefRegex();
-
- [GeneratedRegex("\\.([a-z].*)$")]
- private static partial Regex PropertyHrefRegex();
-
- public string uid { get; set; }
-
- public string name { get; set; }
-
- [YamlMember(Alias = "name.vb")]
- public string nameVb { get; set; }
-
- public string href { get; set; }
-
- public string commentId { get; set; }
-
- public string isSpec { get; set; }
-
- public string fullName { get; set; }
-
- [YamlMember(Alias = "fullName.vb")]
- public string fullNameVb { get; set; }
-
- public string nameWithType { get; set; }
-
- [YamlMember(Alias = "nameWithType.vb")]
- public string nameWithTypeVb { get; set; }
-
- ///
- /// Gets if this is valid or not.
- ///
- public bool IsValid => !commentId.Contains("Overload:");
-
- ///
- /// Sets to link to the online API documentation of Unity.
- ///
- /// The URL of the online API documentation of Unity.
- public void FixHref(string apiUrl)
- {
- // Namespaces point to documentation index
- if (commentId.Contains("N:"))
- {
- href = "index";
- }
- else
- {
- href = uid;
-
- // Trim UnityEngine and UnityEditor namespaces from href
- foreach (var hrefNamespaceToTrim in HrefNamespacesToTrim)
- {
- href = href.Replace(hrefNamespaceToTrim + ".", "");
- }
-
- // Fix href of constructors
- href = href.Replace(".#ctor", "-ctor");
-
- // Fix href of generics
- href = GenericHrefRegex().Replace(href, "");
- href = href.Replace("`", "_");
-
- // Fix href of methods
- href = MethodHrefPointerRegex().Replace(href, "");
- href = MethodHrefRegex().Replace(href, "");
-
- // Fix href of properties
- if (commentId.Contains("P:") || commentId.Contains("M:"))
- {
- href = PropertyHrefRegex().Replace(href, "-$1");
- }
- }
-
- href = apiUrl + href + ".html";
- }
- }
-}
\ No newline at end of file
diff --git a/filterConfig.yml b/filterConfig.yml
deleted file mode 100644
index e4aef4c..0000000
--- a/filterConfig.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-apiRules:
-- exclude:
- uidRegex: ^AOT
-- exclude:
- uidRegex: ^JetBrains
-- exclude:
- uidRegex: ^TreeEditor
-- exclude:
- uidRegex: ^Unity\.CodeEditor
-- exclude:
- uidRegex: ^UnityEditorInternal
-- exclude:
- uidRegex: ^UnityEditor\.InspectorMode
-- exclude:
- uidRegex: ^UnityEngineInternal
-- exclude:
- uidRegex: ^UnityEngine.Internal
-- exclude:
- uidRegex: Finalize$
-- exclude:
- hasAttribute:
- uid: UnityEngine.Internal.ExcludeFromDocsAttribute
\ No newline at end of file