com.wallstop-studios.unity-helpers 2.0.0-rc81.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/.editorconfig +1 -1
  2. package/.gitattributes +1 -1
  3. package/.githooks/pre-commit +31 -5
  4. package/.githooks/pre-push +50 -0
  5. package/.github/dependabot.yml +24 -2
  6. package/.github/scripts/check-markdown-links.ps1 +77 -0
  7. package/.github/scripts/check_markdown_links.py +89 -0
  8. package/.github/scripts/check_markdown_url_encoding.py +74 -0
  9. package/.github/scripts/validate_markdown_links.py +194 -0
  10. package/.github/workflows/csharpier-autofix.yml +152 -0
  11. package/.github/workflows/format-on-demand.yml +305 -0
  12. package/.github/workflows/lint-doc-links.yml +8 -5
  13. package/.github/workflows/markdown-json.yml +6 -2
  14. package/.github/workflows/prettier-autofix.yml +195 -0
  15. package/.github/workflows/update-dotnet-tools.yml +80 -0
  16. package/.github/workflows/yaml-format-lint.yml +41 -0
  17. package/.lychee.toml +4 -4
  18. package/.markdownlint.jsonc +21 -0
  19. package/.pre-commit-config.yaml +11 -3
  20. package/.yamllint.yaml +31 -0
  21. package/AGENTS.md +5 -1
  22. package/CHANGELOG.md +11 -0
  23. package/CONTRIBUTING.md +49 -0
  24. package/CONTRIBUTING.md.meta +7 -0
  25. package/EDITOR_TOOLS_GUIDE.md +4 -0
  26. package/Editor/AnimationEventEditor.cs +337 -160
  27. package/Editor/Core/Helper/AnimationEventHelpers.cs +178 -152
  28. package/Editor/CustomEditors/PersistentDirectoryGUI.cs +20 -11
  29. package/Editor/CustomEditors/TexturePlatformOverrideEntryDrawer.cs +11 -2
  30. package/Editor/FitTextureSizeWindow.cs +43 -19
  31. package/Editor/PersistentDirectorySettings.cs +64 -12
  32. package/Editor/PrefabChecker.cs +72 -5
  33. package/Editor/Sprites/AnimationCopier.cs +132 -56
  34. package/Editor/Sprites/AnimationCreator.cs +63 -22
  35. package/Editor/Sprites/AnimationViewerWindow.cs +42 -6
  36. package/Editor/Sprites/TexturePlatformNameHelper.cs +50 -39
  37. package/Editor/Sprites/TextureResizerWizard.cs +23 -1
  38. package/Editor/Sprites/TextureSettingsApplierWindow.cs +148 -85
  39. package/Editor/Tools/ImageBlurTool.cs +81 -10
  40. package/Editor/Utils/EditorUi.cs +1 -1
  41. package/Editor/Utils/ScriptableObjectSingletonCreator.cs +1 -1
  42. package/GETTING_STARTED.md +40 -56
  43. package/RANDOM_PERFORMANCE.md +12 -12
  44. package/README.md +395 -2407
  45. package/RELATIONAL_COMPONENTS.md +92 -83
  46. package/Runtime/AssemblyInfo.cs +2 -0
  47. package/Runtime/Core/Attributes/NotNullAttribute.cs +1 -3
  48. package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +50 -5
  49. package/Runtime/Core/DataStructure/CyclicBuffer.cs +0 -1
  50. package/Runtime/Core/Extension/RandomExtensions.cs +68 -0
  51. package/Runtime/Core/Extension/WallstopStudiosLogger.cs +16 -0
  52. package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +4 -1
  53. package/Runtime/Core/Helper/ReflectionHelpers.cs +21 -10
  54. package/Runtime/Core/Helper/SpriteHelpers.cs +3 -1
  55. package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +45 -1
  56. package/Runtime/Core/Serialization/JsonConverters/GameObjectConverter.cs +13 -5
  57. package/Runtime/Core/Serialization/JsonConverters/ResolutionConverter.cs +1 -1
  58. package/Runtime/Core/Serialization/JsonConverters/TypeConverter.cs +1 -1
  59. package/Runtime/Core/Serialization/Serializer.cs +101 -0
  60. package/Runtime/Integrations/VContainer/AssemblyInfo.cs +9 -0
  61. package/Runtime/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
  62. package/Runtime/Integrations/VContainer/ObjectResolverRelationalExtensions.cs +96 -0
  63. package/Runtime/Integrations/VContainer/RelationalComponentEntryPoint.cs +90 -10
  64. package/Runtime/Integrations/VContainer/RelationalComponentsBuilderExtensions.cs +13 -1
  65. package/Runtime/Integrations/VContainer/RelationalObjectPools.cs +114 -0
  66. package/Runtime/Integrations/VContainer/RelationalObjectPools.cs.meta +11 -0
  67. package/Runtime/Integrations/VContainer/RelationalSceneAssignmentOptions.cs +16 -4
  68. package/Runtime/Integrations/VContainer/RelationalSceneLoadListener.cs +241 -0
  69. package/Runtime/Integrations/VContainer/RelationalSceneLoadListener.cs.meta +11 -0
  70. package/Runtime/Integrations/Zenject/AssemblyInfo.cs +9 -0
  71. package/Runtime/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
  72. package/Runtime/Integrations/Zenject/DiContainerRelationalExtensions.cs +69 -2
  73. package/Runtime/Integrations/Zenject/RelationalComponentSceneInitializer.cs +89 -12
  74. package/Runtime/Integrations/Zenject/RelationalComponentsInstaller.cs +23 -1
  75. package/Runtime/Integrations/Zenject/RelationalMemoryPools.cs +44 -0
  76. package/Runtime/Integrations/Zenject/RelationalMemoryPools.cs.meta +11 -0
  77. package/Runtime/Integrations/Zenject/RelationalSceneAssignmentOptions.cs +16 -10
  78. package/Runtime/Integrations/Zenject/RelationalSceneLoadListener.cs +243 -0
  79. package/Runtime/Integrations/Zenject/RelationalSceneLoadListener.cs.meta +11 -0
  80. package/Runtime/Tags/AttributeMetadataCache.cs +1 -4
  81. package/Runtime/Utils/Buffers.cs +4 -4
  82. package/Runtime/Utils/ScriptableObjectSingleton.cs +0 -1
  83. package/Runtime/Utils/SetTextureImportData.cs +3 -1
  84. package/Runtime/Utils/TextureScale.cs +10 -2
  85. package/Runtime/Visuals/UGUI/EnhancedImage.cs +6 -0
  86. package/Runtime/Visuals/UIToolkit/LayeredImage.cs +4 -1
  87. package/SERIALIZATION.md +15 -0
  88. package/SPATIAL_TREE_2D_PERFORMANCE.md +85 -82
  89. package/SPATIAL_TREE_3D_PERFORMANCE.md +94 -91
  90. package/Samples~/DI - VContainer/README.md +232 -51
  91. package/Samples~/DI - VContainer/Scripts/GameLifetimeScope.cs +22 -4
  92. package/Samples~/DI - VContainer/Scripts/RelationalConsumer.cs +5 -2
  93. package/Samples~/DI - VContainer/Scripts/Spawner.cs +113 -4
  94. package/Samples~/DI - Zenject/README.md +217 -53
  95. package/Samples~/DI - Zenject/Scripts/RelationalConsumer.cs +3 -0
  96. package/Samples~/DI - Zenject/Scripts/RelationalConsumerPool.cs +37 -0
  97. package/Samples~/DI - Zenject/Scripts/RelationalConsumerPool.cs.meta +12 -0
  98. package/Samples~/DI - Zenject/Scripts/SpawnerZenject.cs +74 -3
  99. package/Samples~/Random - PRNG/README.md +2 -1
  100. package/Samples~/Relational Components - Basic/README.md +3 -1
  101. package/Samples~/Serialization - JSON/README.md +2 -1
  102. package/Samples~/Spatial Structures - 2D and 3D/README.md +2 -1
  103. package/Samples~/UGUI - EnhancedImage/README.md +2 -1
  104. package/Samples~/UI Toolkit - MultiFile Selector (Editor)/README.md +2 -1
  105. package/THIRD_PARTY_NOTICES.md +1 -1
  106. package/Tests/Editor/Attributes/AnimationEventHelpersTests.cs +16 -0
  107. package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +3 -3
  108. package/Tests/Editor/Integrations/VContainer/VContainerRelationalEntryPointTests.cs +6 -2
  109. package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs +170 -0
  110. package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs.meta +11 -0
  111. package/Tests/Editor/Integrations/VContainer/WallstopStudios.UnityHelpers.Tests.Editor.VContainer.asmdef +2 -1
  112. package/Tests/Editor/Integrations/Zenject/WallstopStudios.UnityHelpers.Tests.Editor.Zenject.asmdef +3 -2
  113. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs +131 -0
  114. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs.meta +11 -0
  115. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalInitializerTests.cs +6 -2
  116. package/Tests/Editor/PersistentDirectorySettingsTests.cs +59 -0
  117. package/Tests/Editor/PersistentDirectorySettingsTests.cs.meta +11 -0
  118. package/Tests/Editor/PrefabCheckerReportTests.cs +32 -0
  119. package/Tests/Editor/PrefabCheckerReportTests.cs.meta +11 -0
  120. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +64 -0
  121. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs.meta +11 -0
  122. package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +1 -1
  123. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +38 -0
  124. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs.meta +11 -0
  125. package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +1 -1
  126. package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +12 -12
  127. package/Tests/Editor/Sprites/SpriteCropperTests.cs +9 -9
  128. package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +3 -3
  129. package/Tests/Editor/Sprites/TexturePlatformNameHelperTests.cs +18 -0
  130. package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +5 -5
  131. package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +3 -3
  132. package/Tests/Editor/Sprites/TextureSettingsApplierWizardAdditionalTests.cs +4 -4
  133. package/Tests/Editor/Sprites/TextureSettingsApplierWizardTests.cs +4 -4
  134. package/Tests/Editor/Tools/ImageBlurToolTests.cs +22 -110
  135. package/Tests/Editor/Utils/CommonTestBase.cs +43 -1
  136. package/Tests/Editor/Utils/ScriptableObjectSingletonCreatorTests.cs +5 -5
  137. package/Tests/Editor/Windows/FitTextureSizeWindowTests.cs +66 -74
  138. package/Tests/Runtime/Attributes/RelationalComponentInitializerTests.cs +4 -15
  139. package/Tests/Runtime/DataStructures/SpatialTree3DBoundsConsistencyTests.cs +29 -29
  140. package/Tests/Runtime/Integrations/VContainer/RelationalComponentsVContainerTests.cs +259 -218
  141. package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs +86 -0
  142. package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs.meta +11 -0
  143. package/Tests/Runtime/Integrations/Zenject/RelationalComponentsZenjectTests.cs +255 -227
  144. package/Tests/Runtime/Performance/SpatialTree2DPerformanceTests.cs +5 -0
  145. package/Tests/Runtime/Performance/SpatialTree3DPerformanceTests.cs +3 -0
  146. package/Tests/Runtime/Serialization/JsonConverterAdditionalTests.cs +30 -0
  147. package/Tests/Runtime/Serialization/JsonConverterAdditionalTests.cs.meta +11 -0
  148. package/Tests/Runtime/Serialization/JsonConverterTests.cs +8 -12
  149. package/Tests/Runtime/Serialization/JsonSerializationTest.cs +16 -5
  150. package/Tests/Runtime/Serialization/SerializerAdditionalTests.cs +12 -0
  151. package/Tests/Runtime/Serialization/SerializerFileIoTests.cs +105 -0
  152. package/Tests/Runtime/Serialization/SerializerFileIoTests.cs.meta +11 -0
  153. package/Tests/Runtime/Serialization/UnityEngineObjectJsonTests.cs +247 -0
  154. package/Tests/Runtime/Serialization/UnityEngineObjectJsonTests.cs.meta +11 -0
  155. package/Tests/Runtime/TestUtils/CommonTestBase.cs +88 -0
  156. package/Tests/Runtime/Utils/CoroutineHandlerTests.cs +1 -1
  157. package/Tests/Runtime/Utils/LZMAComprehensiveTests.cs +1 -1
  158. package/Tests/Runtime/Utils/LZMATests.cs +1 -1
  159. package/Tests/Runtime/Utils/MatchColliderToSpriteTests.cs +1 -1
  160. package/Tests/Runtime/Visuals/EnhancedImageTests.cs +25 -56
  161. package/Tests/Runtime/Visuals/VisualsTestHelpers.cs +1 -8
  162. package/package-lock.json.meta +7 -0
  163. package/package.json +8 -4
  164. package/scripts/check-eol.ps1 +4 -5
  165. package/scripts/lint-tests.ps1 +156 -0
  166. package/scripts/lint-tests.ps1.meta +7 -0
  167. package/scripts/normalize-eol.ps1 +6 -9
  168. package/.github/workflows/csharpier.yml +0 -135
@@ -0,0 +1,152 @@
1
+ name: CSharpier Auto Format
2
+
3
+ on:
4
+ pull_request:
5
+ pull_request_target:
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ format:
14
+ name: Format and propose changes
15
+ if: ${{ github.event_name != 'pull_request_target' }}
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - name: Checkout
19
+ uses: actions/checkout@v5
20
+ with:
21
+ fetch-depth: 0
22
+
23
+ - name: Setup .NET
24
+ uses: actions/setup-dotnet@v5
25
+ with:
26
+ dotnet-version: "8.0.x"
27
+
28
+ - name: Restore .NET tools
29
+ run: dotnet tool restore
30
+
31
+ - name: Run CSharpier (format repository)
32
+ if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.login == 'dependabot[bot]' }}
33
+ run: dotnet tool run csharpier format
34
+
35
+ - name: Commit formatting changes to PR branch (Dependabot only)
36
+ if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.login == 'dependabot[bot]' }}
37
+ uses: stefanzweifel/git-auto-commit-action@v7
38
+ with:
39
+ commit_message: "chore(format): apply CSharpier formatting"
40
+ branch: ${{ github.head_ref }}
41
+ file_pattern: |
42
+ **/*.cs
43
+
44
+ - name: Verify formatting (CI gate)
45
+ run: dotnet tool run csharpier check .
46
+
47
+ format_fork:
48
+ name: Fork PR bot formatting PR (Dependabot only)
49
+ if: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && github.event.pull_request.user.login == 'dependabot[bot]' }}
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - name: Checkout fork PR HEAD
53
+ uses: actions/checkout@v5
54
+ with:
55
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
56
+ ref: ${{ github.event.pull_request.head.ref }}
57
+ persist-credentials: false
58
+ fetch-depth: 0
59
+
60
+ - name: Setup .NET
61
+ uses: actions/setup-dotnet@v5
62
+ with:
63
+ dotnet-version: "8.0.x"
64
+
65
+ - name: Install CSharpier (pinned)
66
+ run: dotnet tool install -g csharpier --version 1.1.2
67
+
68
+ - name: Run CSharpier (format repository)
69
+ run: ~/.dotnet/tools/csharpier .
70
+
71
+ - name: Detect changes
72
+ id: changes
73
+ shell: bash
74
+ run: |
75
+ if git diff --quiet; then
76
+ echo "has_changes=false" >> $GITHUB_OUTPUT
77
+ else
78
+ echo "has_changes=true" >> $GITHUB_OUTPUT
79
+ fi
80
+
81
+ - name: Create bot branch and push to base repo
82
+ if: steps.changes.outputs.has_changes == 'true'
83
+ shell: bash
84
+ env:
85
+ GH_REPO: ${{ github.repository }}
86
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87
+ run: |
88
+ set -euo pipefail
89
+ BRANCH="bot/csharpier/pr-${{ github.event.pull_request.number }}"
90
+ git config user.name "github-actions[bot]"
91
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
92
+ git checkout -B "$BRANCH"
93
+ # Only stage C# files to avoid touching workflow YAML (requires special permissions)
94
+ git add '**/*.cs'
95
+ git commit -m "chore(format): apply CSharpier formatting for PR #${{ github.event.pull_request.number }}"
96
+ git remote add upstream "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
97
+ git fetch upstream
98
+ git push upstream "$BRANCH" --force
99
+ echo "branch=$BRANCH" >> $GITHUB_OUTPUT
100
+
101
+ - name: Open or update formatting PR in base repo
102
+ if: steps.changes.outputs.has_changes == 'true'
103
+ uses: actions/github-script@v8
104
+ with:
105
+ script: |
106
+ const prNumber = context.payload.pull_request.number;
107
+ const baseRef = context.payload.pull_request.base.ref;
108
+ const headBranch = `bot/csharpier/pr-${prNumber}`;
109
+ const {owner, repo} = context.repo;
110
+ const title = `chore(format): Apply CSharpier to PR #${prNumber}`;
111
+ const body = [
112
+ `This automated PR applies CSharpier formatting to the changes from PR #${prNumber}.`,
113
+ '',
114
+ `- Source PR (fork): #${prNumber}`,
115
+ `- Target branch: ${baseRef}`,
116
+ '',
117
+ 'If this PR is merged, it will include the contributor\'s changes plus required formatting.',
118
+ 'You can then close the original PR or ask the author to rebase.',
119
+ ].join('\n');
120
+
121
+ // Check if a PR from this branch already exists
122
+ const existing = await github.rest.pulls.list({ owner, repo, state: 'open', head: `${owner}:${headBranch}` });
123
+ if (existing.data.length === 0) {
124
+ await github.rest.pulls.create({ owner, repo, head: headBranch, base: baseRef, title, body });
125
+ }
126
+
127
+ - name: Comment link on original PR
128
+ if: steps.changes.outputs.has_changes == 'true'
129
+ uses: actions/github-script@v8
130
+ with:
131
+ script: |
132
+ const prNumber = context.payload.pull_request.number;
133
+ const {owner, repo} = context.repo;
134
+ const headBranch = `bot/csharpier/pr-${prNumber}`;
135
+ // Find the formatting PR we just created or updated
136
+ const resp = await github.rest.pulls.list({ owner, repo, state: 'open', head: `${owner}:${headBranch}` });
137
+ if (resp.data.length > 0) {
138
+ const fmtPr = resp.data[0];
139
+ const body = `A formatting PR has been opened: #${fmtPr.number} (applies CSharpier to this PR).`;
140
+ // Avoid duplicate comments by checking recent comments
141
+ const comments = await github.rest.issues.listComments({ owner, repo, issue_number: prNumber, per_page: 50 });
142
+ const already = comments.data.some(
143
+ (c) =>
144
+ c.body &&
145
+ c.body.includes(`#${fmtPr.number}`) &&
146
+ c.user &&
147
+ c.user.login === 'github-actions[bot]'
148
+ );
149
+ if (!already) {
150
+ await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, body });
151
+ }
152
+ }
@@ -0,0 +1,305 @@
1
+ name: Opt-in Formatting
2
+
3
+ on:
4
+ issue_comment:
5
+ types: [created]
6
+ workflow_dispatch:
7
+ inputs:
8
+ pr_number:
9
+ description: PR number to format
10
+ required: true
11
+
12
+ permissions:
13
+ contents: write
14
+ pull-requests: write
15
+
16
+ jobs:
17
+ by_comment:
18
+ name: Run on /format comment
19
+ if: >-
20
+ ${{ github.event_name == 'issue_comment' &&
21
+ github.event.action == 'created' &&
22
+ github.event.issue.pull_request &&
23
+ (contains(github.event.comment.body, '/format') || contains(github.event.comment.body, '/autofix') || contains(github.event.comment.body, '/lint-fix')) }}
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - name: Resolve PR metadata and authorize request
27
+ id: meta
28
+ uses: actions/github-script@v8
29
+ with:
30
+ script: |
31
+ const prNumber = context.payload.issue.number;
32
+ const pr = (await github.rest.pulls.get({ ...context.repo, pull_number: prNumber })).data;
33
+ const commenter = context.payload.comment.user.login;
34
+ const prAuthor = pr.user.login;
35
+ const assoc = context.payload.comment.author_association; // OWNER, MEMBER, COLLABORATOR, CONTRIBUTOR, etc.
36
+
37
+ const isMaintainer = ['OWNER','MEMBER','COLLABORATOR'].includes(assoc);
38
+ const isAuthor = commenter === prAuthor;
39
+ const allowed = isMaintainer || isAuthor;
40
+
41
+ core.setOutput('allowed', String(allowed));
42
+ core.setOutput('pr', String(prNumber));
43
+ core.setOutput('base_ref', pr.base.ref);
44
+ core.setOutput('head_repo', pr.head.repo.full_name);
45
+ core.setOutput('head_ref', pr.head.ref);
46
+ core.setOutput('same_repo', String(pr.head.repo.full_name === `${context.repo.owner}/${context.repo.repo}`));
47
+
48
+ - name: Exit if not authorized
49
+ if: ${{ steps.meta.outputs.allowed != 'true' }}
50
+ run: |
51
+ echo "Commenter is not authorized to trigger formatting." 1>&2
52
+ exit 1
53
+
54
+ - name: Checkout PR branch (same-repo)
55
+ if: ${{ steps.meta.outputs.same_repo == 'true' }}
56
+ uses: actions/checkout@v5
57
+ with:
58
+ ref: ${{ steps.meta.outputs.head_ref }}
59
+ fetch-depth: 0
60
+
61
+ - name: Checkout PR fork head
62
+ if: ${{ steps.meta.outputs.same_repo != 'true' }}
63
+ uses: actions/checkout@v5
64
+ with:
65
+ repository: ${{ steps.meta.outputs.head_repo }}
66
+ ref: ${{ steps.meta.outputs.head_ref }}
67
+ persist-credentials: false
68
+ fetch-depth: 0
69
+
70
+ - name: Setup Node.js
71
+ uses: actions/setup-node@v5
72
+ with:
73
+ node-version: '20'
74
+
75
+ - name: Setup .NET
76
+ uses: actions/setup-dotnet@v5
77
+ with:
78
+ dotnet-version: '8.0.x'
79
+
80
+ - name: Restore .NET tools
81
+ run: dotnet tool restore
82
+
83
+ - name: Apply Prettier fixes
84
+ run: |
85
+ npx --yes prettier@3.3.3 --write "**/*.{md,markdown}"
86
+ npx --yes prettier@3.3.3 --write "**/*.{json,asmdef,asmref}"
87
+ npx --yes prettier@3.3.3 --write "**/*.{yml,yaml}"
88
+
89
+ - name: Apply markdownlint fixes
90
+ run: |
91
+ npx --yes markdownlint-cli@0.40.0 "**/*.md" "**/*.markdown" --config .markdownlint.json --ignore-path .markdownlintignore --fix
92
+
93
+ - name: Apply CSharpier formatting
94
+ run: dotnet tool run csharpier format
95
+
96
+ - name: Detect changes
97
+ id: changes
98
+ shell: bash
99
+ run: |
100
+ if git diff --quiet; then
101
+ echo "has_changes=false" >> $GITHUB_OUTPUT
102
+ else
103
+ echo "has_changes=true" >> $GITHUB_OUTPUT
104
+ fi
105
+
106
+ - name: Commit changes to PR branch (same-repo)
107
+ if: ${{ steps.meta.outputs.same_repo == 'true' && steps.changes.outputs.has_changes == 'true' }}
108
+ uses: stefanzweifel/git-auto-commit-action@v7
109
+ with:
110
+ commit_message: "chore(format): apply requested formatting"
111
+ branch: ${{ steps.meta.outputs.head_ref }}
112
+ file_pattern: |
113
+ **/*.cs
114
+ **/*.md
115
+ **/*.markdown
116
+ **/*.json
117
+ **/*.asmdef
118
+ **/*.asmref
119
+
120
+ - name: Create bot branch and PR (fork)
121
+ if: ${{ steps.meta.outputs.same_repo != 'true' && steps.changes.outputs.has_changes == 'true' }}
122
+ shell: bash
123
+ env:
124
+ GH_REPO: ${{ github.repository }}
125
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
126
+ run: |
127
+ set -euo pipefail
128
+ BRANCH="bot/format/pr-${{ steps.meta.outputs.pr }}"
129
+ git config user.name "github-actions[bot]"
130
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
131
+ git checkout -B "$BRANCH"
132
+ # Stage only supported text files; avoid workflows to prevent permission issues
133
+ git add '**/*.cs' '**/*.md' '**/*.markdown' '**/*.json' '**/*.asmdef' '**/*.asmref'
134
+ git commit -m "chore(format): apply requested formatting for PR #${{ steps.meta.outputs.pr }}"
135
+ git remote add upstream "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
136
+ git fetch upstream
137
+ git push upstream "$BRANCH" --force
138
+
139
+ - name: Open/Update formatting PR (fork)
140
+ if: ${{ steps.meta.outputs.same_repo != 'true' && steps.changes.outputs.has_changes == 'true' }}
141
+ uses: actions/github-script@v8
142
+ with:
143
+ script: |
144
+ const prNumber = Number(core.getInput('pr')) || Number('${{ steps.meta.outputs.pr }}');
145
+ const baseRef = '${{ steps.meta.outputs.base_ref }}';
146
+ const headBranch = `bot/format/pr-${prNumber}`;
147
+ const {owner, repo} = context.repo;
148
+ const title = `chore(format): Apply formatting to PR #${prNumber}`;
149
+ const body = [
150
+ `This automated PR applies Prettier/markdownlint/CSharpier formatting to the changes from PR #${prNumber}.`,
151
+ '',
152
+ `- Source PR (fork): #${prNumber}`,
153
+ `- Target branch: ${baseRef}`,
154
+ ].join('\n');
155
+ const existing = await github.rest.pulls.list({ owner, repo, state: 'open', head: `${owner}:${headBranch}` });
156
+ if (existing.data.length === 0) {
157
+ await github.rest.pulls.create({ owner, repo, head: headBranch, base: baseRef, title, body });
158
+ }
159
+
160
+ - name: Comment result on PR
161
+ if: ${{ steps.changes.outputs.has_changes == 'true' }}
162
+ uses: actions/github-script@v8
163
+ with:
164
+ script: |
165
+ const prNumber = Number('${{ steps.meta.outputs.pr }}');
166
+ const sameRepo = '${{ steps.meta.outputs.same_repo }}' === 'true';
167
+ const body = sameRepo
168
+ ? 'Applied formatting as requested and pushed commits to this PR branch.'
169
+ : 'Opened a formatting PR against the base repository with requested fixes.';
170
+ await github.rest.issues.createComment({ ...context.repo, issue_number: prNumber, body });
171
+
172
+ - name: No-op comment (nothing to change)
173
+ if: ${{ steps.changes.outputs.has_changes != 'true' }}
174
+ uses: actions/github-script@v8
175
+ with:
176
+ script: |
177
+ const prNumber = Number('${{ steps.meta.outputs.pr }}');
178
+ const body = 'No formatting changes were necessary.';
179
+ await github.rest.issues.createComment({ ...context.repo, issue_number: prNumber, body });
180
+
181
+ by_dispatch:
182
+ name: Run via manual dispatch
183
+ if: ${{ github.event_name == 'workflow_dispatch' }}
184
+ runs-on: ubuntu-latest
185
+ steps:
186
+ - name: Resolve PR metadata
187
+ id: meta
188
+ uses: actions/github-script@v8
189
+ with:
190
+ script: |
191
+ const prNumber = Number(core.getInput('pr_number'));
192
+ if (!prNumber) core.setFailed('pr_number is required');
193
+ const pr = (await github.rest.pulls.get({ ...context.repo, pull_number: prNumber })).data;
194
+ core.setOutput('pr', String(prNumber));
195
+ core.setOutput('base_ref', pr.base.ref);
196
+ core.setOutput('head_repo', pr.head.repo.full_name);
197
+ core.setOutput('head_ref', pr.head.ref);
198
+ core.setOutput('same_repo', String(pr.head.repo.full_name === `${context.repo.owner}/${context.repo.repo}`));
199
+
200
+ - name: Checkout PR branch (same-repo)
201
+ if: ${{ steps.meta.outputs.same_repo == 'true' }}
202
+ uses: actions/checkout@v5
203
+ with:
204
+ ref: ${{ steps.meta.outputs.head_ref }}
205
+ fetch-depth: 0
206
+
207
+ - name: Checkout PR fork head
208
+ if: ${{ steps.meta.outputs.same_repo != 'true' }}
209
+ uses: actions/checkout@v5
210
+ with:
211
+ repository: ${{ steps.meta.outputs.head_repo }}
212
+ ref: ${{ steps.meta.outputs.head_ref }}
213
+ persist-credentials: false
214
+ fetch-depth: 0
215
+
216
+ - name: Setup Node.js
217
+ uses: actions/setup-node@v5
218
+ with:
219
+ node-version: '20'
220
+
221
+ - name: Setup .NET
222
+ uses: actions/setup-dotnet@v5
223
+ with:
224
+ dotnet-version: '8.0.x'
225
+
226
+ - name: Restore .NET tools
227
+ run: dotnet tool restore
228
+
229
+ - name: Apply Prettier fixes
230
+ run: |
231
+ npx --yes prettier@3.3.3 --write "**/*.{md,markdown}"
232
+ npx --yes prettier@3.3.3 --write "**/*.{json,asmdef,asmref}"
233
+ npx --yes prettier@3.3.3 --write "**/*.{yml,yaml}"
234
+
235
+ - name: Apply markdownlint fixes
236
+ run: |
237
+ npx --yes markdownlint-cli@0.40.0 "**/*.md" "**/*.markdown" --config .markdownlint.json --ignore-path .markdownlintignore --fix
238
+
239
+ - name: Apply CSharpier formatting
240
+ run: dotnet tool run csharpier format
241
+
242
+ - name: Detect changes
243
+ id: changes
244
+ shell: bash
245
+ run: |
246
+ if git diff --quiet; then
247
+ echo "has_changes=false" >> $GITHUB_OUTPUT
248
+ else
249
+ echo "has_changes=true" >> $GITHUB_OUTPUT
250
+ fi
251
+
252
+ - name: Commit changes to PR branch (same-repo)
253
+ if: ${{ steps.meta.outputs.same_repo == 'true' && steps.changes.outputs.has_changes == 'true' }}
254
+ uses: stefanzweifel/git-auto-commit-action@v7
255
+ with:
256
+ commit_message: "chore(format): apply requested formatting"
257
+ branch: ${{ steps.meta.outputs.head_ref }}
258
+ file_pattern: |
259
+ **/*.cs
260
+ **/*.md
261
+ **/*.markdown
262
+ **/*.json
263
+ **/*.asmdef
264
+ **/*.asmref
265
+
266
+ - name: Create bot branch and PR (fork)
267
+ if: ${{ steps.meta.outputs.same_repo != 'true' && steps.changes.outputs.has_changes == 'true' }}
268
+ shell: bash
269
+ env:
270
+ GH_REPO: ${{ github.repository }}
271
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
272
+ run: |
273
+ set -euo pipefail
274
+ BRANCH="bot/format/pr-${{ steps.meta.outputs.pr }}"
275
+ git config user.name "github-actions[bot]"
276
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
277
+ git checkout -B "$BRANCH"
278
+ # Stage only supported text files; avoid workflows to prevent permission issues
279
+ git add '**/*.cs' '**/*.md' '**/*.markdown' '**/*.json' '**/*.asmdef' '**/*.asmref'
280
+ git commit -m "chore(format): apply requested formatting for PR #${{ steps.meta.outputs.pr }}"
281
+ git remote add upstream "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
282
+ git fetch upstream
283
+ git push upstream "$BRANCH" --force
284
+
285
+ - name: Open/Update formatting PR (fork)
286
+ if: ${{ steps.meta.outputs.same_repo != 'true' && steps.changes.outputs.has_changes == 'true' }}
287
+ uses: actions/github-script@v8
288
+ with:
289
+ script: |
290
+ const prNumber = Number('${{ steps.meta.outputs.pr }}');
291
+ const baseRef = '${{ steps.meta.outputs.base_ref }}';
292
+ const headBranch = `bot/format/pr-${prNumber}`;
293
+ const {owner, repo} = context.repo;
294
+ const title = `chore(format): Apply formatting to PR #${prNumber}`;
295
+ const body = [
296
+ `This automated PR applies Prettier/markdownlint/CSharpier formatting to the changes from PR #${prNumber}.`,
297
+ '',
298
+ `- Source PR (fork): #${prNumber}`,
299
+ `- Target branch: ${baseRef}`,
300
+ ].join('\n');
301
+ const existing = await github.rest.pulls.list({ owner, repo, state: 'open', head: `${owner}:${headBranch}` });
302
+ if (existing.data.length === 0) {
303
+ await github.rest.pulls.create({ owner, repo, head: headBranch, base: baseRef, title, body });
304
+ }
305
+
@@ -11,17 +11,20 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - name: Checkout
14
- uses: actions/checkout@v4
14
+ uses: actions/checkout@v5
15
15
 
16
16
  - name: Run Markdown link linter
17
17
  shell: pwsh
18
18
  run: ./scripts/lint-doc-links.ps1 -VerboseOutput
19
19
 
20
20
  - name: Check dead links (lychee)
21
- uses: lycheeverse/lychee-action@v1
21
+ uses: lycheeverse/lychee-action@v2
22
22
  with:
23
- args: >
24
- --config .lychee.toml
25
- **/*.md
23
+ args: >-
24
+ -c .lychee.toml
25
+ --no-progress
26
+ --include-fragments
27
+ --verbose
28
+ "./**/*.md"
26
29
  env:
27
30
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -14,10 +14,10 @@ jobs:
14
14
  runs-on: ubuntu-latest
15
15
  steps:
16
16
  - name: Checkout
17
- uses: actions/checkout@v4
17
+ uses: actions/checkout@v5
18
18
 
19
19
  - name: Setup Node.js
20
- uses: actions/setup-node@v4
20
+ uses: actions/setup-node@v5
21
21
  with:
22
22
  node-version: '20'
23
23
  cache: 'npm'
@@ -39,3 +39,7 @@ jobs:
39
39
 
40
40
  - name: Markdown lint
41
41
  run: npm run lint:markdown
42
+
43
+ - name: Enforce EOL (CRLF) and No BOM
44
+ shell: pwsh
45
+ run: ./scripts/check-eol.ps1 -VerboseOutput