com.wallstop-studios.dxmessaging 2.0.0-rc27.2 β†’ 2.0.0-rc27.3

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 (42) hide show
  1. package/.github/workflows/csharpier-autofix.yml +2 -2
  2. package/.github/workflows/format-on-demand.yml +6 -6
  3. package/.github/workflows/markdown-link-text-check.yml +1 -1
  4. package/.github/workflows/markdown-link-validity.yml +1 -1
  5. package/.github/workflows/prettier-autofix.yml +11 -4
  6. package/.markdownlint-cli2.jsonc +3 -0
  7. package/.pre-commit-config.yaml +28 -1
  8. package/AGENTS.md +2 -0
  9. package/CONTRIBUTING.md +2 -2
  10. package/Docs/Comparisons.md +1 -1
  11. package/Docs/DesignAndArchitecture.md +0 -5
  12. package/Docs/EmitShorthands.md +11 -14
  13. package/Docs/FAQ.md +3 -3
  14. package/Docs/Glossary.md +5 -5
  15. package/Docs/Helpers.md +144 -33
  16. package/Docs/Index.md +0 -1
  17. package/Docs/InterceptorsAndOrdering.md +3 -3
  18. package/Docs/MessageTypes.md +49 -4
  19. package/Docs/MigrationGuide.md +11 -11
  20. package/Docs/Overview.md +3 -3
  21. package/Docs/Patterns.md +7 -7
  22. package/Docs/Performance.md +9 -9
  23. package/Docs/QuickStart.md +19 -7
  24. package/Docs/TargetingAndContext.md +13 -13
  25. package/Docs/Troubleshooting.md +3 -3
  26. package/Docs/VisualGuide.md +4 -4
  27. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
  28. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta +7 -0
  29. package/README.md +2 -0
  30. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +46 -3
  31. package/Samples~/Mini Combat/README.md +4 -4
  32. package/Samples~/Mini Combat/Walkthrough.md +18 -18
  33. package/Samples~/UI Buttons + Inspector/README.md +1 -1
  34. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +451 -25
  35. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +183 -10
  36. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +41 -0
  37. package/Tests/Runtime/Core/MutationPostProcessorAcrossHandlersTests.cs +2 -8
  38. package/Tests/Runtime/Core/SourceGeneratorNestedTests.cs +116 -0
  39. package/Tests/Runtime/Core/SourceGeneratorNestedTests.cs.meta +11 -0
  40. package/package.json +3 -3
  41. package/scripts/fix-md036-headings.js +71 -0
  42. package/scripts/fix-md036-headings.js.meta +7 -0
@@ -100,7 +100,7 @@ jobs:
100
100
 
101
101
  - name: Open or update formatting PR in base repo
102
102
  if: steps.changes.outputs.has_changes == 'true'
103
- uses: actions/github-script@v7
103
+ uses: actions/github-script@v8
104
104
  with:
105
105
  script: |
106
106
  const prNumber = context.payload.pull_request.number;
@@ -126,7 +126,7 @@ jobs:
126
126
 
127
127
  - name: Comment link on original PR
128
128
  if: steps.changes.outputs.has_changes == 'true'
129
- uses: actions/github-script@v7
129
+ uses: actions/github-script@v8
130
130
  with:
131
131
  script: |
132
132
  const prNumber = context.payload.pull_request.number;
@@ -25,7 +25,7 @@ jobs:
25
25
  steps:
26
26
  - name: Resolve PR metadata and authorize request
27
27
  id: meta
28
- uses: actions/github-script@v7
28
+ uses: actions/github-script@v8
29
29
  with:
30
30
  script: |
31
31
  const prNumber = context.payload.issue.number;
@@ -138,7 +138,7 @@ jobs:
138
138
 
139
139
  - name: Open/Update formatting PR (fork)
140
140
  if: ${{ steps.meta.outputs.same_repo != 'true' && steps.changes.outputs.has_changes == 'true' }}
141
- uses: actions/github-script@v7
141
+ uses: actions/github-script@v8
142
142
  with:
143
143
  script: |
144
144
  const prNumber = Number(core.getInput('pr')) || Number('${{ steps.meta.outputs.pr }}');
@@ -159,7 +159,7 @@ jobs:
159
159
 
160
160
  - name: Comment result on PR
161
161
  if: ${{ steps.changes.outputs.has_changes == 'true' }}
162
- uses: actions/github-script@v7
162
+ uses: actions/github-script@v8
163
163
  with:
164
164
  script: |
165
165
  const prNumber = Number('${{ steps.meta.outputs.pr }}');
@@ -171,7 +171,7 @@ jobs:
171
171
 
172
172
  - name: No-op comment (nothing to change)
173
173
  if: ${{ steps.changes.outputs.has_changes != 'true' }}
174
- uses: actions/github-script@v7
174
+ uses: actions/github-script@v8
175
175
  with:
176
176
  script: |
177
177
  const prNumber = Number('${{ steps.meta.outputs.pr }}');
@@ -185,7 +185,7 @@ jobs:
185
185
  steps:
186
186
  - name: Resolve PR metadata
187
187
  id: meta
188
- uses: actions/github-script@v7
188
+ uses: actions/github-script@v8
189
189
  with:
190
190
  script: |
191
191
  const prNumber = Number(core.getInput('pr_number'));
@@ -284,7 +284,7 @@ jobs:
284
284
 
285
285
  - name: Open/Update formatting PR (fork)
286
286
  if: ${{ steps.meta.outputs.same_repo != 'true' && steps.changes.outputs.has_changes == 'true' }}
287
- uses: actions/github-script@v7
287
+ uses: actions/github-script@v8
288
288
  with:
289
289
  script: |
290
290
  const prNumber = Number('${{ steps.meta.outputs.pr }}');
@@ -12,7 +12,7 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
14
  - name: Checkout
15
- uses: actions/checkout@v4
15
+ uses: actions/checkout@v5
16
16
 
17
17
  - name: Validate link text for markdown-to-markdown links
18
18
  run: python .github/scripts/check_markdown_links.py .
@@ -12,7 +12,7 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
14
  - name: Checkout
15
- uses: actions/checkout@v4
15
+ uses: actions/checkout@v5
16
16
 
17
17
  - name: Run lychee link checker (repo-wide)
18
18
  uses: lycheeverse/lychee-action@v2
@@ -44,7 +44,11 @@ jobs:
44
44
 
45
45
  - name: Markdownlint (auto-fix)
46
46
  if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
47
- run: npx markdownlint "**/*.md" "**/*.markdown" --config .markdownlint.json --ignore-path .markdownlintignore --fix
47
+ run: npx --yes markdownlint-cli@0.40.0 "**/*.md" "**/*.markdown" --config .markdownlint.json --ignore-path .markdownlintignore --fix
48
+
49
+ - name: Fix EOL/BOM (Dependabot only)
50
+ if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
51
+ run: node scripts/fix-eol.js -v
48
52
 
49
53
  - name: Commit formatting changes to PR branch (Dependabot only)
50
54
  if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.login == 'dependabot[bot]' }}
@@ -112,7 +116,10 @@ jobs:
112
116
  npm run format:yaml
113
117
 
114
118
  - name: Markdownlint (auto-fix)
115
- run: npx markdownlint "**/*.md" "**/*.markdown" --config .markdownlint.json --ignore-path .markdownlintignore --fix
119
+ run: npx --yes markdownlint-cli@0.40.0 "**/*.md" "**/*.markdown" --config .markdownlint.json --ignore-path .markdownlintignore --fix
120
+
121
+ - name: Fix EOL/BOM
122
+ run: node scripts/fix-eol.js -v
116
123
 
117
124
  - name: Detect changes
118
125
  id: changes
@@ -146,7 +153,7 @@ jobs:
146
153
 
147
154
  - name: Open or update formatting PR in base repo
148
155
  if: steps.changes.outputs.has_changes == 'true'
149
- uses: actions/github-script@v7
156
+ uses: actions/github-script@v8
150
157
  with:
151
158
  script: |
152
159
  const prNumber = context.payload.pull_request.number;
@@ -171,7 +178,7 @@ jobs:
171
178
 
172
179
  - name: Comment link on original PR
173
180
  if: steps.changes.outputs.has_changes == 'true'
174
- uses: actions/github-script@v7
181
+ uses: actions/github-script@v8
175
182
  with:
176
183
  script: |
177
184
  const prNumber = context.payload.pull_request.number;
@@ -1,4 +1,7 @@
1
1
  {
2
+ // Apply automatic fixes when available
3
+ "fix": true,
4
+
2
5
  // Limit linting impact until large, single-line docs are reformatted
3
6
  "ignores": [
4
7
  // Exclude third-party and generated content
@@ -25,11 +25,20 @@ repos:
25
25
  hooks:
26
26
  - id: prettier
27
27
  name: Prettier (Markdown, JSON, asmdef, asmref, YAML)
28
- entry: npx --yes prettier@3.3.3 --write
28
+ entry: npx --yes prettier@3.6.2 --write
29
29
  language: system
30
30
  files: '(?i)\.(md|markdown|json|asmdef|asmref|ya?ml)$'
31
31
  description: Use pinned Prettier version to match CI.
32
32
 
33
+ - repo: local
34
+ hooks:
35
+ - id: markdown-structure-fix
36
+ name: Markdown structure auto-fix (headings, fences)
37
+ entry: node scripts/fix-md036-headings.js
38
+ language: system
39
+ files: '(?i)\.(md|markdown)$'
40
+ description: Auto-fix MD036 (no-emphasis-as-heading) by converting bold-only lines to headings.
41
+
33
42
  - repo: local
34
43
  hooks:
35
44
  - id: markdownlint
@@ -48,6 +57,14 @@ repos:
48
57
 
49
58
  - repo: local
50
59
  hooks:
60
+ - id: eol-bom-fix
61
+ name: Auto-fix CRLF and remove BOM
62
+ entry: node scripts/fix-eol.js -v
63
+ language: system
64
+ pass_filenames: false
65
+ stages:
66
+ - pre-commit
67
+ description: Convert line endings to CRLF and strip UTF-8 BOM on text files.
51
68
  - id: eol-bom-check
52
69
  name: Enforce CRLF and no BOM
53
70
  entry: node scripts/check-eol.js
@@ -56,3 +73,13 @@ repos:
56
73
  stages:
57
74
  - pre-commit
58
75
  - pre-push
76
+
77
+ - repo: local
78
+ hooks:
79
+ - id: conflict-markers
80
+ name: Fail on merge conflict markers
81
+ entry: bash -lc 'if rg -n -S -g "!**/.git/**" -e "^(<<<<<<<|=======|>>>>>>>)" .; then echo "Conflict markers found. Resolve merges before committing." >&2; exit 1; fi'
82
+ language: system
83
+ pass_filenames: false
84
+ stages:
85
+ - pre-commit
package/AGENTS.md CHANGED
@@ -23,6 +23,7 @@
23
23
  - Place code under `DxMessaging.Core`, `DxMessaging.Unity`, or `DxMessaging.Editor` as appropriate.
24
24
  - Do not use underscores in function names, especially test function names.
25
25
  - Do not use regions, anywhere, ever.
26
+ - Avoid `var` wherever possible, use expressive types.
26
27
 
27
28
  ## Testing Guidelines
28
29
 
@@ -36,6 +37,7 @@
36
37
  - Do not use Description annotations for tests.
37
38
  - Do not create `async Task` test methods - the Unity test runner does not support this. Make do with `IEnumerator` based UnityTestMethods.
38
39
  - Do not use `Assert.ThrowsAsync`, it does not exist.
40
+ - When asserting that UnityEngine.Objects are null or not null, please check for null directly (thing != null, thing == null), to properly adhere to Unity Object existence checks.
39
41
 
40
42
  ## Commit & Pull Request Guidelines
41
43
 
package/CONTRIBUTING.md CHANGED
@@ -25,8 +25,8 @@ Handy commands:
25
25
  - Internal links (local): `python .github/scripts/validate_markdown_links.py .`
26
26
  - Lint markdown (all files): `pre-commit run markdownlint --all-files`
27
27
  - Lint markdown (manual): `npx markdownlint-cli@0.41.0 "**/*.md" -c .markdownlint.jsonc --fix`
28
- - Format JSON/.asmdef (all files): `pre-commit run prettier-json --all-files`
29
- - Format JSON/.asmdef (manual): `npx prettier@3.3.3 --write "**/*.{json,asmdef}"`
28
+ - Format JSON/.asmdef (all files): `pre-commit run prettier --all-files`
29
+ - Format JSON/.asmdef (manual): `npx prettier@3.6.2 --write "**/*.{json,asmdef}"`
30
30
  - Format YAML (all files): `pre-commit run prettier-yaml --all-files`
31
31
  - Check YAML formatting + lint: `npm run check:yaml`
32
32
  - Fix EOL/BOM issues quickly: `node scripts/fix-eol.js -v`
@@ -358,7 +358,7 @@ Add/remove systems without affecting others
358
358
  - βœ… Observability - Count messages, inspect payloads easily
359
359
  - βœ… Determinism - Priority-based ordering eliminates flakiness
360
360
 
361
- **Example:**
361
+ ##### Example
362
362
 
363
363
  ```csharp
364
364
  // Test with isolated bus
@@ -18,31 +18,26 @@ This document explains DxMessaging’s internal design, performance optimization
18
18
  DxMessaging was built with these principles:
19
19
 
20
20
  1. Zero‑Allocation Communication
21
-
22
21
  - Messages are `readonly struct` types passed by `ref`.
23
22
  - No boxing, no temporary objects, minimal GC pressure.
24
23
  - Handlers receive `ref` parameters for struct messages.
25
24
 
26
25
  1. Type‑Safe by Default
27
-
28
26
  - Compile‑time guarantees via generic constraints.
29
27
  - No string‑based dispatch (unlike Unity’s `SendMessage`).
30
28
  - Source generators provide boilerplate‑free message definitions.
31
29
 
32
30
  1. Predictable Execution
33
-
34
31
  - Priority‑based handler ordering (lower priority runs first).
35
32
  - Three‑stage pipeline: Interceptors β†’ Handlers β†’ Post‑Processors.
36
33
  - Deterministic behavior within each priority level.
37
34
 
38
35
  1. Observable & Debuggable
39
-
40
36
  - Built‑in diagnostics via `CyclicBuffer`.
41
37
  - Registration logging with `RegistrationLog`.
42
38
  - Inspector integration for runtime visibility.
43
39
 
44
40
  1. Lifecycle Safety
45
-
46
41
  - `MessageRegistrationToken` manages enable/disable.
47
42
  - Automatic cleanup prevents memory leaks.
48
43
  - Unity lifecycle integration via `MessageAwareComponent`.
@@ -60,7 +60,7 @@ var msg = new GamePaused();
60
60
  msg.Emit(); // Every listener receives this
61
61
  ```
62
62
 
63
- **Equivalent to:**
63
+ #### Equivalent to
64
64
 
65
65
  ```csharp
66
66
  msg.EmitUntargeted();
@@ -68,7 +68,7 @@ msg.EmitUntargeted();
68
68
  MessageHandler.MessageBus.UntargetedBroadcast(ref msg);
69
69
  ```
70
70
 
71
- **Examples:**
71
+ ##### Examples
72
72
 
73
73
  - Scene loaded/unloaded
74
74
  - Game state changes (paused, resumed)
@@ -90,7 +90,7 @@ heal.EmitAt(player); // Only the player receives this
90
90
 
91
91
  **Caution:** `InstanceId` has implicit conversion from both `GameObject` and `Component`. Make sure your target type matches how listeners registered!
92
92
 
93
- **Examples:**
93
+ #### Examples
94
94
 
95
95
  - Heal/damage commands to specific entities
96
96
  - UI updates for specific panels
@@ -109,7 +109,7 @@ var damage = new TookDamage(5);
109
109
  damage.EmitFrom(enemy); // Anyone interested in this enemy receives it
110
110
  ```
111
111
 
112
- **Use cases:**
112
+ #### Use cases
113
113
 
114
114
  - Combat logging ("Enemy X took damage")
115
115
  - Analytics ("Track damage from specific boss")
@@ -160,7 +160,7 @@ void OnAnyDamage(ref InstanceId source, ref TookDamage msg)
160
160
  }
161
161
  ```
162
162
 
163
- **Why this is revolutionary:**
163
+ #### Why this is revolutionary
164
164
 
165
165
  - **Classic event bus:** Subscribe to PlayerDamaged, EnemyDamaged, NPCDamaged... (tight coupling)
166
166
  - **DxMessaging:** Subscribe to ALL damage once (zero coupling, infinite scalability)
@@ -169,7 +169,7 @@ void OnAnyDamage(ref InstanceId source, ref TookDamage msg)
169
169
 
170
170
  ---
171
171
 
172
- **πŸ“– For the full deep dive on GameObject vs Component targeting and global observers, see [Targeting & Context](TargetingAndContext.md)**
172
+ ##### πŸ“– For the full deep dive on GameObject vs Component targeting and global observers, see [Targeting & Context](TargetingAndContext.md)
173
173
 
174
174
  ---
175
175
 
@@ -244,14 +244,14 @@ DxMessaging includes three built-in string message types for rapid prototyping:
244
244
 
245
245
  ### When to Use String Messages
246
246
 
247
- **Good for:**
247
+ #### Good for
248
248
 
249
249
  - Rapid prototyping
250
250
  - Debug logging
251
251
  - Test utilities
252
252
  - Tool scripts
253
253
 
254
- **Not good for:**
254
+ ##### Not good for
255
255
 
256
256
  - Production gameplay code (use typed messages instead)
257
257
  - Performance-critical paths
@@ -271,7 +271,7 @@ msg.EmitAt(target, localBus); // Target on specific bus
271
271
  msg.EmitFrom(source, localBus); // Broadcast on specific bus
272
272
  ```
273
273
 
274
- **When to use:**
274
+ ### When to use
275
275
 
276
276
  - Testing with isolated buses
277
277
  - Subsystems with their own message domains
@@ -295,20 +295,17 @@ If a handler isn’t firing, first suspect a GameObject vs Component mismatch. S
295
295
 
296
296
  ### "My handler isn't firing!"
297
297
 
298
- **Check these in order:**
298
+ #### Check these in order
299
299
 
300
300
  1. **GameObject vs Component mismatch?**
301
-
302
301
  - Did you register for a GameObject but emit to a Component (or vice versa)?
303
302
  - Use explicit helpers (`EmitGameObjectTargeted` vs `EmitComponentTargeted`) to eliminate this issue
304
303
 
305
304
  1. **Is the handler enabled?**
306
-
307
305
  - Check that `token.Enable()` was called (usually in `OnEnable`)
308
306
  - Verify the component is active
309
307
 
310
308
  1. **Correct message type?**
311
-
312
309
  - Untargeted messages use `Emit()`
313
310
  - Targeted messages use `EmitAt(target)`
314
311
  - Broadcast messages use `EmitFrom(source)`
@@ -344,7 +341,7 @@ See [Diagnostics](Diagnostics.md) for more debugging tools.
344
341
  | **Broadcast from Component** | `msg.EmitFrom(component)` | `msg.EmitComponentBroadcast(component)` |
345
342
  | **Non-Unity InstanceId** | `msg.EmitAt(id)` | `msg.EmitTargeted(id)` |
346
343
 
347
- **Our recommendation:**
344
+ ### Our recommendation
348
345
 
349
346
  - In Unity gameplay code: Use **explicit helpers** for clarity and safety
350
347
  - In tests and non-Unity code: Use **shorthands** for brevity
package/Docs/FAQ.md CHANGED
@@ -45,18 +45,18 @@ Do I need a global bus?
45
45
 
46
46
  ## Related Documentation
47
47
 
48
- **New to DxMessaging?**
48
+ ### New to DxMessaging?
49
49
 
50
50
  - β†’ [Visual Guide](VisualGuide.md) β€” Beginner-friendly introduction
51
51
  - β†’ [Getting Started](GettingStarted.md) β€” Complete guide
52
52
  - β†’ [Glossary](Glossary.md) β€” All terms explained
53
53
 
54
- **Common Issues:**
54
+ #### Common Issues
55
55
 
56
56
  - β†’ [Troubleshooting](Troubleshooting.md) β€” Solutions to common problems
57
57
  - β†’ [Common Patterns](Patterns.md) β€” See how to use it correctly
58
58
 
59
- **Reference:**
59
+ ##### Reference
60
60
 
61
61
  - β†’ [Quick Reference](QuickReference.md) β€” API cheat sheet
62
62
  - β†’ [Message Types](MessageTypes.md) β€” Which type to use when
package/Docs/Glossary.md CHANGED
@@ -205,7 +205,7 @@ DxMessaging handles this automatically via `MessageAwareComponent`:
205
205
 
206
206
  Making systems **independent** so they don't need references to each other.
207
207
 
208
- **Before DxMessaging:**
208
+ #### Before DxMessaging
209
209
 
210
210
  ```csharp
211
211
  public class UI : MonoBehaviour {
@@ -215,7 +215,7 @@ public class UI : MonoBehaviour {
215
215
  }
216
216
  ```
217
217
 
218
- **With DxMessaging:**
218
+ ##### With DxMessaging
219
219
 
220
220
  ```csharp
221
221
  public class UI : MessageAwareComponent {
@@ -245,18 +245,18 @@ public class UI : MessageAwareComponent {
245
245
 
246
246
  ## Related Documentation
247
247
 
248
- **Learn More:**
248
+ ### Learn More
249
249
 
250
250
  - β†’ [Visual Guide](VisualGuide.md) β€” See these concepts visualized
251
251
  - β†’ [Getting Started](GettingStarted.md) β€” Full introduction with examples
252
252
  - β†’ [Message Types](MessageTypes.md) β€” When to use each type
253
253
 
254
- **Reference:**
254
+ #### Reference
255
255
 
256
256
  - β†’ [Quick Reference](QuickReference.md) β€” API cheat sheet
257
257
  - β†’ [API Reference](Reference.md) β€” Complete API documentation
258
258
 
259
- **Examples:**
259
+ ##### Examples
260
260
 
261
261
  - β†’ [Mini Combat sample](../Samples~/Mini%20Combat/README.md) β€” See concepts in action
262
262
  - β†’ [Patterns](Patterns.md) β€” Real-world usage patterns