com.wallstop-studios.dxmessaging 2.0.0-rc27 → 2.0.0-rc27.2

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 (357) hide show
  1. package/.config/dotnet-tools.json +10 -10
  2. package/.csharpierignore +1 -0
  3. package/.csharpierrc.json +3 -0
  4. package/.editorconfig +184 -184
  5. package/.gitattributes +87 -63
  6. package/.github/dependabot.yml +32 -10
  7. package/.github/scripts/check-markdown-links.ps1 +77 -0
  8. package/.github/scripts/check_markdown_links.py +89 -0
  9. package/.github/scripts/check_markdown_url_encoding.py +74 -0
  10. package/.github/scripts/validate_markdown_links.py +194 -0
  11. package/.github/workflows/csharpier-autofix.yml +152 -0
  12. package/.github/workflows/format-on-demand.yml +305 -0
  13. package/.github/workflows/json-format-check.yml +34 -0
  14. package/.github/workflows/lint-doc-links.yml +30 -0
  15. package/.github/workflows/markdown-json.yml +45 -0
  16. package/.github/workflows/markdown-link-text-check.yml +21 -0
  17. package/.github/workflows/markdown-link-validity.yml +32 -0
  18. package/.github/workflows/markdownlint.yml +31 -0
  19. package/.github/workflows/npm-publish.yml +75 -75
  20. package/.github/workflows/prettier-autofix.yml +195 -0
  21. package/.github/workflows/update-dotnet-tools.yml +80 -0
  22. package/.github/workflows/yaml-format-lint.yml +41 -0
  23. package/.lychee.toml +26 -0
  24. package/.markdownlint-cli2.jsonc +14 -0
  25. package/.markdownlint.json +21 -0
  26. package/.markdownlint.jsonc +21 -0
  27. package/.markdownlintignore +7 -0
  28. package/.pre-commit-config.yaml +58 -22
  29. package/.prettierignore +21 -0
  30. package/.prettierrc.json +20 -0
  31. package/.yamllint.yaml +31 -0
  32. package/AGENTS.md +49 -0
  33. package/AGENTS.md.meta +7 -0
  34. package/CHANGELOG.md.meta +7 -7
  35. package/CONTRIBUTING.md +33 -0
  36. package/CONTRIBUTING.md.meta +7 -0
  37. package/Docs/Advanced.md +236 -0
  38. package/Docs/Advanced.md.meta +7 -0
  39. package/Docs/Comparisons.md +468 -0
  40. package/Docs/Comparisons.md.meta +7 -0
  41. package/Docs/Compatibility.md +17 -0
  42. package/Docs/Compatibility.md.meta +7 -0
  43. package/Docs/DesignAndArchitecture.md +140 -0
  44. package/Docs/DesignAndArchitecture.md.meta +7 -0
  45. package/Docs/Diagnostics.md +61 -0
  46. package/Docs/Diagnostics.md.meta +7 -0
  47. package/Docs/EmitShorthands.md +437 -0
  48. package/Docs/EmitShorthands.md.meta +8 -0
  49. package/Docs/EndToEnd.md +139 -0
  50. package/Docs/EndToEnd.md.meta +7 -0
  51. package/Docs/EndToEndSceneTransitions.md +130 -0
  52. package/Docs/EndToEndSceneTransitions.md.meta +7 -0
  53. package/Docs/FAQ.md +62 -0
  54. package/Docs/FAQ.md.meta +7 -0
  55. package/Docs/GettingStarted.md +133 -0
  56. package/Docs/GettingStarted.md.meta +7 -0
  57. package/Docs/Glossary.md +262 -0
  58. package/Docs/Glossary.md.meta +7 -0
  59. package/Docs/Helpers.md +559 -0
  60. package/Docs/Helpers.md.meta +7 -0
  61. package/Docs/Index.md +303 -0
  62. package/Docs/Index.md.meta +7 -0
  63. package/Docs/Install.md +36 -0
  64. package/Docs/Install.md.meta +7 -0
  65. package/Docs/InterceptorsAndOrdering.md +167 -0
  66. package/Docs/InterceptorsAndOrdering.md.meta +7 -0
  67. package/Docs/ListeningPatterns.md +58 -0
  68. package/Docs/ListeningPatterns.md.meta +7 -0
  69. package/Docs/MessageTypes.md +141 -0
  70. package/Docs/MessageTypes.md.meta +7 -0
  71. package/Docs/MigrationGuide.md +468 -0
  72. package/Docs/MigrationGuide.md.meta +7 -0
  73. package/Docs/Overview.md +63 -0
  74. package/Docs/Overview.md.meta +7 -0
  75. package/Docs/Patterns.md +755 -0
  76. package/Docs/Patterns.md.meta +7 -0
  77. package/Docs/Performance.md +33 -0
  78. package/Docs/Performance.md.meta +7 -0
  79. package/Docs/QuickReference.md +164 -0
  80. package/Docs/QuickReference.md.meta +7 -0
  81. package/Docs/QuickStart.md +168 -0
  82. package/Docs/QuickStart.md.meta +7 -0
  83. package/Docs/Reference.md +88 -0
  84. package/Docs/Reference.md.meta +7 -0
  85. package/Docs/StringMessages.md +71 -0
  86. package/Docs/StringMessages.md.meta +7 -0
  87. package/Docs/TargetingAndContext.md +451 -0
  88. package/Docs/TargetingAndContext.md.meta +7 -0
  89. package/Docs/Troubleshooting.md +68 -0
  90. package/Docs/Troubleshooting.md.meta +7 -0
  91. package/Docs/UnityIntegration.md +137 -0
  92. package/Docs/UnityIntegration.md.meta +7 -0
  93. package/Docs/VisualGuide.md +488 -0
  94. package/Docs/VisualGuide.md.meta +7 -0
  95. package/Docs.meta +8 -0
  96. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +33 -33
  97. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +33 -33
  98. package/Editor/Analyzers/System.Collections.Immutable.dll.meta +33 -33
  99. package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +33 -33
  100. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +33 -33
  101. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +71 -71
  102. package/Editor/Analyzers.meta +8 -8
  103. package/Editor/CustomEditors/MessagingComponentEditor.cs +530 -530
  104. package/Editor/CustomEditors/MessagingComponentEditor.cs.meta +2 -2
  105. package/Editor/CustomEditors.meta +2 -2
  106. package/Editor/DxMessagingEditorInitializer.cs +22 -19
  107. package/Editor/DxMessagingEditorInitializer.cs.meta +2 -2
  108. package/Editor/Settings/DxMessagingSettings.cs +87 -68
  109. package/Editor/Settings/DxMessagingSettings.cs.meta +2 -2
  110. package/Editor/Settings/DxMessagingSettingsProvider.cs +61 -55
  111. package/Editor/Settings/DxMessagingSettingsProvider.cs.meta +2 -2
  112. package/Editor/Settings.meta +2 -2
  113. package/Editor/SetupCscRsp.cs +187 -187
  114. package/Editor/SetupCscRsp.cs.meta +2 -2
  115. package/Editor/WallstopStudios.DxMessaging.Editor.asmdef +14 -18
  116. package/Editor/WallstopStudios.DxMessaging.Editor.asmdef.meta +7 -7
  117. package/Editor.meta +8 -8
  118. package/LICENSE.md +9 -7
  119. package/LICENSE.md.meta +7 -7
  120. package/README.md +447 -396
  121. package/README.md.meta +7 -7
  122. package/Runtime/AssemblyInfo.cs +7 -7
  123. package/Runtime/AssemblyInfo.cs.meta +2 -2
  124. package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs +32 -14
  125. package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs.meta +2 -2
  126. package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs +29 -11
  127. package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs.meta +2 -2
  128. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +24 -10
  129. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs.meta +2 -2
  130. package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs +30 -11
  131. package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs.meta +2 -2
  132. package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs +30 -11
  133. package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs.meta +2 -2
  134. package/Runtime/Core/Attributes.meta +2 -2
  135. package/Runtime/Core/DataStructure/CyclicBuffer.cs +318 -263
  136. package/Runtime/Core/DataStructure/CyclicBuffer.cs.meta +2 -2
  137. package/Runtime/Core/DataStructure.meta +2 -2
  138. package/Runtime/Core/Diagnostics/MessageEmissionData.cs +74 -53
  139. package/Runtime/Core/Diagnostics/MessageEmissionData.cs.meta +2 -2
  140. package/Runtime/Core/Diagnostics/MessageRegistrationData.cs +46 -25
  141. package/Runtime/Core/Diagnostics/MessageRegistrationData.cs.meta +2 -2
  142. package/Runtime/Core/Diagnostics/MessageRegistrationType.cs +21 -21
  143. package/Runtime/Core/Diagnostics/MessageRegistrationType.cs.meta +2 -2
  144. package/Runtime/Core/Diagnostics.meta +2 -2
  145. package/Runtime/Core/Extensions/EnumExtensions.cs +44 -44
  146. package/Runtime/Core/Extensions/EnumExtensions.cs.meta +2 -2
  147. package/Runtime/Core/Extensions/IListExtensions.cs +48 -48
  148. package/Runtime/Core/Extensions/IListExtensions.cs.meta +2 -2
  149. package/Runtime/Core/Extensions/MessageExtensions.cs +615 -408
  150. package/Runtime/Core/Extensions/MessageExtensions.cs.meta +11 -11
  151. package/Runtime/Core/Extensions.meta +8 -8
  152. package/Runtime/Core/Helper/MessageCache.cs +192 -150
  153. package/Runtime/Core/Helper/MessageCache.cs.meta +2 -2
  154. package/Runtime/Core/Helper/MessageHelperIndexer.cs +14 -14
  155. package/Runtime/Core/Helper/MessageHelperIndexer.cs.meta +2 -2
  156. package/Runtime/Core/Helper.meta +2 -2
  157. package/Runtime/Core/IMessage.cs +39 -12
  158. package/Runtime/Core/IMessage.cs.meta +11 -11
  159. package/Runtime/Core/InstanceId.cs +145 -133
  160. package/Runtime/Core/InstanceId.cs.meta +11 -11
  161. package/Runtime/Core/MessageBus/IMessageBus.cs +367 -324
  162. package/Runtime/Core/MessageBus/IMessageBus.cs.meta +11 -11
  163. package/Runtime/Core/MessageBus/MessageBus.cs +4285 -3538
  164. package/Runtime/Core/MessageBus/MessageBus.cs.meta +11 -11
  165. package/Runtime/Core/MessageBus/MessagingRegistration.cs +105 -105
  166. package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +11 -11
  167. package/Runtime/Core/MessageBus/RegistrationLog.cs +117 -111
  168. package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +11 -11
  169. package/Runtime/Core/MessageBus.meta +8 -8
  170. package/Runtime/Core/MessageHandler.cs +3866 -3060
  171. package/Runtime/Core/MessageHandler.cs.meta +11 -11
  172. package/Runtime/Core/MessageRegistrationHandle.cs +119 -110
  173. package/Runtime/Core/MessageRegistrationHandle.cs.meta +11 -11
  174. package/Runtime/Core/MessageRegistrationToken.cs +2006 -1820
  175. package/Runtime/Core/MessageRegistrationToken.cs.meta +11 -11
  176. package/Runtime/Core/Messages/GlobalStringMessage.cs +34 -16
  177. package/Runtime/Core/Messages/GlobalStringMessage.cs.meta +2 -2
  178. package/Runtime/Core/Messages/IBroadcastMessage.cs +42 -27
  179. package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +11 -11
  180. package/Runtime/Core/Messages/ITargetedMessage.cs +43 -27
  181. package/Runtime/Core/Messages/ITargetedMessage.cs.meta +11 -11
  182. package/Runtime/Core/Messages/IUntargetedMessage.cs +43 -27
  183. package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +11 -11
  184. package/Runtime/Core/Messages/ReflexiveMessage.cs +201 -152
  185. package/Runtime/Core/Messages/ReflexiveMessage.cs.meta +2 -2
  186. package/Runtime/Core/Messages/SourcedStringMessage.cs +34 -0
  187. package/Runtime/Core/Messages/SourcedStringMessage.cs.meta +11 -0
  188. package/Runtime/Core/Messages/StringMessage.cs +36 -16
  189. package/Runtime/Core/Messages/StringMessage.cs.meta +2 -2
  190. package/Runtime/Core/Messages.meta +8 -8
  191. package/Runtime/Core/MessagingDebug.cs +82 -77
  192. package/Runtime/Core/MessagingDebug.cs.meta +11 -11
  193. package/Runtime/Core.meta +8 -8
  194. package/Runtime/Unity/MessageAwareComponent.cs +167 -95
  195. package/Runtime/Unity/MessageAwareComponent.cs.meta +11 -11
  196. package/Runtime/Unity/MessagingComponent.cs +125 -88
  197. package/Runtime/Unity/MessagingComponent.cs.meta +11 -11
  198. package/Runtime/Unity.meta +8 -8
  199. package/Runtime/WallstopStudios.DxMessaging.asmdef +14 -16
  200. package/Runtime/WallstopStudios.DxMessaging.asmdef.meta +7 -7
  201. package/Runtime.meta +8 -8
  202. package/Samples~/Mini Combat/Boot.cs +19 -0
  203. package/Samples~/Mini Combat/Boot.cs.meta +11 -0
  204. package/Samples~/Mini Combat/Enemy.cs +13 -0
  205. package/Samples~/Mini Combat/Enemy.cs.meta +11 -0
  206. package/Samples~/Mini Combat/Messages.cs +23 -0
  207. package/Samples~/Mini Combat/Messages.cs.meta +11 -0
  208. package/Samples~/Mini Combat/Player.cs +20 -0
  209. package/Samples~/Mini Combat/Player.cs.meta +11 -0
  210. package/Samples~/Mini Combat/README.md +265 -0
  211. package/Samples~/Mini Combat/README.md.meta +7 -0
  212. package/Samples~/Mini Combat/UIOverlay.cs +20 -0
  213. package/Samples~/Mini Combat/UIOverlay.cs.meta +11 -0
  214. package/Samples~/Mini Combat/Walkthrough.md +414 -0
  215. package/Samples~/Mini Combat/Walkthrough.md.meta +7 -0
  216. package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef +13 -0
  217. package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef.meta +7 -0
  218. package/Samples~/Mini Combat.meta +8 -0
  219. package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +17 -0
  220. package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs.meta +11 -0
  221. package/Samples~/UI Buttons + Inspector/Messages.cs +8 -0
  222. package/Samples~/UI Buttons + Inspector/Messages.cs.meta +11 -0
  223. package/Samples~/UI Buttons + Inspector/MessagingObserver.cs +26 -0
  224. package/Samples~/UI Buttons + Inspector/MessagingObserver.cs.meta +11 -0
  225. package/Samples~/UI Buttons + Inspector/README.md +166 -0
  226. package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs +20 -0
  227. package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs.meta +11 -0
  228. package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef +13 -0
  229. package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef.meta +7 -0
  230. package/Samples~/UI Buttons + Inspector.meta +8 -0
  231. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +273 -273
  232. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs.meta +11 -11
  233. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +308 -308
  234. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs.meta +2 -2
  235. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +18 -18
  236. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj.meta +7 -7
  237. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.meta +8 -8
  238. package/SourceGenerators.meta +8 -8
  239. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +838 -742
  240. package/Tests/Runtime/Benchmarks/PerformanceTests.cs.meta +11 -11
  241. package/Tests/Runtime/Benchmarks.meta +8 -8
  242. package/Tests/Runtime/Core/AlternateBusTests.cs +82 -82
  243. package/Tests/Runtime/Core/AlternateBusTests.cs.meta +11 -11
  244. package/Tests/Runtime/Core/BroadcastTests.cs +897 -897
  245. package/Tests/Runtime/Core/BroadcastTests.cs.meta +11 -11
  246. package/Tests/Runtime/Core/CyclicBufferTests.cs +70 -0
  247. package/Tests/Runtime/Core/CyclicBufferTests.cs.meta +11 -0
  248. package/Tests/Runtime/Core/DiagnosticsTests.cs +118 -118
  249. package/Tests/Runtime/Core/DiagnosticsTests.cs.meta +11 -11
  250. package/Tests/Runtime/Core/EdgeCaseTests.cs +579 -565
  251. package/Tests/Runtime/Core/EdgeCaseTests.cs.meta +11 -11
  252. package/Tests/Runtime/Core/EnablementTests.cs +69 -69
  253. package/Tests/Runtime/Core/EnablementTests.cs.meta +2 -2
  254. package/Tests/Runtime/Core/GenericMessageTests.cs +47 -47
  255. package/Tests/Runtime/Core/GenericMessageTests.cs.meta +2 -2
  256. package/Tests/Runtime/Core/GlobalAcceptAllTests.cs +190 -190
  257. package/Tests/Runtime/Core/GlobalAcceptAllTests.cs.meta +11 -11
  258. package/Tests/Runtime/Core/InterceptorCancellationTests.cs +170 -0
  259. package/Tests/Runtime/Core/InterceptorCancellationTests.cs.meta +11 -0
  260. package/Tests/Runtime/Core/LifecycleTests.cs +72 -72
  261. package/Tests/Runtime/Core/LifecycleTests.cs.meta +11 -11
  262. package/Tests/Runtime/Core/MessagingTestBase.cs +208 -208
  263. package/Tests/Runtime/Core/MessagingTestBase.cs.meta +11 -11
  264. package/Tests/Runtime/Core/MutationDedupeTests.cs +98 -0
  265. package/Tests/Runtime/Core/MutationDedupeTests.cs.meta +11 -0
  266. package/Tests/Runtime/Core/MutationDestructionTests.cs +434 -0
  267. package/Tests/Runtime/Core/MutationDestructionTests.cs.meta +11 -0
  268. package/Tests/Runtime/Core/MutationDuringEmissionTests.cs +2021 -0
  269. package/Tests/Runtime/Core/MutationDuringEmissionTests.cs.meta +11 -0
  270. package/Tests/Runtime/Core/MutationGlobalAddTests.cs +99 -0
  271. package/Tests/Runtime/Core/MutationGlobalAddTests.cs.meta +11 -0
  272. package/Tests/Runtime/Core/MutationInterceptorTests.cs +187 -0
  273. package/Tests/Runtime/Core/MutationInterceptorTests.cs.meta +11 -0
  274. package/Tests/Runtime/Core/MutationPostProcessorAcrossHandlersTests.cs +112 -0
  275. package/Tests/Runtime/Core/MutationPostProcessorAcrossHandlersTests.cs.meta +11 -0
  276. package/Tests/Runtime/Core/MutationPostProcessorMoreTests.cs +114 -0
  277. package/Tests/Runtime/Core/MutationPostProcessorMoreTests.cs.meta +11 -0
  278. package/Tests/Runtime/Core/MutationPriorityTests.cs +116 -0
  279. package/Tests/Runtime/Core/MutationPriorityTests.cs.meta +11 -0
  280. package/Tests/Runtime/Core/NominalTests.cs +1734 -1734
  281. package/Tests/Runtime/Core/NominalTests.cs.meta +11 -11
  282. package/Tests/Runtime/Core/OrderingTests.cs +1929 -0
  283. package/Tests/Runtime/Core/OrderingTests.cs.meta +11 -0
  284. package/Tests/Runtime/Core/OverDeregistrationTests.cs +125 -0
  285. package/Tests/Runtime/Core/OverDeregistrationTests.cs.meta +11 -0
  286. package/Tests/Runtime/Core/PostProcessorTests.cs +1236 -1236
  287. package/Tests/Runtime/Core/PostProcessorTests.cs.meta +11 -11
  288. package/Tests/Runtime/Core/ReflexiveErrorTests.cs +40 -0
  289. package/Tests/Runtime/Core/ReflexiveErrorTests.cs.meta +11 -0
  290. package/Tests/Runtime/Core/ReflexiveTests.cs +170 -171
  291. package/Tests/Runtime/Core/ReflexiveTests.cs.meta +11 -11
  292. package/Tests/Runtime/Core/RegistrationTests.cs +1266 -1266
  293. package/Tests/Runtime/Core/RegistrationTests.cs.meta +11 -11
  294. package/Tests/Runtime/Core/StringShorthandTests.cs +98 -0
  295. package/Tests/Runtime/Core/StringShorthandTests.cs.meta +12 -0
  296. package/Tests/Runtime/Core/TargetedTests.cs +888 -888
  297. package/Tests/Runtime/Core/TargetedTests.cs.meta +11 -11
  298. package/Tests/Runtime/Core/TypedShorthandTests.cs +230 -0
  299. package/Tests/Runtime/Core/TypedShorthandTests.cs.meta +12 -0
  300. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +170 -0
  301. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs.meta +12 -0
  302. package/Tests/Runtime/Core/UntargetedTests.cs +272 -272
  303. package/Tests/Runtime/Core/UntargetedTests.cs.meta +11 -11
  304. package/Tests/Runtime/Core.meta +8 -8
  305. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +9 -9
  306. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs.meta +11 -11
  307. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +18 -19
  308. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs.meta +2 -2
  309. package/Tests/Runtime/Scripts/Components/ManualListenerComponent.cs +22 -22
  310. package/Tests/Runtime/Scripts/Components/ManualListenerComponent.cs.meta +11 -11
  311. package/Tests/Runtime/Scripts/Components/ShorthandTargetedBroadcastComponent.cs +46 -0
  312. package/Tests/Runtime/Scripts/Components/ShorthandTargetedBroadcastComponent.cs.meta +12 -0
  313. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +198 -198
  314. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs.meta +11 -11
  315. package/Tests/Runtime/Scripts/Components/StringMessageAwareComponent.cs +75 -0
  316. package/Tests/Runtime/Scripts/Components/StringMessageAwareComponent.cs.meta +12 -0
  317. package/Tests/Runtime/Scripts/Components/UntargetedClassReceiverComponent.cs +16 -0
  318. package/Tests/Runtime/Scripts/Components/UntargetedClassReceiverComponent.cs.meta +12 -0
  319. package/Tests/Runtime/Scripts/Components/UntargetedReceiverComponent.cs +16 -0
  320. package/Tests/Runtime/Scripts/Components/UntargetedReceiverComponent.cs.meta +12 -0
  321. package/Tests/Runtime/Scripts/Components.meta +8 -8
  322. package/Tests/Runtime/Scripts/Messages/ClassUntargetedMessage.cs +17 -0
  323. package/Tests/Runtime/Scripts/Messages/ClassUntargetedMessage.cs.meta +12 -0
  324. package/Tests/Runtime/Scripts/Messages/ComplexTargetedMessage.cs +29 -30
  325. package/Tests/Runtime/Scripts/Messages/ComplexTargetedMessage.cs.meta +11 -11
  326. package/Tests/Runtime/Scripts/Messages/GenericUntargetedMessage.cs +7 -7
  327. package/Tests/Runtime/Scripts/Messages/GenericUntargetedMessage.cs.meta +2 -2
  328. package/Tests/Runtime/Scripts/Messages/SimpleBroadcastMessage.cs +7 -8
  329. package/Tests/Runtime/Scripts/Messages/SimpleBroadcastMessage.cs.meta +11 -11
  330. package/Tests/Runtime/Scripts/Messages/SimpleTargetedMessage.cs +7 -8
  331. package/Tests/Runtime/Scripts/Messages/SimpleTargetedMessage.cs.meta +11 -11
  332. package/Tests/Runtime/Scripts/Messages/SimpleUntargetedMessage.cs +7 -8
  333. package/Tests/Runtime/Scripts/Messages/SimpleUntargetedMessage.cs.meta +11 -11
  334. package/Tests/Runtime/Scripts/Messages.meta +8 -8
  335. package/Tests/Runtime/Scripts.meta +8 -8
  336. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +19 -23
  337. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef.meta +7 -7
  338. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj +7 -7
  339. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj.meta +7 -7
  340. package/Tests/Runtime.meta +8 -8
  341. package/Tests.meta +8 -8
  342. package/Third Party Notices.md +3 -1
  343. package/Third Party Notices.md.meta +7 -7
  344. package/package-lock.json.meta +7 -0
  345. package/package.json +61 -34
  346. package/package.json.meta +7 -7
  347. package/scripts/check-eol.js +94 -0
  348. package/scripts/check-eol.js.meta +7 -0
  349. package/scripts/check-eol.ps1 +91 -0
  350. package/scripts/check-eol.ps1.meta +8 -0
  351. package/scripts/fix-eol.js +97 -0
  352. package/scripts/fix-eol.js.meta +7 -0
  353. package/scripts/fix-markdown-file.js +64 -0
  354. package/scripts/fix-markdown-file.js.meta +7 -0
  355. package/scripts/lint-doc-links.ps1 +25 -0
  356. package/scripts/lint-doc-links.ps1.meta +7 -0
  357. package/scripts.meta +8 -0
@@ -0,0 +1,77 @@
1
+ Param(
2
+ [string]$Root = "."
3
+ )
4
+
5
+ $ErrorActionPreference = 'Stop'
6
+
7
+ function Normalize-Name {
8
+ param([string]$s)
9
+ if ([string]::IsNullOrWhiteSpace($s)) { return "" }
10
+ # Remove extension (like .md), collapse non-alphanumerics, lowercase
11
+ $noExt = $s -replace '\.[^\.]+$',''
12
+ $normalized = ($noExt -replace '[^A-Za-z0-9]', '')
13
+ return $normalized.ToLowerInvariant()
14
+ }
15
+
16
+ $issueCount = 0
17
+
18
+ # Exclude typical directories that shouldn't be scanned
19
+ $excludeDirs = @('.git', 'node_modules', '.vs')
20
+
21
+ $mdFiles = Get-ChildItem -Path $Root -Recurse -File -Filter *.md |
22
+ Where-Object { $excludeDirs -notcontains $_.Directory.Name }
23
+
24
+ # Regex for inline markdown links (exclude images), capture optional title
25
+ $pattern = '(?<!\!)\[(?<text>[^\]]+)\]\((?<target>[^)\s]+)(?:\s+"[^"]*")?\)'
26
+
27
+ foreach ($file in $mdFiles) {
28
+ $lines = Get-Content -LiteralPath $file.FullName -Encoding UTF8
29
+ for ($i = 0; $i -lt $lines.Count; $i++) {
30
+ $line = $lines[$i]
31
+ $matches = [System.Text.RegularExpressions.Regex]::Matches($line, $pattern)
32
+ foreach ($m in $matches) {
33
+ $text = $m.Groups['text'].Value.Trim()
34
+ $targetRaw = $m.Groups['target'].Value.Trim()
35
+
36
+ # Skip anchors, external links, and mailto
37
+ if ($targetRaw -match '^(#|https?://|mailto:|tel:|data:)') { continue }
38
+
39
+ # Remove query/anchor for file checks
40
+ $targetCore = $targetRaw -replace '[?#].*$',''
41
+
42
+ # Decode URL-encoded chars
43
+ try { $targetCore = [uri]::UnescapeDataString($targetCore) } catch { }
44
+
45
+ # Only care about links to markdown files
46
+ if (-not ($targetCore -match '\.md$')) { continue }
47
+
48
+ $fileName = [System.IO.Path]::GetFileName($targetCore)
49
+ $baseName = [System.IO.Path]::GetFileNameWithoutExtension($targetCore)
50
+
51
+ # Fail when the visible link text is the raw file name
52
+ $isExactFileName = $text.Equals($fileName, [System.StringComparison]::OrdinalIgnoreCase)
53
+
54
+ # Also fail when the visible text looks like a path or ends with .md
55
+ # contains path separators and no whitespace (heuristic for raw paths)
56
+ $looksLikePath = ($text -match '[\\/]' -and -not ($text -match '\\s'))
57
+ $looksLikeMarkdownFileName = $text.Trim().ToLowerInvariant().EndsWith('.md')
58
+
59
+ if ($isExactFileName -or $looksLikePath -or $looksLikeMarkdownFileName) {
60
+ $issueCount++
61
+ $lineNo = $i + 1
62
+ $msg = "Link text '$text' should be human-readable, not a raw file name or path"
63
+ # GitHub Actions annotation
64
+ Write-Output "::error file=$($file.FullName),line=$lineNo::$msg (target: $targetRaw)"
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ if ($issueCount -gt 0) {
71
+ Write-Host "Found $issueCount documentation link(s) with non-human-readable text." -ForegroundColor Red
72
+ Write-Host "Use a descriptive phrase instead of the raw file name."
73
+ exit 1
74
+ }
75
+ else {
76
+ Write-Host "All markdown links have human-readable text."
77
+ }
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import re
4
+ import sys
5
+ import urllib.parse
6
+
7
+
8
+ EXCLUDE_DIRS = {".git", "node_modules", ".vs"}
9
+
10
+
11
+ def normalize_name(s: str) -> str:
12
+ if not s:
13
+ return ""
14
+ # remove extension, strip non-alphanumerics, lowercase
15
+ base = re.sub(r"\.[^.]+$", "", s)
16
+ return re.sub(r"[^A-Za-z0-9]", "", base).lower()
17
+
18
+
19
+ LINK_RE = re.compile(r"(?<!\!)\[(?P<text>[^\]]+)\]\((?P<target>[^)\s]+)(?:\s+\"[^\"]*\")?\)")
20
+
21
+
22
+ def should_check_target(target: str) -> bool:
23
+ if re.match(r"^(#|https?://|mailto:|tel:|data:)", target):
24
+ return False
25
+ # only check links that end in .md (ignoring anchors/query)
26
+ core = re.sub(r"[?#].*$", "", target)
27
+ try:
28
+ core = urllib.parse.unquote(core)
29
+ except Exception:
30
+ pass
31
+ return core.lower().endswith(".md")
32
+
33
+
34
+ def main(root: str) -> int:
35
+ issues = 0
36
+ for dirpath, dirnames, filenames in os.walk(root):
37
+ # prune excluded directories
38
+ dirnames[:] = [d for d in dirnames if d not in EXCLUDE_DIRS]
39
+ for filename in filenames:
40
+ if not filename.lower().endswith(".md"):
41
+ continue
42
+ path = os.path.join(dirpath, filename)
43
+ try:
44
+ with open(path, "r", encoding="utf-8") as f:
45
+ lines = f.readlines()
46
+ except Exception:
47
+ continue
48
+ for idx, line in enumerate(lines, start=1):
49
+ for m in LINK_RE.finditer(line):
50
+ text = m.group("text").strip()
51
+ target_raw = m.group("target").strip()
52
+ if not should_check_target(target_raw):
53
+ continue
54
+ target_core = re.sub(r"[?#].*$", "", target_raw)
55
+ try:
56
+ target_core = urllib.parse.unquote(target_core)
57
+ except Exception:
58
+ pass
59
+ file_name = os.path.basename(target_core)
60
+ base_name, _ = os.path.splitext(file_name)
61
+
62
+ is_exact_file_name = text.lower() == file_name.lower()
63
+ looks_like_path = (("/" in text) or ("\\" in text)) and not re.search(r"\s", text)
64
+ looks_like_markdown = text.strip().lower().endswith(".md")
65
+
66
+ if (
67
+ is_exact_file_name
68
+ or looks_like_path
69
+ or looks_like_markdown
70
+ ):
71
+ issues += 1
72
+ msg = f"{path}:{idx}: Link text '{text}' should be human-readable, not a raw file name or path (target: {target_raw})"
73
+ print(msg)
74
+
75
+ if issues:
76
+ print(
77
+ f"Found {issues} documentation link(s) with non-human-readable text.",
78
+ file=sys.stderr,
79
+ )
80
+ print(
81
+ "Use a descriptive phrase instead of the raw file name.", file=sys.stderr
82
+ )
83
+ return 1
84
+ return 0
85
+
86
+
87
+ if __name__ == "__main__":
88
+ root = sys.argv[1] if len(sys.argv) > 1 else "."
89
+ sys.exit(main(root))
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import re
4
+ import sys
5
+
6
+
7
+ EXCLUDE_DIRS = {".git", "node_modules", ".vs", ".vscode", "Library", "Temp"}
8
+
9
+
10
+ # Inline markdown link or image: ![alt](target "title") or [text](target "title")
11
+ INLINE_LINK_RE = re.compile(
12
+ r"!?(?P<all>\[(?P<text>[^\]]+)\]\((?P<target>[^)\s]+)(?:\s+\"[^\"]*\")?\))"
13
+ )
14
+
15
+ # Reference-style link definitions: [id]: target "title"
16
+ REF_DEF_RE = re.compile(r"^\s*\[[^\]]+\]:\s*(?P<target>\S+)(?:\s+\"[^\"]*\")?\s*$")
17
+
18
+
19
+ def is_external(target: str) -> bool:
20
+ return target.startswith("http://") or target.startswith("https://") or target.startswith("mailto:") or target.startswith("tel:") or target.startswith("data:")
21
+
22
+
23
+ def has_unencoded_chars(target: str) -> bool:
24
+ # Only flag raw spaces or plus signs in the path/query/fragment
25
+ return (" " in target) or ("+" in target)
26
+
27
+
28
+ def scan_file(path: str) -> int:
29
+ issues = 0
30
+ try:
31
+ with open(path, "r", encoding="utf-8") as f:
32
+ lines = f.readlines()
33
+ except Exception:
34
+ return 0
35
+
36
+ for idx, line in enumerate(lines, start=1):
37
+ # Inline links/images
38
+ for m in INLINE_LINK_RE.finditer(line):
39
+ target = m.group("target").strip()
40
+ if is_external(target):
41
+ continue
42
+ if has_unencoded_chars(target):
43
+ issues += 1
44
+ print(f"{path}:{idx}: Unencoded character(s) in link target: '{target}'. Encode spaces as %20 and '+' as %2B.")
45
+
46
+ # Reference-style link definitions
47
+ m = REF_DEF_RE.match(line)
48
+ if m:
49
+ target = m.group("target").strip()
50
+ if not is_external(target) and has_unencoded_chars(target):
51
+ issues += 1
52
+ print(f"{path}:{idx}: Unencoded character(s) in link definition: '{target}'. Encode spaces as %20 and '+' as %2B.")
53
+
54
+ return issues
55
+
56
+
57
+ def main(root: str) -> int:
58
+ issues = 0
59
+ for dirpath, dirnames, filenames in os.walk(root):
60
+ dirnames[:] = [d for d in dirnames if d not in EXCLUDE_DIRS]
61
+ for filename in filenames:
62
+ if filename.lower().endswith(".md"):
63
+ issues += scan_file(os.path.join(dirpath, filename))
64
+ if issues:
65
+ print(f"Found {issues} markdown link(s) with unencoded spaces or plus signs.", file=sys.stderr)
66
+ print("Please URL-encode spaces as %20 and '+' as %2B in relative links.", file=sys.stderr)
67
+ return 1
68
+ return 0
69
+
70
+
71
+ if __name__ == "__main__":
72
+ root = sys.argv[1] if len(sys.argv) > 1 else "."
73
+ sys.exit(main(root))
74
+
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import re
4
+ import sys
5
+ import urllib.parse
6
+ from typing import Dict, List, Set, Tuple
7
+
8
+
9
+ EXCLUDE_DIRS = {".git", "node_modules", ".vs"}
10
+
11
+
12
+ LINK_RE = re.compile(r"(?<!\!)\[(?P<text>[^\]]+)\]\((?P<target>[^)\s]+)(?:\s+\"[^\"]*\")?\)")
13
+
14
+
15
+ def unescape_uri(s: str) -> str:
16
+ try:
17
+ return urllib.parse.unquote(s)
18
+ except Exception:
19
+ return s
20
+
21
+
22
+ def normalize_heading_to_id(text: str) -> str:
23
+ """
24
+ Approximate GitHub-style anchor slug generation (GFM):
25
+ - Lowercase
26
+ - Strip Markdown formatting and code ticks
27
+ - Remove most punctuation
28
+ - Replace whitespace with hyphens
29
+ - Collapse multiple hyphens
30
+ - Trim leading/trailing hyphens
31
+ """
32
+ if not text:
33
+ return ""
34
+ t = text
35
+ # Remove inline code ticks
36
+ t = t.replace("`", "")
37
+ # Remove Markdown emphasis markers
38
+ t = t.replace("*", "").replace("_", "").replace("~", "")
39
+ # Remove link/image markup inside headings e.g. [text](url)
40
+ t = re.sub(r"!?\[[^\]]*\]\([^)]*\)", "", t)
41
+ # Remove HTML tags
42
+ t = re.sub(r"<[^>]+>", "", t)
43
+ # Lowercase
44
+ t = t.lower()
45
+ # Replace whitespace with hyphens
46
+ t = re.sub(r"\s+", "-", t)
47
+ # Remove punctuation except hyphens and alphanumerics
48
+ t = re.sub(r"[^a-z0-9-]", "", t)
49
+ # Collapse multiple hyphens
50
+ t = re.sub(r"-+", "-", t)
51
+ # Trim hyphens
52
+ t = t.strip("-")
53
+ return t
54
+
55
+
56
+ def collect_heading_ids(file_path: str) -> Set[str]:
57
+ """
58
+ Build the set of anchor IDs generated by headings within a markdown file.
59
+ Handles ATX (# ...) and Setext (underlined) headings. Accounts for duplicate
60
+ slugs by adding -1, -2, ... suffixes (GitHub behavior).
61
+ """
62
+ try:
63
+ with open(file_path, "r", encoding="utf-8") as f:
64
+ lines = f.readlines()
65
+ except Exception:
66
+ return set()
67
+
68
+ ids: Set[str] = set()
69
+ slug_counts: Dict[str, int] = {}
70
+
71
+ def add_slug_from_text(text: str):
72
+ slug = normalize_heading_to_id(text)
73
+ if slug == "":
74
+ return
75
+ count = slug_counts.get(slug, 0)
76
+ if count == 0:
77
+ final = slug
78
+ else:
79
+ final = f"{slug}-{count}"
80
+ slug_counts[slug] = count + 1
81
+ ids.add(final)
82
+
83
+ # ATX headings
84
+ atx_re = re.compile(r"^\s{0,3}#{1,6}\s+(.*)$")
85
+
86
+ # Walk lines, handle setext headings by looking ahead
87
+ i = 0
88
+ while i < len(lines):
89
+ line = lines[i].rstrip("\n")
90
+ m = atx_re.match(line)
91
+ if m:
92
+ add_slug_from_text(m.group(1).strip())
93
+ i += 1
94
+ continue
95
+ # Setext H1/H2
96
+ if i + 1 < len(lines):
97
+ underline = lines[i + 1].rstrip("\n")
98
+ if re.match(r"^\s{0,3}=+\s*$", underline) or re.match(r"^\s{0,3}-+\s*$", underline):
99
+ add_slug_from_text(line.strip())
100
+ i += 2
101
+ continue
102
+ i += 1
103
+
104
+ return ids
105
+
106
+
107
+ def is_external(target: str) -> bool:
108
+ return bool(re.match(r"^(https?://|mailto:|tel:|data:)", target))
109
+
110
+
111
+ def resolve_path(base_dir: str, target_path: str) -> str:
112
+ return os.path.normpath(os.path.join(base_dir, target_path))
113
+
114
+
115
+ def check_internal_link(src_file: str, target_raw: str) -> Tuple[bool, str]:
116
+ # Separate fragment
117
+ if target_raw.startswith("#"):
118
+ # Anchor within same file
119
+ frag = target_raw[1:]
120
+ anchor = unescape_uri(frag)
121
+ anchor = anchor.strip()
122
+ anchor = anchor.lower()
123
+ ids = collect_heading_ids(src_file)
124
+ if anchor in ids:
125
+ return True, ""
126
+ return False, f"dangling anchor '#{frag}' (no matching heading)"
127
+
128
+ # Split off query/fragment
129
+ core = re.sub(r"[?#].*$", "", target_raw)
130
+ core = unescape_uri(core)
131
+ base_dir = os.path.dirname(src_file)
132
+ target_fs = resolve_path(base_dir, core)
133
+ if not os.path.exists(target_fs):
134
+ return False, f"target file not found: {core}"
135
+
136
+ # Fragment check if present
137
+ m = re.search(r"#(.+)$", target_raw)
138
+ if m:
139
+ frag = m.group(1)
140
+ anchor = unescape_uri(frag).strip().lower()
141
+ ids = collect_heading_ids(target_fs)
142
+ if anchor not in ids:
143
+ return False, f"dangling anchor '#{frag}' in {core}"
144
+
145
+ return True, ""
146
+
147
+
148
+ def main(paths: List[str]) -> int:
149
+ issues = 0
150
+
151
+ def iter_markdown_files() -> List[str]:
152
+ files: List[str] = []
153
+ for p in paths:
154
+ if os.path.isdir(p):
155
+ for dirpath, dirnames, filenames in os.walk(p):
156
+ dirnames[:] = [d for d in dirnames if d not in EXCLUDE_DIRS]
157
+ for filename in filenames:
158
+ if filename.lower().endswith(".md"):
159
+ files.append(os.path.join(dirpath, filename))
160
+ else:
161
+ if p.lower().endswith(".md") and os.path.exists(p):
162
+ files.append(p)
163
+ return files
164
+
165
+ files = iter_markdown_files()
166
+ for path in files:
167
+ try:
168
+ with open(path, "r", encoding="utf-8") as f:
169
+ lines = f.readlines()
170
+ except Exception:
171
+ continue
172
+ for idx, line in enumerate(lines, start=1):
173
+ for m in LINK_RE.finditer(line):
174
+ target = m.group("target").strip()
175
+ # Skip images, external links, anchors we can't resolve externally here
176
+ if is_external(target):
177
+ continue
178
+ ok, reason = check_internal_link(path, target)
179
+ if not ok:
180
+ issues += 1
181
+ print(f"{path}:{idx}: Broken link '{target}': {reason}")
182
+
183
+ if issues:
184
+ print(f"Found {issues} broken internal markdown link(s).", file=sys.stderr)
185
+ print("Fix the paths or anchors so links resolve.", file=sys.stderr)
186
+ return 1
187
+ return 0
188
+
189
+
190
+ if __name__ == "__main__":
191
+ args = sys.argv[1:]
192
+ if not args:
193
+ args = ["."]
194
+ sys.exit(main(args))
@@ -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@v7
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@v7
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
+ }