Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions .claude/skills/sync-readmes/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: Verify and update Aspid.FastTools README files against the actual c
user-invocable: false
---

The package ships **fourteen** README files (4 main + 10 sample) that drift from the code easily. Use after any change touching namespaces of public types, public API surface, `[CreateAssetMenu]` paths, source generator output, or sample structure.
The package ships **sixteen** README files (4 main + 12 sample) that drift from the code easily. Use after any change touching namespaces of public types, public API surface, `[CreateAssetMenu]` paths, source generator output, or sample structure.

## Files in scope

Expand All @@ -17,16 +17,18 @@ The package ships **fourteen** README files (4 main + 10 sample) that drift from
| `Aspid.FastTools/Packages/tech.aspid.fasttools/Documentation/EN/README.md` | EN | `../Images/` |
| `Aspid.FastTools/Packages/tech.aspid.fasttools/Documentation/RU/README.md` | RU | `../Images/` |

Per-feature references (`SerializedPropertyExtensions.md`, `VisualElementExtensions.md`) live alongside the Documentation copies inside `Documentation/EN/` and `Documentation/RU/`.
Per-feature references (`Types.md`, `SerializeReferences.md`, `SerializeReferenceTooling.md`, `Ids.md`, `SerializedPropertyExtensions.md`, `VisualElementExtensions.md`) live alongside the Documentation copies inside `Documentation/EN/` and `Documentation/RU/`.

Expected structural differences between root and Documentation copies (not drift):

- **Badge block** (Unity / Release / License shields) — only in the root copies.
- **`## Source Code` / `## Исходный код` block** linking to the GitHub repo — only in the Documentation copies.
- **Badge block** (Unity / Stable / Preview / License shields) — only in the root copies.
- **Language switcher** under the banner — root links `README.md` / `README_RU.md`; Documentation copies link the sibling locale as `../RU/README.md` / `../EN/README.md`.
- **Source-code link row** (`[Source Code](…) · [Unity Asset Store](…) · [Releases](…)`, RU: `Исходный код`) under the one-liner — only in the Documentation copies.
- **LICENSE / CHANGELOG links** (in `## License` / `## Лицензия`) — root uses repo-relative paths; Documentation copies use absolute `github.com/.../blob/main/...` URLs.
- **Image paths** — see table above.
- **Feature-reference links** — root uses the full `Documentation/EN/...` path; Documentation copies link to the bare filename (same folder).

**Sample READMEs** — one EN + one RU per sample folder under `Aspid.FastTools/Packages/tech.aspid.fasttools/Samples~/` (`Types/`, `Ids/`, `EnumValues/`, `ProfilerMarkers/`, `VisualElements/`).
**Sample READMEs** — one EN + one RU per sample folder under `Aspid.FastTools/Packages/tech.aspid.fasttools/Samples~/` (`Types/`, `Ids/`, `EnumValues/`, `ProfilerMarkers/`, `VisualElements/`, `SerializeReferences/`).

## Workflow

Expand All @@ -45,7 +47,6 @@ For every fact the README states, prove it from the code:
Where READMEs historically lie (re-verify these even if the text looks plausible):

- **Namespaces** — they are split per feature (runtime and editor alike); never assume a type sits in the root `Aspid.FastTools`. Check the `using` lines in samples.
- **The two ID registries** — `StringIdRegistry` and `IdRegistry` have different APIs, menu paths, and runtime behavior; don't conflate them — read both sources.
- **Sample asset menu paths** — samples use their own menu segment order; always re-grep `[CreateAssetMenu]` instead of trusting the existing README.

### 2. Apply edits to all matching files
Expand Down
37 changes: 1 addition & 36 deletions Aspid.FastTools.Generators/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@ Deploy pipeline: `Aspid.FastTools.Generators/ILRepack.targets` merges `Aspid.Gen

A repo-level PostToolUse hook (`.claude/hooks/rebuild-generators-on-change.sh`) also runs `dotnet build` automatically after any `Edit`/`Write` to `*.cs` under `Aspid.FastTools.Generators/Aspid.FastTools.Generators/`. The hook intentionally **does not** trigger for tests, the Sample project, or Unity-side edits — keep that scope if you modify it.

## Solution Structure

```
Aspid.FastTools.Generators/ ← generator implementation (+ ILRepack.targets deploy merge)
Aspid.FastTools.Generators.Tests/ ← unit tests + GeneratorTestHost helper
Aspid.FastTools.Generators.Sample/ ← manual smoke-test project
Aspid.FastTools.Generators.sln
Directory.Build.targets ← copies the merged DLL into the Unity package
```

## Target Framework

`netstandard2.0` — required by Roslyn. No Unity assemblies, no runtime packages.
Expand Down Expand Up @@ -95,32 +85,7 @@ Pipeline data passed between stages **must be value-equatable**. Roslyn caches r
- `Equals` and `GetHashCode` over every field
- For nested arrays use `ImmutableArray<T>` with element-wise comparison (or `EquatableArray<T>` if introduced)

Reference shapes:

```csharp
internal readonly struct TypeData : IEquatable<TypeData>
{
public readonly string TypeKey; // "Foo.Outer.Inner"
public readonly string TypeName;
public readonly string? Namespace;
public readonly string ContainingTypeChain; // "Outer.Middle." or ""
public readonly string FullyQualifiedDisplay;
public readonly string TypeParamList; // "<T,U>" or ""
public readonly string ConstraintsClause;
public readonly int Arity;
// ... ctor + IEquatable<TypeData> Equals/GetHashCode over all fields
}

internal readonly struct IdStructData : IEquatable<IdStructData>
{
public readonly string StructName;
public readonly string TypeParameters; // "<T>" or ""
public readonly int Arity;
public readonly string? Namespace;
public readonly ImmutableArray<ContainingTypeInfo> ContainingTypes;
// ... IEquatable<IdStructData> walks ContainingTypes element-wise
}
```
Reference shapes: `TypeData` and `IdStructData` in the generator sources.

Cache stability is regression-tested in `IncrementalCacheTests` — that test runs each generator twice over compilations differing only in an unrelated source file, and asserts every output step is `Cached`/`Unchanged`. Adding a non-equatable field to any pipeline struct will fail it.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2681730314047826224
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3946854324957946979}
- component: {fileID: 9052271508596160596}
m_Layer: 0
m_Name: BrokenWeaponPreset
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3946854324957946979
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2681730314047826224}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &9052271508596160596
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2681730314047826224}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 812007f2bd1be48ee8eca8c040018591, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Game.Gear.Loadout
_primary:
rid: 2339642446330462275
_sidearms:
- rid: 2339642446330462276
references:
version: 2
RefIds:
- rid: 2339642446330462275
type: {class: Pistoll, ns: Game.Gear, asm: Assembly-CSharp}
data:
_damage: 10
- rid: 2339642446330462276
type: {class: Shotgun, ns: Game.Gear, asm: Assembly-CSharp}
data:
_pellets: 8
_spread: 12

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2681730314047826224
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3946854324957946979}
- component: {fileID: 9052271508596160596}
m_Layer: 0
m_Name: SharedWeaponPreset
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3946854324957946979
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2681730314047826224}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &9052271508596160596
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2681730314047826224}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 812007f2bd1be48ee8eca8c040018591, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Game.Gear.Loadout
_primary:
rid: 2339642446330462275
_sidearms:
- rid: 2339642446330462275
references:
version: 2
RefIds:
- rid: 2339642446330462275
type: {class: Pistol, ns: Game.Gear, asm: Assembly-CSharp}
data:
_damage: 10

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2681730314047826224
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3946854324957946979}
- component: {fileID: 9052271508596160596}
m_Layer: 0
m_Name: WeaponPreset
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3946854324957946979
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2681730314047826224}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &9052271508596160596
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2681730314047826224}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 812007f2bd1be48ee8eca8c040018591, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Game.Gear.Loadout
_primary:
rid: 2339642446330462275
_sidearms:
- rid: 2339642446330462276
references:
version: 2
RefIds:
- rid: 2339642446330462275
type: {class: Pistol, ns: Game.Gear, asm: Assembly-CSharp}
data:
_damage: 10
- rid: 2339642446330462276
type: {class: Shotgun, ns: Game.Gear, asm: Assembly-CSharp}
data:
_pellets: 8
_spread: 12

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using UnityEngine;
using System.Collections.Generic;
using Aspid.FastTools.Types;

// Docs-media harness: mirrors the SerializeReference Selector example in
// Documentation/EN|RU/SerializeReferences.md — IWeapon implementations picked into
// [SerializeReference] fields. Lives in DevTests, but uses a neutral game-like
// namespace because the picker breadcrumbs are visible in the recorded media.

// ReSharper disable once CheckNamespace
namespace Game.Gear
{
public interface IWeapon
{
void Fire();
}

[Serializable]
public sealed class Pistol : IWeapon
{
[SerializeField] [Min(0)] private int _damage = 10;

public void Fire() => Debug.Log($"Pistol: {_damage} dmg");
}

[Serializable]
public sealed class Shotgun : IWeapon
{
[SerializeField] [Min(1)] private int _pellets = 8;
[SerializeField] [Range(0f, 45f)] private float _spread = 12f;

public void Fire() => Debug.Log($"Shotgun: {_pellets} pellets, {_spread}° spread");
}

[Serializable]
public sealed class PlasmaRifle : IWeapon
{
[SerializeField] [Min(0f)] private float _power = 40f;
[SerializeField] [Min(0f)] private float _range = 60f;

public void Fire() => Debug.Log($"Plasma rifle: {_power} power, {_range} m");
}

public sealed class Loadout : MonoBehaviour
{
[TypeSelector]
[SerializeReference] private IWeapon _primary;

[TypeSelector]
[SerializeReference] private List<IWeapon> _sidearms;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Aspid.FastTools/Assets/DevTests/Types/Scripts/DocsMedia.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading