iTranslated by AI
Implementing Custom Directives with Roslyn
Prequel
In a Unity environment, the #: directive used for .NET 10 single-file execution causes a compilation error. (Interestingly, #! at the beginning of a file works just fine.)
Even if you move the test scripts themselves to folders like Tests~ which aren't imported by Unity, the problem remains that references are difficult because Unity projects write all .csproj files to the root. Furthermore, .csproj files generated by Unity might not be buildable in VS Code.
Also, in Visual Studio Insiders, IntelliSense doesn't work for single-file execution .cs files. However, it does work in VS Code, even if it (might) not be able to build them.
In short, it's a messy transition period, so if a class has no dependency on Unity, why not just import it directly! So, I created a custom preprocessor directive-like syntax using a Source Generator.
Usage
#:package FUnit@*
#:package FUnit.Directives@*
// 👇 Referencing Directives allows using //:funit:
//:funit:include ../Runtime/MyClass.cs
return await FUnit.RunAsync(args, describe =>
{
describe("Test", it =>
{
it("should work", () =>
{
// Since the source generator outputs it as if it read and generated the file normally,
// you can test even internal members!
Must.BeEqual(310, MyClass.Method());
// ~~~~~~~~~~~~~~ Type and method included from MyClass.cs
})
});
});
include Directive
//:funit:include <target_file.cs> *Must be at the beginning of the line
It treats the argument (?) as a relative path from the .cs file, simply reads it with System.IO.File, and outputs it directly as "generated source code" from the Source Generator.
Whether it's to avoid circular references in the project, because it's not referenced at all, or across any other boundaries, you can quickly import specified files.
Notes
Roslyn has an error diagnostic called RS1035, but I'm building it as if it weren't there.
When implementing the directive, I choseISourceGeneratorbecauseIIncrementalGeneratorhas difficulty detecting code deletion. Since it's only executed once for "single-file execution," I don't think it will be a problem.
It seems to be an error limited to
IIncrementalGenerator. In other words,includeis legal even in C#!
Besides that, while I perform syntax checks and file existence checks, I don't verify if the file being loaded is appropriate at all, so if you load the file itself, everything becomes ambiguous. (Including the same file multiple times is fine.)
👇 Original source (Everything becomes ambiguous)

👇 Generated source (Duplicate names, etc.)

Conclusion
There was a request on GitHub to add an #:item directive, so I feel like include support will be added eventually. As it stands now, it feels like it's just one step away from being complete!
Please use this as a stopgap until the official support is available.
That's all. Thank you.
Discussion