From 8b39986ac2032839fb6318d72312f4cead458170 Mon Sep 17 00:00:00 2001 From: Igor Sinicyn Date: Thu, 20 Aug 2026 21:44:55 +0300 Subject: [PATCH] ScaffoldCS.Templates --- .editorconfig | 7 + CodeMe.ScaffoldCS.sln.DotSettings | 6 + CodeMe.ScaffoldCS.slnx | 2 + Directory.Packages.props | 3 +- README.md | 30 + docs/TemplateRender.md | 9 + .../CodeMe.ScaffoldCS.Templates.csproj | 14 + .../Infrastructure/CharSpanExtensions.cs | 20 + .../Internals/AmbientTemplate.cs | 16 + .../Internals/ConditionBranch.cs | 9 + .../Internals/IControlTemplateSymbol.cs | 5 + .../Internals/IScopedTemplateValue.cs | 6 + .../Internals/ITemplatePart.cs | 24 + .../Internals/ITemplateSymbol.cs | 6 + .../Output/CurrentLineHandlingMode.cs | 12 + .../Output/CurrentLineState.cs | 14 + .../Output/IndentationFormat.cs | 14 + .../Output/NewLineFormat.cs | 12 + .../Output/TemplateTextWriter.cs | 438 ++++++++ .../Output/TemplateTextWriterOptions.cs | 22 + .../Render/ClearLineSymbol.cs | 8 + .../Render/CollectionRenderExtensions.cs | 26 + .../Render/CollectionRenderOptions.cs | 21 + .../Render/CollectionSymbol.cs | 45 + .../Render/ConditionBranchSymbol.cs | 44 + .../Render/ConditionSymbol`1.cs | 17 + .../Render/ConditionSymbol`2.cs | 22 + .../Render/Conditions.cs | 37 + .../Render/IfFalseTemplatePart.cs | 68 ++ .../Render/IfTrueTemplatePart.cs | 68 ++ .../Render/LineHandlingSymbol.cs | 9 + .../Render/Symbols.cs | 62 ++ .../Render/SymbolsCS.cs | 55 + .../Render/ValueSymbol.cs | 19 + .../Template.Context.cs | 115 ++ .../Template.TestAccessor.cs | 21 + .../Template.Write.cs | 319 ++++++ src/CodeMe.ScaffoldCS.Templates/Template.cs | 56 + .../TemplatePart.cs | 56 + .../packages.lock.json | 13 + .../CodeMe.ScaffoldCS.csproj | 4 + src/CodeMe.ScaffoldCS/README.md | 2 +- src/CodeMe.ScaffoldCS/packages.lock.json | 15 +- ...deMe.ScaffoldCS.Templates.UnitTests.csproj | 7 + .../Infrastructure/Models/Class.cs | 3 + .../Infrastructure/Models/Property.cs | 3 + .../Infrastructure/TemplateTestExtensions.cs | 30 + .../TemplateTextWriterTestExtensions.cs | 75 ++ .../Output/TemplateTextWriterTests.cs | 997 ++++++++++++++++++ .../TemplateTests.cs | 350 ++++++ .../packages.lock.json | 154 +++ .../TemplateTests.cs | 11 + .../packages.lock.json | 105 +- 53 files changed, 3461 insertions(+), 45 deletions(-) create mode 100644 docs/TemplateRender.md create mode 100644 src/CodeMe.ScaffoldCS.Templates/CodeMe.ScaffoldCS.Templates.csproj create mode 100644 src/CodeMe.ScaffoldCS.Templates/Infrastructure/CharSpanExtensions.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Internals/AmbientTemplate.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Internals/ConditionBranch.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Internals/IControlTemplateSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Internals/IScopedTemplateValue.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Internals/ITemplatePart.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Internals/ITemplateSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Output/CurrentLineHandlingMode.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Output/CurrentLineState.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Output/IndentationFormat.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Output/NewLineFormat.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Output/TemplateTextWriter.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Output/TemplateTextWriterOptions.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/ClearLineSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/CollectionRenderExtensions.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/CollectionRenderOptions.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/CollectionSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/ConditionBranchSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/ConditionSymbol`1.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/ConditionSymbol`2.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/Conditions.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/IfFalseTemplatePart.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/IfTrueTemplatePart.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/LineHandlingSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/Symbols.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/SymbolsCS.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Render/ValueSymbol.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Template.Context.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Template.TestAccessor.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Template.Write.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/Template.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/TemplatePart.cs create mode 100644 src/CodeMe.ScaffoldCS.Templates/packages.lock.json create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/CodeMe.ScaffoldCS.Templates.UnitTests.csproj create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/Infrastructure/Models/Class.cs create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/Infrastructure/Models/Property.cs create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/Infrastructure/TemplateTestExtensions.cs create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/Infrastructure/TemplateTextWriterTestExtensions.cs create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/Output/TemplateTextWriterTests.cs create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/TemplateTests.cs create mode 100644 tests/CodeMe.ScaffoldCS.Templates.UnitTests/packages.lock.json create mode 100644 tests/CodeMe.ScaffoldCS.UnitTests/TemplateTests.cs diff --git a/.editorconfig b/.editorconfig index 1e10e86..2ed42e2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,18 +1,25 @@ [*.cs] csharp_style_prefer_primary_constructors = false dotnet_style_prefer_collection_expression = false +csharp_indent_braces = false +csharp_new_line_before_open_brace = all # ReSharper properties resharper_align_multiline_binary_expressions_chain = false resharper_braces_for_foreach = required resharper_braces_for_ifelse = required resharper_braces_for_while = required +resharper_braces_redundant = true resharper_csharp_keep_blank_lines_in_code = 1 resharper_csharp_keep_blank_lines_in_declarations = 1 resharper_csharp_wrap_before_binary_opsign = true resharper_csharp_wrap_parameters_style = chop_if_long +resharper_max_attribute_length_for_same_line = 60 resharper_method_or_operator_body = expression_body resharper_place_single_method_argument_lambda_on_same_line = false resharper_wrap_after_declaration_lpar = true resharper_wrap_after_invocation_lpar = true resharper_wrap_chained_binary_expressions = chop_if_long + +# Microsoft .NET properties +csharp_prefer_braces = true:none diff --git a/CodeMe.ScaffoldCS.sln.DotSettings b/CodeMe.ScaffoldCS.sln.DotSettings index ed3bda4..8d9d380 100644 --- a/CodeMe.ScaffoldCS.sln.DotSettings +++ b/CodeMe.ScaffoldCS.sln.DotSettings @@ -5,9 +5,15 @@ True <?xml version="1.0" encoding="utf-16"?><Profile name="Cleanup on Save"><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeAccessors="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeEmptyString="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" ArrangeBraces="True" /><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><XMLReformatCode>True</XMLReformatCode><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><CSharpReformatComments>True</CSharpReformatComments><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><RemoveCodeRedundancies>True</RemoveCodeRedundancies></Profile> Required + DO_NOT_CHANGE + False ZeroIndent False <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb" /></Policy> + True + True + True + True True \ No newline at end of file diff --git a/CodeMe.ScaffoldCS.slnx b/CodeMe.ScaffoldCS.slnx index 76332cd..ea37f3d 100644 --- a/CodeMe.ScaffoldCS.slnx +++ b/CodeMe.ScaffoldCS.slnx @@ -7,9 +7,11 @@ + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 6d54c12..b889258 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,7 +4,8 @@ + - + \ No newline at end of file diff --git a/README.md b/README.md index 1c2b6d1..ad8bada 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,32 @@ # CodeMe.ScaffoldCS Scaffolding framework inspired by CodegenCS + +# Template issues + +Have a good scenarios: +* Last line behavior (last line is empty) + * May be fixed if we keep endline in the current line and trim endline on close + (last line behavior) + * Will also fix inconsistency with delayed flush on MacOS ('\r' separator) +* Consider to split Template and advanced rendering logic. The goal is to have api that allows to add third-party rendering customisation +* Add api for column-level padding. Func to PaddedTemplatePart? + * Need both options. +* Split template / text writer options + +Waits for grooming: +* Value handling customizations. Interceptors? + * We need a really good scenario for it. With naive implementation interceptors will slow down each write operation so lets keep it on hold. +* Review behaviors for `// {SummaryWithNewLineAtTheEnd} something` render scenario. Something like NextLineIndentation or EnforceIndentation() maybe? +* Shall we append indentation on whitespace-only lines? + * Do we need "append indentation on empty lines" option? +* Add support for alignment arg for multiline values? + * Need a good scenario for this. We have auto-indentation for this +* Multiline value nahdling. + * Add option for Template to disable multiline indentation. Add .RenderLiteral() / .RenderMultiline() + * Or just add .RenderLiteral() and no option + +Delayed: +* Docs are missing +* No XML comments + +# Metamodel issues \ No newline at end of file diff --git a/docs/TemplateRender.md b/docs/TemplateRender.md new file mode 100644 index 0000000..294acd1 --- /dev/null +++ b/docs/TemplateRender.md @@ -0,0 +1,9 @@ +# Summary + +Render logic is based on c# [interpolated dtring handler](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/performance/interpolated-string-handler) feature. + +Also, we use ambient template context (based on [ScopedAsyncLocal<T>](https://github.com/ig-sinicyn/CodeMe/tree/master/docs/Basics/AsyncLocal)) to ease passing of the current writer to the nested parts. + +We do support conditional evaluation by IIF/IF-ELSE-ENDIF macro. + +We do support conditional line trim by RL (RemoveLine macro) diff --git a/src/CodeMe.ScaffoldCS.Templates/CodeMe.ScaffoldCS.Templates.csproj b/src/CodeMe.ScaffoldCS.Templates/CodeMe.ScaffoldCS.Templates.csproj new file mode 100644 index 0000000..50c7988 --- /dev/null +++ b/src/CodeMe.ScaffoldCS.Templates/CodeMe.ScaffoldCS.Templates.csproj @@ -0,0 +1,14 @@ + + + + + net10.0 + Template render engine inspired by CodegenCS + Scaffolld;Template;Codegen;Code Generation + + + + + + + diff --git a/src/CodeMe.ScaffoldCS.Templates/Infrastructure/CharSpanExtensions.cs b/src/CodeMe.ScaffoldCS.Templates/Infrastructure/CharSpanExtensions.cs new file mode 100644 index 0000000..c29934b --- /dev/null +++ b/src/CodeMe.ScaffoldCS.Templates/Infrastructure/CharSpanExtensions.cs @@ -0,0 +1,20 @@ +namespace CodeMe.ScaffoldCS.Templates.Infrastructure; + +internal static class CharSpanExtensions +{ + public static int NextIndexOfAny( + this ReadOnlySpan span, + int startIndex, + char value0, + char value1) + { + var index = span[startIndex..].IndexOfAny(value0, value1); + return index < 0 ? index : startIndex + index; + } + + public static bool IsMultiline(this ReadOnlySpan span) + { + var index = span.IndexOfAny('\r', '\n'); + return index >= 0; + } +} \ No newline at end of file diff --git a/src/CodeMe.ScaffoldCS.Templates/Internals/AmbientTemplate.cs b/src/CodeMe.ScaffoldCS.Templates/Internals/AmbientTemplate.cs new file mode 100644 index 0000000..6bb04d6 --- /dev/null +++ b/src/CodeMe.ScaffoldCS.Templates/Internals/AmbientTemplate.cs @@ -0,0 +1,16 @@ +using CodeMe.Basics.Threading; + +namespace CodeMe.ScaffoldCS.Templates.Internals; + +public static class AmbientTemplate +{ + private static readonly ScopedAsyncLocal