{"id":14915378,"url":"https://github.com/datacute/EmbeddedResourcePropertyGenerator","last_synced_at":"2025-09-23T07:32:18.962Z","repository":{"id":256929260,"uuid":"856788926","full_name":"datacute/EmbeddedResourcePropertyGenerator","owner":"datacute","description":"Generates properties for embedded resources in a project.","archived":false,"fork":false,"pushed_at":"2025-08-03T09:34:37.000Z","size":166,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-29T02:43:23.441Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/Datacute.EmbeddedResourcePropertyGenerator","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/datacute.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-09-13T07:55:36.000Z","updated_at":"2025-08-03T09:31:15.000Z","dependencies_parsed_at":"2024-09-14T00:13:13.921Z","dependency_job_id":"3580cd6c-a3e1-410e-976b-fce93191bb98","html_url":"https://github.com/datacute/EmbeddedResourcePropertyGenerator","commit_stats":null,"previous_names":["datacute/embeddedresourcepropertygenerator"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/datacute/EmbeddedResourcePropertyGenerator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacute%2FEmbeddedResourcePropertyGenerator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacute%2FEmbeddedResourcePropertyGenerator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacute%2FEmbeddedResourcePropertyGenerator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacute%2FEmbeddedResourcePropertyGenerator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datacute","download_url":"https://codeload.github.com/datacute/EmbeddedResourcePropertyGenerator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacute%2FEmbeddedResourcePropertyGenerator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275599759,"owners_count":25493969,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-17T02:00:09.119Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-09-22T23:01:41.851Z","updated_at":"2025-09-23T07:32:18.953Z","avatar_url":"https://github.com/datacute.png","language":"C#","funding_links":[],"categories":["Contributors Welcome for those"],"sub_categories":["1. [ThisAssembly](https://ignatandrei.github.io/RSCG_Examples/v2/docs/ThisAssembly) , in the [EnhancementProject](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementproject) category"],"readme":"[![Build](https://github.com/datacute/EmbeddedResourcePropertyGenerator/actions/workflows/ci.yml/badge.svg)](https://github.com/datacute/EmbeddedResourcePropertyGenerator/actions/workflows/ci.yml)\n\n# Embedded Resource Property Generator\nThe Embedded Resource Property Generator is an Incremental Source Generator\nwhich generates properties for text file embedded resources in a\nproject, in a similar way to how properties are generated from the string\nresources in .resx files.\n\nBy adding the `[EmbeddedResourceProperties]` attribute to a partial class,\nand specifying the filename extension and folder path to search, the\nsource generator will add a property to the class for each matching\nembedded resource file. Accessing the property will return the text\ncontent of the embedded resource file.\n\n## Why not just use a resx file?\nThe use case for this project is when you have a large number of text\nfiles that you want to embed in your project, such as SQL queries, and you\nwish to  develop these files with an external editor that supports syntax\nhighlighting, execution, debugging, and other features.\n\nWhile resx files do support including files, doing so requires either\nthe use of another custom editor, or manipulating the xml of the resx\nfile directly.\n\n## What's wrong with just using Assembly.GetManifestResourceStream?\nThe purpose of providing properties to access the text, is to aid the\ndeveloper by generating doc-comments for the properties, showing the first\nfew lines of the file.\n\n```csharp\n/// \u003csummary\u003eText value of the Embedded Resource: GoodIndenting.cypher\u003c/summary\u003e\n/// \u003cvalue\u003e\n/// \u003ccode\u003e\n/// MERGE (n)\n///   ON CREATE SET n.prop = 0\n/// MERGE (a:A)-[:T]-(b:B)\n///   ON CREATE SET a.name = 'me'\n///   ON MATCH SET b.name = 'you'\n/// RETURN a.prop\n/// \u003c/code\u003e\n/// \u003c/value\u003e\n/// \u003cremarks\u003e\n/// The value is read from the embedded resource on first access.\n/// \u003c/remarks\u003e\npublic static string GoodIndenting =\u003e \n  // Generated code to read the resource \"Namespace.ClassName.GoodIndenting.cypher\";\n```\n\nThe full names of the embedded resources are also generated, and no longer\nneed to be supplied by the developer, making it easy to move the location\nof the resource files to another directory, without needing to find and\nfix all the references to the resource names.\n\n## Usage\n\n1. Add the [Datacute.EmbeddedResourcePropertyGenerator NuGet package](https://www.nuget.org/packages/Datacute.EmbeddedResourcePropertyGenerator)\nto your project.\n    ```bash\n    dotnet add package Datacute.EmbeddedResourcePropertyGenerator\n    ```\n2. Add a directory to your project to group the files you want to embed.\n3. Add text files to your project, in that directory, and set their Build\n   Action to `EmbeddedResource`.\n    ```text\n    \u003e SqlQueries\n        SelectAll.sql\n        SelectById.sql\n    Program.cs\n    ```\n    ```xml\n      \u003cItemGroup\u003e\n        \u003cEmbeddedResource Include=\"SqlQueries\\SelectAll.sql\" /\u003e\n        \u003cEmbeddedResource Include=\"SqlQueries\\SelectById.sql\"/\u003e\n      \u003c/ItemGroup\u003e\n    ```\n4. Add a partial class to your code.\n5. Include a using statement to reference the `Datacute.EmbeddedResourcePropertyGenerator` namespace.\n6. Put the attribute `[EmbeddedResourceProperties]` on the class.\n7. Specify the extension and folder path to search for embedded resources.\n8. Use the properties generated on the partial class.\n    ```csharp\n    using Datacute.EmbeddedResourcePropertyGenerator;\n    \n    [EmbeddedResourceProperties(\".sql\", \"SqlQueries\")]\n    public static partial class SqlQuery;\n    \n    class Program\n    {\n        static void Main()\n        {\n            Console.WriteLine(SqlQuery.SelectAll);\n        }\n    }\n    ``` \n\nWithin your .csproj file, you can alter the `PackageReference` to include `PrivateAssets=\"all\" ExcludeAssets=\"runtime\"`\nThis stops projects that reference this one from also getting a reference to this package, and stops the dll files\nfrom being copied to your build output.\n\n## Localisation and External Overrides\nLocalisation and External Overrides are not supported. If you need these\nfeatures, consider using a resx file instead.\n\n## Non-text File Types\nThis project expects text files so that it can generate properties that\nare strings. It currently expects UTF-8 encoded files.\n\nIf you need to embed other types of files, use the \n`Assembly.GetManifestResourceStream` method directly.\n\n## Extending the Behaviour\nThe generated code includes a private nested class `EmbeddedResource` containing:\n\n| Method or Class | Purpose |\n|-----------------|---------|\n| `Read(string resourceName)` | Method for reading embedded resources |\n| `BackingField` | Nested class caching the property values |\n| `ResourceName` | Nested class holding the resource names |\n\nThe implementation supports including two ***partial methods*** that can\nbe implemented in the same partial class as the generated properties.\n\nIf the partial methods are not implemented, the calls to them are removed, \nand the code effectively reduces to:\n\n```csharp\npublic static string Example =\u003e\n        EmbeddedResource.BackingField.Example ??= EmbeddedResource.Read(EmbeddedResource.ResourceName.Example);\n```\n\n### Partial methods:\n- `ReadEmbeddedResourceValue` - This method is called to allow the class\n  to override how the value representing the content of the embedded\n  resource is obtained. If the `backingField` parameter is null when this\n  method ends, the default implementation will be used.\n- `AlterEmbeddedResourceReturnValue` - This method is called after the\n  text content has been read, and can be used to modify the text content\n  before it is returned. Altering the returned value does not affect the\n  value stored in the backing field.\n\n```csharp\n    [EmbeddedResourceProperties(\".sql\", \"SqlQueries\")]\n    public static partial class SqlQuery\n    {\n        static partial void ReadEmbeddedResourceValue(\n            ref string? backingField, \n            string resourceName, \n            string propertyName)\n        {\n            // This method is called before the default implementation.\n\n            // The default implementation only reads the resource\n            // if the backingField is null, so by setting it in this method,\n            // the default implementation can be bypassed.\n\n            // The backingField is a reference to a static field\n            // for the property, and will be null for the first call,\n            // but will retain the value for subsequent calls\n            // for the same property.\n\n            // Use custom logic to read the text content given the names\n            // of the resource, and of the property.\n            backingField ??= CustomReader(resourceName, propertyName);\n        }\n\n        static partial void AlterEmbeddedResourceReturnValue(\n            ref string value,\n            string resourceName,\n            string propertyName);\n        {\n            // The value parameter is a reference to a variable that \n            // will be returned as the value of the property.\n            \n            // Implement custom logic to alter the value.\n            value = CustomValueAlteringMethod(value, resourceName, propertyName);\n        }\n    }\n```\n\nThis is an example of the code generated for a property, showing how the partial methods are called:\n\n```csharp\n/// \u003csummary\u003eText value of the Embedded Resource: Example.txt\u003c/summary\u003e\n/// \u003cvalue\u003e\n/// \u003ccode\u003e\n/// This is the content of the Example.txt file.\n/// Only the first few lines are shown here.\n/// \u003c/code\u003e\n/// \u003c/value\u003e\n/// \u003cremarks\u003e\n/// The value is read from the embedded resource on first access.\n/// \u003c/remarks\u003e\npublic static string Example\n{\n    get\n    {\n        ReadEmbeddedResourceValue(ref EmbeddedResource.BackingField.Example, EmbeddedResource.ResourceName.Example, \"Example\");\n        var value = EmbeddedResource.BackingField.Example ??= EmbeddedResource.Read(EmbeddedResource.ResourceName.Example);\n        AlterEmbeddedResourceReturnValue(ref value, EmbeddedResource.ResourceName.Example, \"Example\");\n        return value;\n    }\n}\n```\n\n## Diagnostics\nThe source generator traces its behaviour using code based on https://github.com/datacute/LightweightTracing\n\nThe trace log can be appended to the generated source files by setting the `DiagnosticTraceLog`\nproperty to true.\n\n```csharp\n[EmbeddedResourceProperties(\".sql\", \"SqlQueries\", DiagnosticTraceLog = true)]\npublic static partial class SqlQuery;\n``` \n\n## Thanks\n\nThanks to Andrew Lock for his Series: [Creating a source generator](https://andrewlock.net/series/creating-a-source-generator/).\n\n## Future Enhancements\n- [ ] Add an option to leave out the Read method.\n  - It is now included in the generated code for each class,\n    but an implementation of the `ReadEmbeddedResourceValue` partial\n    method might make it unnecessary.\n- [ ] Support for alternative text encodings.\n  - Overriding `ReadEmbeddedResourceValue` is a technique that can be\n    used to read the text content of the embedded resource with a\n    different encoding, but the doc-comment will still be generated\n    expecting UTF-8.\n- [ ] Support for specifying the number of lines to include in the\n  doc-comment (including zero to exclude the code section).\n  - This is currently set to 10 lines.\n- [ ] Support generating text formatting methods.\n  - Call `CompositeFormat.Parse` on the loaded text, and additionally count\n    the number of format items, and generate a method that takes the\n    same number of arguments.\n  - Using a resx file is probably a better fit that adding this feature.\n- [ ] Support generating `ReadOnlySpan\u003cbyte\u003e` properties instead of `string`\n  - The decoding from utf-8 may not be needed.\n- [ ] Make use of the `field` keyword when C# 14 or above is used.\n  - See https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#the-field-keyword\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatacute%2FEmbeddedResourcePropertyGenerator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatacute%2FEmbeddedResourcePropertyGenerator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatacute%2FEmbeddedResourcePropertyGenerator/lists"}