{"id":23704979,"url":"https://github.com/skarllot/sourcegenerators","last_synced_at":"2026-04-02T18:32:30.013Z","repository":{"id":228222786,"uuid":"729958299","full_name":"skarllot/SourceGenerators","owner":"skarllot","description":"Provides utility functions and helpers to aid in writing source files for source generators using high-performance writer and string interpolations","archived":false,"fork":false,"pushed_at":"2026-03-24T12:39:54.000Z","size":4187,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-25T15:07:46.730Z","etag":null,"topics":["codewriter","generator","interpolation","performance","source","span","template"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skarllot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["skarllot"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2023-12-10T21:33:54.000Z","updated_at":"2026-03-24T12:39:56.000Z","dependencies_parsed_at":"2024-03-17T18:31:45.094Z","dependency_job_id":"6c424547-394d-4516-980f-5abf3c6f705a","html_url":"https://github.com/skarllot/SourceGenerators","commit_stats":null,"previous_names":["skarllot/sourcegenerators"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/skarllot/SourceGenerators","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarllot%2FSourceGenerators","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarllot%2FSourceGenerators/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarllot%2FSourceGenerators/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarllot%2FSourceGenerators/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skarllot","download_url":"https://codeload.github.com/skarllot/SourceGenerators/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skarllot%2FSourceGenerators/sbom","scorecard":{"id":910283,"data":{"date":"2025-08-19T17:39:39Z","repo":{"name":"github.com/skarllot/SourceGenerators","commit":"b4f3b6be6b2162b01c3c0dedc1422bb09c90db66"},"scorecard":{"version":"v5.2.1","commit":"ab2f6e92482462fe66246d9e32f642855a691dc1"},"score":8.7,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#maintained"}},{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#code-review"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: RenovateBot: .github/renovate.json:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#dependency-update-tool"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#security-policy"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:  18 out of  18 GitHub-owned GitHubAction dependencies pinned","Info:   8 out of   8 third-party GitHubAction dependencies pinned","Info:   3 out of   3 nugetCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:33","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:34","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/create-tag.yml:19","Info: topLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:25","Info: topLevel 'contents' permission set to 'read': .github/workflows/create-tag.yml:12","Info: topLevel 'contents' permission set to 'read': .github/workflows/dependency-review.yml:13","Info: topLevel 'contents' permission set to 'read': .github/workflows/dotnet.yml:18","Info: topLevel 'contents' permission set to 'read': .github/workflows/package.yml:13","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:18"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#token-permissions"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#vulnerabilities"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#cii-best-practices"}},{"name":"SAST","score":8,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 20 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#sast"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#license"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/package.yml:16"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#packaging"}},{"name":"Contributors","score":0,"reason":"project has 0 contributing companies or organizations -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#contributors"}},{"name":"Branch-Protection","score":8,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'","Info: 'stale review dismissal' is required to merge on branch 'main'","Warn: required approving review count is 1 on branch 'main'","Info: codeowner review is required on branch 'main'","Info: 'last push approval' is required to merge on branch 'main'","Info: 'up-to-date branches' is required to merge on branch 'main'","Info: status check found to merge onto on branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#branch-protection"}},{"name":"CI-Tests","score":10,"reason":"30 out of 30 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/ab2f6e92482462fe66246d9e32f642855a691dc1/docs/checks.md#ci-tests"}}]},"last_synced_at":"2025-08-24T18:51:41.948Z","repository_id":228222786,"created_at":"2025-08-24T18:51:41.948Z","updated_at":"2025-08-24T18:51:41.948Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31312917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codewriter","generator","interpolation","performance","source","span","template"],"created_at":"2024-12-30T14:06:52.098Z","updated_at":"2026-04-02T18:32:30.005Z","avatar_url":"https://github.com/skarllot.png","language":"C#","readme":"\u003cdiv style=\"text-align: center;\"\u003e\n  \u003cimg src=\"logos/banner-12x4.png\" alt=\"SourceGenerators Logo\" height=\"256\" style=\"border-radius: 15px;\" /\u003e\n\u003c/div\u003e\n\n\u003ch1 style=\"text-align: center;\"\u003eSourceGenerators\u003c/h1\u003e\n\n\u003cdiv style=\"text-align: center;\"\u003e\n\n[![Build status](https://github.com/skarllot/SourceGenerators/actions/workflows/dotnet.yml/badge.svg?branch=main)](https://github.com/skarllot/SourceGenerators/actions)\n[![codecov](https://codecov.io/gh/skarllot/SourceGenerators/graph/badge.svg?token=LS2ZQG4BAM)](https://codecov.io/gh/skarllot/SourceGenerators)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/skarllot/SourceGenerators/badge)](https://securityscorecards.dev/viewer/?uri=github.com/skarllot/SourceGenerators)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/skarllot/SourceGenerators/main/LICENSE)\n\n\u003c/div\u003e\n\n_Provides utility functions and helpers to aid in writing source files for source generators using high-performance writer and string interpolations_\n\n[🏃 Quickstart](#quickstart) \u0026nbsp; | \u0026nbsp; [📗 Guide](#guide) \u0026nbsp; | \u0026nbsp; [📦 NuGet](#nuget-packages)\n\n\u003chr /\u003e\n\nA high-performance source text writer for .NET incremental source generators. Write generated source code using plain\nstrings or C# string interpolations with automatic indentation support.\n\n## NuGet Packages\n* [![NuGet](https://img.shields.io/nuget/v/Raiqub.Generators.InterpolationCodeWriter?label=\u0026logo=nuget\u0026style=flat-square)![NuGet](https://img.shields.io/nuget/dt/Raiqub.Generators.InterpolationCodeWriter?label=\u0026style=flat-square)](https://www.nuget.org/packages/Raiqub.Generators.InterpolationCodeWriter/) **Raiqub.Generators.InterpolationCodeWriter**: provides a compiled library with `SourceTextWriter` for writing source code\n* [![NuGet](https://img.shields.io/nuget/v/Raiqub.Generators.InterpolationCodeWriter.CSharp?label=\u0026logo=nuget\u0026style=flat-square)![NuGet](https://img.shields.io/nuget/dt/Raiqub.Generators.InterpolationCodeWriter.CSharp?label=\u0026style=flat-square)](https://www.nuget.org/packages/Raiqub.Generators.InterpolationCodeWriter.CSharp/) **Raiqub.Generators.InterpolationCodeWriter.CSharp**: provides a compiled library with `CodeWriterDispatcher` and extensions for Roslyn source generators\n* [![NuGet](https://img.shields.io/nuget/v/Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources?label=\u0026logo=nuget\u0026style=flat-square)![NuGet](https://img.shields.io/nuget/dt/Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources?label=\u0026style=flat-square)](https://www.nuget.org/packages/Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources/) **Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources**: provides source files that are embedded into your project (no runtime dependency)\n\n## Compatibility\n\nThe compiled libraries target .NET Standard 2.0, .NET 8, and .NET 10. The source files package requires at least the\n.NET 6.0 SDK, but you can target earlier frameworks.\n\n## Quickstart\n\nAdd the source files package to your source generator project:\n\n```shell\ndotnet add package Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources\n```\n\nThen implement the `ICodeWriter\u003cT\u003e` interface to define your code writer:\n\n```csharp\npublic class MyWriter : ICodeWriter\u003cMyModel\u003e\n{\n    public bool CanGenerateFor(MyModel model) =\u003e model.Properties.Count \u003e 0;\n\n    public string GetFileName(MyModel model) =\u003e $\"{model.Namespace ?? \"_\"}.{model.Name}Extensions.g.cs\";\n\n    public void Write(SourceTextWriter writer, MyModel model)\n    {\n        writer.WriteLine($\"namespace {model.Namespace};\");\n        writer.WriteLine();\n        writer.WriteLine($\"public static partial class {model.Name}Extensions\");\n        writer.WriteLine(\"{\");\n        writer.PushIndent();\n\n        // Write members using string interpolation...\n\n        writer.PopIndent();\n        writer.WriteLine(\"}\");\n    }\n}\n```\n\n## Guide\n\n### SourceTextWriter\n\n`SourceTextWriter` is a high-performance text writer built on `StringBuilder` with automatic indentation support. It accepts plain strings and C# string interpolations through a custom `InterpolatedStringHandler`.\n\n```csharp\nvar writer = new SourceTextWriter();\n\nwriter.WriteLine(\"using System;\");\nwriter.WriteLine();\nwriter.WriteLine($\"namespace {ns};\");\nwriter.WriteLine();\nwriter.WriteLine($\"public class {className}\");\nwriter.WriteLine(\"{\");\nwriter.PushIndent();\nwriter.WriteLine($\"public string Name {{ get; set; }}\");\nwriter.PopIndent();\nwriter.WriteLine(\"}\");\n\nstring result = writer.ToString();\n```\n\nKey features:\n- **Automatic indentation**: Use `PushIndent()` / `PopIndent()` to manage indentation levels (4 spaces per level by default)\n- **String interpolation support**: Write code using `$\"...\"` syntax directly\n- **Culture-invariant formatting**: Numbers and other values are formatted using `InvariantCulture` by default\n- **Configurable**: Customize line endings, indentation size, and format provider\n\n### TextSegment\n\n`TextSegment` is an [interpolated string handler](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler) that captures the parts of an interpolated string for later use. It lets you compose reusable text fragments and embed them directly inside a `writer.Write($\"...\")` call.\n\n**Direct assignment** from an interpolated string:\n\n```csharp\nTextSegment typeName = $\"{namespaceName}.{className}\";\n\nwriter.WriteLine($\"// Generated type: {typeName}\");\n```\n\n**Returning segments from helper methods** keeps complex formatting out of the main writer loop:\n\n```csharp\nprivate static TextSegment FormatTypeRef(string ns, string name) =\u003e\n    $\"{ns}.{name}\";\n\n// Segments are embedded as holes — no intermediate string allocation\nwriter.WriteLine($\"[global::{FormatTypeRef(\"System\", \"Serializable\")}]\");\nwriter.WriteLine($\"public partial class {className}\");\n```\n\n**`TextSegment.Create`** provides extra options such as appending a line terminator or supplying a custom `IFormatProvider`:\n\n```csharp\n// Append a newline after the segment is written\nTextSegment line = TextSegment.Create($\"public {returnType} {methodName}();\", appendLine: true);\nline.WriteTo(writer);\n```\n\n### ICodeWriter / ICodeWriter\u0026lt;T\u0026gt;\n\n`ICodeWriter` defines a stateless code writer that generates source code. `ICodeWriter\u003cT\u003e` extends it with model-based generation:\n\n- `CanGenerateFor(T model)` - determines if code should be generated for the given model\n- `GetFileName(T model)` - returns the file name for the generated source\n- `Write(SourceTextWriter writer, T model)` - writes the source code using the provided writer and model\n\nImplementations should be stateless to ensure thread-safety in source generator contexts.\n\n### CodeWriterDispatcher\n\n`CodeWriterDispatcher\u003cT\u003e` dispatches source generation across multiple code writers. It is stateless and safe to store as a static field:\n\n```csharp\nprivate static readonly CodeWriterDispatcher\u003cMyModel\u003e s_dispatcher =\n    new([new MyWriter1(), new MyWriter2()]);\n```\n\nThen call `GenerateSources` to generate source files using the `SourceProductionContext`:\n\n```csharp\nprivate static void Emit(\n    SourceProductionContext context,\n    ImmutableArray\u003cMyModel\u003e types)\n{\n    s_dispatcher.GenerateSources(types, context);\n}\n```\n\nAn optional exception handler can be provided to report diagnostics instead of throwing:\n\n```csharp\nprivate static readonly CodeWriterDispatcher\u003cMyModel\u003e s_dispatcher =\n    new(\n        (ex, model) =\u003e Diagnostic.Create(...),\n        new MyWriter1(), new MyWriter2());\n```\n\n## Advanced Configuration\n\n### Disabling Built-in Polyfills\n\nThe `CSharp.Sources` package embeds polyfill types (such as `SpanExtensions`, `SpanLineEnumerator`, and `StringBuilderMemory`) to support targeting .NET Standard 2.0. If your project already provides these types — for example, via the [PolyFill](https://www.nuget.org/packages/PolyFill) library — you can suppress the embedded polyfills to avoid duplicate type definition errors.\n\nAdd the `NO_RAIQUB_SOURCEGENERATORS_POLYFILL` compiler constant to your project file:\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cDefineConstants\u003e$(DefineConstants);NO_RAIQUB_SOURCEGENERATORS_POLYFILL\u003c/DefineConstants\u003e\n\u003c/PropertyGroup\u003e\n```\n\nThis flag has no effect on the compiled library packages (`InterpolationCodeWriter` and `InterpolationCodeWriter.CSharp`).\n\n## Contributing\n\nIf something is not working for you or if you think that the source file\nshould change, feel free to create an issue or Pull Request.\nI will be happy to discuss and potentially integrate your ideas!\n\n## License\n\nSee the [LICENSE](./LICENSE) file for details.\n","funding_links":["https://github.com/sponsors/skarllot"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskarllot%2Fsourcegenerators","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskarllot%2Fsourcegenerators","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskarllot%2Fsourcegenerators/lists"}