Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
88cfe10
Update generator
Nov 29, 2025
8a419b8
Fix bugs
Dec 25, 2025
1e0fdb7
Fix
Jan 19, 2026
9e9385b
Update EnumPropertyDrawer and SerializableType
VPDPersonal Feb 2, 2026
6088eea
Add package.json
VPDPersonal Feb 2, 2026
e8105a9
Add meta file
VPDPersonal Feb 2, 2026
dee5d62
Update TypeSelector
VPDPersonal Feb 19, 2026
2c3575e
Update
VPDPersonal Mar 4, 2026
a523813
Update README.md
Mar 4, 2026
72a7607
Add README_RU.md.meta
VPDPersonal Mar 4, 2026
4702ec8
Integrate Aspid.Internal.Unity
VPDPersonal Mar 4, 2026
63492ec
Add Samples to UnityFastTools json
VPDPersonal Mar 4, 2026
0815798
Rename Samples
VPDPersonal Mar 4, 2026
25f000f
Fix package.json
VPDPersonal Mar 4, 2026
4a289ec
Fix package.json
VPDPersonal Mar 4, 2026
437aad8
Rename UnityFastTools to FastTools
VPDPersonal Mar 4, 2026
2bada94
Fix README
VPDPersonal Mar 4, 2026
e7cf7af
Merge remote-tracking branch 'origin/main' into Develop
VPDPersonal Mar 4, 2026
b38c788
Fix smaples and package.json
VPDPersonal Mar 5, 2026
ac908c2
Fix GetScriptNameWithIndex
VPDPersonal Mar 7, 2026
3ef883d
Update
VPDPersonal Mar 19, 2026
98ae32a
Add CLAUDE.md
VPDPersonal Mar 21, 2026
c392d3e
Add Generic Support
VPDPersonal Mar 21, 2026
d664d40
Fix extension methods
VPDPersonal Mar 24, 2026
39b2164
Add ComponentTypeSelectorAttribute
VPDPersonal Mar 25, 2026
16e5846
Update Unity
VPDPersonal Mar 25, 2026
a4ee044
Add prototype
VPDPersonal Mar 25, 2026
a7253de
Fix rename
VPDPersonal Mar 25, 2026
088429b
Fix Rename
VPDPersonal Mar 25, 2026
15d5f76
Optimize performance and reduce code duplication
VPDPersonal Mar 26, 2026
eba8cfa
Add dialog window
VPDPersonal Mar 26, 2026
a1e1e73
Update
VPDPersonal Mar 27, 2026
29bf5ba
Update
VPDPersonal Mar 27, 2026
ad77650
Add xml comments
VPDPersonal Mar 27, 2026
ee0e3a7
Big Refactoring
VPDPersonal Apr 3, 2026
a53cf90
Fix
VPDPersonal Apr 3, 2026
9dee4db
Fix
VPDPersonal Apr 3, 2026
0339855
Fix
VPDPersonal Apr 3, 2026
f04f822
Fix
VPDPersonal Apr 3, 2026
65ba5c3
Fix
VPDPersonal Apr 3, 2026
1cae9f5
Fix
VPDPersonal Apr 3, 2026
115cb2c
Add XML documentation to VisualElement and IStyle extensions
VPDPersonal Apr 4, 2026
75b3412
Clean
VPDPersonal Apr 4, 2026
4cc91c0
Fix for addressables
VPDPersonal Apr 5, 2026
d9f8f5f
Fix meta
VPDPersonal Apr 5, 2026
29a2e23
Update samples
VPDPersonal Apr 5, 2026
9e4d4ff
update ignore
VPDPersonal Apr 5, 2026
3f2542a
Update Readme and Claude.md
VPDPersonal Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
36 changes: 36 additions & 0 deletions .claude/agents/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: code-reviewer
description: Reviews C# code for Unity/Editor boundary violations, generator correctness, and package conventions
---

You are a C# code reviewer specializing in Unity packages and Roslyn source generators. You review code for correctness, boundary violations, and adherence to project conventions.

## Project Context

This is **Aspid.FastTools** — a Unity package (`com.aspid.fasttools`) with two separate projects:
- `Aspid.FastTools/` — Unity project (Runtime + Editor assemblies)
- `Aspid.FastTools.Generators/` — .NET solution with Roslyn source generators

## Review Checklist

### Assembly Boundaries
- `Unity/Runtime/` code must NOT reference `UnityEditor` namespace — it ships with player builds
- `Unity/Editor/Scripts/` code is editor-only and may use `UnityEditor` freely
- Generator code targets `netstandard2.0` and must NOT reference any Unity assemblies

### Generators (`Aspid.FastTools.Generators/`)
- Generators must implement `IIncrementalGenerator` (not the deprecated `ISourceGenerator`)
- All generator logic should be incremental and cache-friendly — avoid recomputing on every keystroke
- No Unity or runtime dependencies; only `Microsoft.CodeAnalysis.CSharp` and `Aspid.Generators.Helper`

### Unity Runtime Code
- Prefer `[SerializeField]` over public fields for Inspector-visible state
- `ScriptableObject` subclasses should not be instantiated with `new` — use `ScriptableObject.CreateInstance`
- Extension methods on `VisualElement` should follow the fluent pattern already established in `VisualElementExtensions.*`

### General C# Quality
- Nullable annotations must be consistent — the project has `<Nullable>enable</Nullable>`
- Avoid boxing of value types in hot paths (ProfilerMarkers, EnumValues iteration)
- Partial classes must all reside in files named consistently with the partial suffix pattern used elsewhere

Report issues grouped by severity: **Error** (breaks compilation or runtime), **Warning** (likely bug or convention violation), **Info** (minor improvement).
13 changes: 13 additions & 0 deletions .claude/skills/build-generator/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: build-generator
description: Build Roslyn source generators and deploy the resulting DLL into the Unity package
user-invocable: true
---

Build the Aspid.FastTools source generators and deploy to Unity:

1. Run `dotnet build Aspid.FastTools.Generators/Aspid.FastTools.Generators/Aspid.FastTools.Generators.csproj -c Release` from the repository root
2. Copy `Aspid.FastTools.Generators/Aspid.FastTools.Generators/bin/Release/netstandard2.0/Aspid.FastTools.Generators.dll` to `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll`
3. Report the result: build output, any errors, and confirm the DLL was copied successfully

Arguments: $ARGUMENTS (optional: pass `Debug` to build in Debug configuration instead of Release)
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.claude/settings.local.json
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "Aspid.FastTools/Assets/Plugins/Aspid/Internal/Unity"]
path = Aspid.FastTools/Assets/Plugins/Aspid/Internal/Unity
url = git@github.com:VPDPersonal/Aspid.Internal.Unity.git
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>UnityFastToolsGenerators.Sample</RootNamespace>
<RootNamespace>Aspid.FastTools.Sample</RootNamespace>
<UnityVersion>6000.2.7f2</UnityVersion>
<LangVersion>9</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Aspid.UnityFastTools.Generators\Aspid.UnityFastTools.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\Aspid.FastTools.Generators\Aspid.FastTools.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<IsPackable>false</IsPackable>

<RootNamespace>UnityFastToolsGenerators.Tests</RootNamespace>
<RootNamespace>Aspid.FastTools.Tests</RootNamespace>
</PropertyGroup>

<ItemGroup>
Expand All @@ -20,7 +20,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Aspid.UnityFastTools.Generators\Aspid.UnityFastTools.Generators.csproj" />
<ProjectReference Include="..\Aspid.FastTools.Generators\Aspid.FastTools.Generators.csproj" />
</ItemGroup>


Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.UnityFastTools.Generators", "UnityFastToolsGenerators\Aspid.UnityFastTools.Generators\Aspid.UnityFastTools.Generators.csproj", "{CB9D8D51-7D86-4B84-A0DB-73E418962DA7}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.FastTools.Generators", "Aspid.FastTools.Generators\Aspid.FastTools.Generators.csproj", "{CB9D8D51-7D86-4B84-A0DB-73E418962DA7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.UnityFastTools.Generators.Sample", "UnityFastToolsGenerators\Aspid.UnityFastTools.Generators.Sample\Aspid.UnityFastTools.Generators.Sample.csproj", "{2835DD81-D105-4C2E-AE03-BC7D064C29D1}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.FastTools.Generators.Sample", "Aspid.FastTools.Generators.Sample\Aspid.FastTools.Generators.Sample.csproj", "{2835DD81-D105-4C2E-AE03-BC7D064C29D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.UnityFastTools.Generators.Tests", "UnityFastToolsGenerators\Aspid.UnityFastTools.Generators.Tests\Aspid.UnityFastTools.Generators.Tests.csproj", "{F4953608-2F14-4B2E-B91C-B3FDFC81B180}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.FastTools.Generators.Tests", "Aspid.FastTools.Generators.Tests\Aspid.FastTools.Generators.Tests.csproj", "{F4953608-2F14-4B2E-B91C-B3FDFC81B180}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>13</LangVersion>
<LangVersion>latest</LangVersion>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<RootNamespace>UnityFastToolsGenerators</RootNamespace>
<RootNamespace>Aspid.FastTools</RootNamespace>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Aspid.Generators.Helper;

namespace Aspid.FastTools.Descriptions;

public static class General
{
public static readonly string ProfilerMarkerGeneratedCode = $"""{Classes.GeneratedCodeAttribute}("Aspid.FastTools.Generators.ProfilerMarkersGenerator", "1.0.0")""";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.CodeAnalysis;
using Aspid.Generators.Helper;
using Aspid.FastTools.Generators.IdStruct.Data;

namespace Aspid.FastTools.Generators.IdStruct.Bodies;

public static class IdStructBody
{
public static void GenerateCode(in SourceProductionContext context, in IdStructData data)
{
var hasNamespace = data.Namespace != null;

var code = new CodeWriter()
.AppendLine("// <auto-generated>")
.AppendLine("#nullable enable")
.AppendLine()
.AppendLineIf(hasNamespace, $"namespace {data.Namespace}")
.BeginBlockIf(hasNamespace)
.AppendLine($"partial struct {data.StructName}")
.BeginBlock()
.AppendLine("#if UNITY_EDITOR")
.AppendLine("[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]")
.AppendLine("[global::UnityEngine.SerializeField] private string __stringId;")
.AppendLine("#endif")
.AppendLine("[global::UnityEngine.SerializeField] private int _id;")
.AppendLine("public int Id => _id;")
.EndBlock()
.EndBlockIf(hasNamespace);

var hintName = $"{data.StructName}.IId.g.cs";
context.AddSource(hintName, code.GetSourceText());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.CodeAnalysis;

namespace Aspid.FastTools.Generators.IdStruct.Data;

public readonly struct IdStructData(INamedTypeSymbol symbol)
{
public readonly INamedTypeSymbol Symbol = symbol;
public readonly string StructName = symbol.Name;
public readonly string? Namespace = symbol.ContainingNamespace.IsGlobalNamespace
? null
: symbol.ContainingNamespace.ToDisplayString();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Aspid.FastTools.Generators.IdStruct.Data;
using Aspid.FastTools.Generators.IdStruct.Bodies;

namespace Aspid.FastTools.Generators.IdStruct;

[Generator(LanguageNames.CSharp)]
public class IdStructGenerator : IIncrementalGenerator
{
private const string IIdFullName = "Aspid.FastTools.IId";

public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.SyntaxProvider
.CreateSyntaxProvider(Predicate, Transform)
.Where(static d => d.HasValue)
.Select(static (d, _) => d!.Value);

context.RegisterSourceOutput(provider, static (ctx, data) => IdStructBody.GenerateCode(ctx, data));
}

private static bool Predicate(SyntaxNode node, CancellationToken _)
{
if (node is not StructDeclarationSyntax structDecl) return false;
if (!structDecl.Modifiers.Any(SyntaxKind.PartialKeyword)) return false;
return structDecl.BaseList is { Types.Count: > 0 };
}

private static IdStructData? Transform(GeneratorSyntaxContext context, CancellationToken ct)
{
var structDecl = (StructDeclarationSyntax)context.Node;

if (context.SemanticModel.GetDeclaredSymbol(structDecl, ct) is not INamedTypeSymbol symbol)
return null;

var iidInterface = context.SemanticModel.Compilation.GetTypeByMetadataName(IIdFullName);
if (iidInterface == null) return null;

foreach (var iface in symbol.AllInterfaces)
{
if (SymbolEqualityComparer.Default.Equals(iface, iidInterface))
return new IdStructData(symbol);
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
using Microsoft.CodeAnalysis;
using Aspid.Generators.Helper;
using System.Collections.Immutable;
using UnityFastToolsGenerators.Generators.ProfilerMarkers.Data;
using Aspid.FastTools.Generators.ProfilerMarkers.Data;
using static Aspid.Generators.Helper.Classes;
using static Aspid.FastTools.Descriptions.General;
using static Aspid.Generators.Helper.Unity.UnityClasses;
using static UnityFastToolsGenerators.Descriptions.General;

namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Bodies;
namespace Aspid.FastTools.Generators.ProfilerMarkers.Bodies;

public static class ExtensionClassBody
{
public static void GenerateCode(in SourceProductionContext context, in ImmutableArray<MarkerCall> markerCalls)
{
var markerCallTypes = markerCalls
.GroupBy(markerCall => markerCall.NamedTypeSymbol, SymbolEqualityComparer.Default)
.Select(group => new MarkerCallType(group.Key!, group.ToImmutableArray()));
.Select(group => new MarkerCallType((INamedTypeSymbol)group.Key!, group.ToImmutableArray()));

foreach (var markerCallType in markerCallTypes)
GenerateCode(context, markerCallType);
Expand All @@ -28,13 +28,14 @@ private static void GenerateCode(in SourceProductionContext context, in MarkerCa

var hasNamespaceName = !symbol.ContainingNamespace.IsGlobalNamespace;
var namespaceName = hasNamespaceName ? symbol.ContainingNamespace.ToDisplayString() : null;

var markerCallMembers = type.MarkerCalls
.GroupBy(markerCall => markerCall.MethodSymbol, SymbolEqualityComparer.Default)
.Select(grouping => new MarkerCallMember((IMethodSymbol)grouping.Key!, grouping.ToImmutableArray()))
.ToImmutableArray();

var className = $"__{typeName}ProfilerMarkerExtensions";
var arityPart = symbol.Arity > 0 ? $"_{symbol.Arity}" : string.Empty;
var className = $"__{typeName}{arityPart}ProfilerMarkerExtensions";

var code = new CodeWriter()
.AppendLine("// <auto-generated>")
Expand Down Expand Up @@ -76,11 +77,16 @@ private static CodeWriter AppendProfilerMarkers(this CodeWriter code, ImmutableA

private static CodeWriter AppendWithoutMessage(
this CodeWriter code,
ISymbol symbol,
INamedTypeSymbol symbol,
ImmutableArray<MarkerCallMember> markerCallMembers)
{
var typeParams = symbol.TypeParameters;
var typeParamList = typeParams.Length > 0
? $"<{string.Join(", ", typeParams.Select(p => p.Name))}>"
: string.Empty;

code.AppendLine($"[{ProfilerMarkerGeneratedCode}]")
.AppendLine($"public static {ProfilerMarker}.AutoScope Marker(this {symbol.ToDisplayStringGlobal()} _, [{CallerLineNumberAttribute}] int line = -1)")
.AppendLine($"public static {ProfilerMarker}.AutoScope Marker{typeParamList}(this {symbol.ToDisplayStringGlobal()} _, [{CallerLineNumberAttribute}] int line = -1)")
.BeginBlock();

foreach (var markerCall in markerCallMembers.SelectMany(member => member.MarkerCalls))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.CodeAnalysis;

namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Data;
namespace Aspid.FastTools.Generators.ProfilerMarkers.Data;

public readonly struct MarkerCall(
INamedTypeSymbol namedTypeSymbol,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;

namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Data;
namespace Aspid.FastTools.Generators.ProfilerMarkers.Data;

public readonly struct MarkerCallMember(
IMethodSymbol methodSymbol,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;

namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Data;
namespace Aspid.FastTools.Generators.ProfilerMarkers.Data;

public readonly struct MarkerCallType(
ISymbol symbol,
INamedTypeSymbol symbol,
ImmutableArray<MarkerCall> markerCalls)
{
public readonly ISymbol Symbol = symbol;
public readonly INamedTypeSymbol Symbol = symbol;
public readonly ImmutableArray<MarkerCall> MarkerCalls = markerCalls;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using UnityFastToolsGenerators.Generators.ProfilerMarkers.Data;
using UnityFastToolsGenerators.Generators.ProfilerMarkers.Bodies;
using Aspid.FastTools.Generators.ProfilerMarkers.Data;
using Aspid.FastTools.Generators.ProfilerMarkers.Bodies;

namespace UnityFastToolsGenerators.Generators.ProfilerMarkers;
namespace Aspid.FastTools.Generators.ProfilerMarkers;

[Generator(LanguageNames.CSharp)]
public class ProfilerMarkersGenerator : IIncrementalGenerator
Expand Down
11 changes: 11 additions & 0 deletions Aspid.FastTools.Generators/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project>

<Target Name="CopyToUnity" AfterTargets="Build" Condition="'$(IsRoslynComponent)' == 'true'">
<PropertyGroup>
<_UnityDestination>$(MSBuildThisFileDirectory)../Aspid.FastTools/Assets/Plugins/Aspid/FastTools/</_UnityDestination>
</PropertyGroup>
<MakeDir Directories="$(_UnityDestination)" />
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(_UnityDestination)" SkipUnchangedFiles="true" />
</Target>

</Project>
File renamed without changes.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

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

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading