Skip to content

feat: add file-based template attribute and utility method for whitespace handling#6

Merged
bmazzarol merged 3 commits into
mainfrom
feat/file-templating
Oct 25, 2025
Merged

feat: add file-based template attribute and utility method for whitespace handling#6
bmazzarol merged 3 commits into
mainfrom
feat/file-templating

Conversation

@bmazzarol

@bmazzarol bmazzarol commented Oct 25, 2025

Copy link
Copy Markdown
Owner
  • Introduced FileTemplateAttribute to support templates from external files.
  • Added RenderUtilities.ApplyExtraWhitespace for improved whitespace handling.
  • Enhanced internal generator setup to embed new utility and attribute source files.
  • Improved consistency in parameter type representation and tests.

Summary by CodeRabbit

  • New Features

    • External file-based templates with configuration-driven bindings
    • Centralized whitespace handling for consistent template output
    • Support for nested template calls
    • New sample template demonstrating parameter usage
  • Documentation

    • Added "File Templates" guide and navigation entry
  • Tests

    • Expanded coverage for nested templates and whitespace formatting
  • Chores

    • Minor documentation/markdown formatting tweaks and package version updates

…pace handling

- Introduced `FileTemplateAttribute` to support templates from external files.
- Added `RenderUtilities.ApplyExtraWhitespace` for improved whitespace handling.
- Enhanced internal generator setup to embed new utility and attribute source files.
- Improved consistency in parameter type representation and tests.
@bmazzarol bmazzarol self-assigned this Oct 25, 2025
@bmazzarol bmazzarol added the enhancement New feature or request label Oct 25, 2025
@coderabbitai

coderabbitai Bot commented Oct 25, 2025

Copy link
Copy Markdown

Warning

Rate limit exceeded

@bmazzarol has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 9 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b7f1e42 and 2b65799.

📒 Files selected for processing (2)
  • Cutout.Docs/articles/file-templates.md (1 hunks)
  • Cutout/TemplateSourceGenerator.cs (4 hunks)

Walkthrough

The PR adds file-based template support (new FileTemplateAttribute and .editorconfig binding), centralizes whitespace handling via RenderUtilities.ApplyExtraWhitespace, updates the source generator to combine attribute- and file-based templates, adjusts renderer emission, adds sample/template files, and updates numerous generated test snapshots (type-alias and whitespace changes).

Changes

Cohort / File(s) Summary
Docs & Config
CODE_OF_CONDUCT.md, Cutout.Docs/articles/file-templates.md, Cutout.Docs/toc.yml, Cutout.Sample/.editorconfig, Cutout/.editorconfig
Documentation and toc updated; new file-templates doc and toc entry; .editorconfig entries added for sample template method binding and embedding source files.
Sample files
Cutout.Sample/Cutout.Sample.csproj, Cutout.Sample/SampleTemplate.cs.liquid, Cutout.Sample/Examples.cs
Adds SampleTemplate.cs.liquid as AdditionalFiles, editorconfig binding to Cutout.Sample.Examples.Test4, and a [FileTemplate] example method Test4.
New attributes & utilities (source)
Cutout/FileTemplateAttribute.Source.cs, Cutout/TemplateAttribute.Source.cs, Cutout/RenderUtilities.Source.cs
Introduces FileTemplateAttribute, canonical TemplateAttribute source, and RenderUtilities with ApplyExtraWhitespace<T>.
Generator core & template plumbing
Cutout/TemplateSourceGenerator.cs, Cutout/TemplateSourceGenerator.TemplateMethodImpl.cs, Cutout/TemplateAttributeParts.cs, Cutout/TemplateSourceGenerator.TemplateAttribute.cs (removed)
Extends generator to discover templates from AdditionalFiles/.editorconfig and syntax; builds TemplateMethodDetails from files or attributes; emits both standard and whitespace-receiver variants; removes previously embedded TemplateAttribute artifact.
Renderer changes
Cutout/Renderer/Renderer.cs
Refactors write paths to use RenderUtilities.ApplyExtraWhitespace when whitespace receiver present; normalizes whitespace argument handling in call emission.
Cutout project & packaging
Cutout/Cutout.csproj, Parent.Directory.Packages.props
Adds conditional Pasted package/project analyzer references and includes **/*.Source.cs as AdditionalFiles; bumps Cutout package version and adds Pasted package version.
Tests: new/modified test sources
Cutout.Tests/CallStatementTests.cs, Cutout.Tests/.../Case5*, Cutout.Tests/SharedTests.Case1#*
Adds Case5 nested call test; adds verified snapshots for FileTemplateAttribute and RenderUtilities; removes parameterless TemplateAttribute ctor in snapshot.
Generated test verification updates (type alias + whitespace utility)
Cutout.Tests/.../*.g.verified.cs, Cutout.Tests/.../*.wsr.g.verified.cs (multiple files across CallStatementTests, ForStatementTests, IfStatementTests, TemplateTests, etc.)
Many verification files updated to use primitive aliases (Stringstring, Int32int, fully-qualified model types) and to replace manual newline/whitespace handling with Cutout.RenderUtilities.ApplyExtraWhitespace calls.
Test tooling / generator helpers
Cutout.Tests/Extensions/GeneratorDriverExtensions.cs
Expanded ignore predicate to also skip FileTemplateAttribute.g.cs and RenderUtilities.g.cs among generated results.

Sequence Diagram(s)

sequenceDiagram
    participant Tool as TemplateSourceGenerator
    participant Attr as Attribute Path
    participant File as File Path (.editorconfig / AdditionalFiles)
    participant Comb as Combiner
    participant Emit as EmitGeneratorOutput

    Note over Tool: post-initialization emits attribute & utility sources

    par Attribute-based discovery
        Tool->>Attr: Analyze syntax & semantics
        Attr->>Comb: BuildTemplateDetailsFromSyntax()
    and File-based discovery
        Tool->>File: Read AnalyzerConfig (template_method) & AdditionalText
        File->>Comb: BuildTemplateDetailsFromFile()
    end

    Comb->>Emit: Yield combined TemplateMethodDetails
    Emit->>Emit: Generate standard + wsr variants using RenderUtilities
Loading
sequenceDiagram
    participant RendererOld as Old inline handling
    participant RenderUtil as RenderUtilities.ApplyExtraWhitespace
    participant Builder as StringBuilder.Append

    rect rgb(250,240,240)
    Note over RendererOld: previous per-append newline checks
    RendererOld->>Builder: Append(value)
    RendererOld->>RendererOld: if contains newline -> Append(whitespace)
    end

    rect rgb(240,250,240)
    Note over RenderUtil: centralized handling
    RendererOld->>RenderUtil: ApplyExtraWhitespace(value, whitespace)
    RenderUtil->>Builder: Append(result)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus on:

  • Cutout/TemplateSourceGenerator.cs — file-discovery, .editorconfig parsing, method binding, and combined emission paths.
  • Cutout/Renderer/Renderer.cs — ensure ApplyExtraWhitespace usage preserves previous semantics for all cases.
  • Cutout/RenderUtilities.Source.cs — correctness for nulls, non-string types, and newline replacement behavior.
  • Test verification snapshots — sample a few changed .wsr.g.verified.cs files to confirm expected output differences.
  • Project file conditional references for Pasted and AdditionalFiles handling.

Possibly related PRs

Poem

🐇 A rabbit wrote a tiny line,

From file to template, threads align.
FileTemplate calls, editor config sings,
Whitespace tucked by RenderUtilities' wings,
Templates bloom — compiled, neat, and fine.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: add file-based template attribute and utility method for whitespace handling" directly aligns with the primary objectives and main changes in the changeset. The title accurately identifies the two key features being introduced: (1) FileTemplateAttribute for supporting templates sourced from external files, and (2) RenderUtilities.ApplyExtraWhitespace for improved whitespace handling in generated code. The title is concise, specific, and avoids vague terms—it clearly communicates the feature additions that form the core purpose of this PR. While the changeset also includes supporting changes like type consistency updates and test file modifications, the title appropriately focuses on the main user-facing features and enhancements, which is the expected level of detail for a PR title.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Oct 25, 2025

Copy link
Copy Markdown

Test Results

82 tests   82 ✅  5s ⏱️
 1 suites   0 💤
 1 files     0 ❌

Results for commit 2b65799.

♻️ This comment has been updated with latest results.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b88117c and 0f160ff.

📒 Files selected for processing (42)
  • CODE_OF_CONDUCT.md (1 hunks)
  • Cutout.Sample/.editorconfig (1 hunks)
  • Cutout.Sample/Cutout.Sample.csproj (1 hunks)
  • Cutout.Sample/Examples.cs (1 hunks)
  • Cutout.Sample/SampleTemplate.cs.liquid (1 hunks)
  • Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/CallStatementTests.cs (2 hunks)
  • Cutout.Tests/Extensions/GeneratorDriverExtensions.cs (1 hunks)
  • Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/ForStatementTests.Case2a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/ForStatementTests.Case2a#Test.Test.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/ForStatementTests.Case3a#Test.Test.wsr.g.verified.cs (2 hunks)
  • Cutout.Tests/IfStatementTests.Case1a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/IfStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/IfStatementTests.Case2a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/IfStatementTests.Case2a#Test.Test.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/IfStatementTests.Case3a#Test.Test.g.verified.cs (1 hunks)
  • Cutout.Tests/IfStatementTests.Case3a#Test.Test.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/SharedTests.Case1#FileTemplateAttribute.g.verified.cs (1 hunks)
  • Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (1 hunks)
  • Cutout.Tests/SharedTests.Case1#TemplateAttribute.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.wsr.g.verified.cs (1 hunks)
  • Cutout.Tests/TemplateTests.Case5a#Test.TestWithConstantTemplate.wsr.g.verified.cs (1 hunks)
  • Cutout/.editorconfig (1 hunks)
  • Cutout/Cutout.csproj (1 hunks)
  • Cutout/FileTemplateAttribute.Source.cs (1 hunks)
  • Cutout/RenderUtilities.Source.cs (1 hunks)
  • Cutout/Renderer/Renderer.cs (3 hunks)
  • Cutout/TemplateAttribute.Source.cs (1 hunks)
  • Cutout/TemplateAttributeParts.cs (1 hunks)
  • Cutout/TemplateSourceGenerator.TemplateAttribute.cs (0 hunks)
  • Cutout/TemplateSourceGenerator.TemplateMethodImpl.cs (2 hunks)
  • Cutout/TemplateSourceGenerator.cs (4 hunks)
  • Parent.Directory.Packages.props (1 hunks)
💤 Files with no reviewable changes (1)
  • Cutout/TemplateSourceGenerator.TemplateAttribute.cs
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-02T15:10:00.574Z
Learnt from: bmazzarol
PR: bmazzarol/Cutout#3
File: Cutout/Parser/Parser.cs:20-36
Timestamp: 2025-08-02T15:10:00.574Z
Learning: The Cutout Parser (Cutout/Parser/Parser.cs) is specifically designed for use in a source generator context, where it runs during compilation rather than at runtime. This context makes memory optimization concerns around thread-static contexts less relevant since source generators have limited lifespans during the build process.

Applied to files:

  • Cutout/TemplateSourceGenerator.cs
🧬 Code graph analysis (28)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (1)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1)
  • Test (11-18)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.wsr.g.verified.cs (2)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (2)
  • Test (11-32)
  • Test (13-31)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout.Tests/ForStatementTests.Case2a#Test.Test.g.verified.cs (3)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (2)
  • Test (11-32)
  • Test (13-31)
Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.g.verified.cs (1)
Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.wsr.g.verified.cs (1)
  • TestWithParameter (13-17)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (2)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (1)
Cutout/RenderUtilities.Source.cs (2)
  • RenderUtilities (11-24)
  • ApplyExtraWhitespace (13-23)
Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.g.verified.cs (1)
Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.wsr.g.verified.cs (1)
  • TestWithModel (13-19)
Cutout.Tests/SharedTests.Case1#FileTemplateAttribute.g.verified.cs (2)
Cutout.Tests/SharedTests.Case1#TemplateAttribute.g.verified.cs (1)
  • AttributeUsage (13-28)
Cutout/FileTemplateAttribute.Source.cs (2)
  • AttributeUsage (12-19)
  • FileTemplateAttribute (18-18)
Cutout.Tests/ForStatementTests.Case2a#Test.Test.wsr.g.verified.cs (2)
Cutout.Tests/ForStatementTests.Case2a#Test.Test.g.verified.cs (2)
  • Test (11-24)
  • Test (13-23)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout.Tests/IfStatementTests.Case3a#Test.Test.wsr.g.verified.cs (4)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/ForStatementTests.Case2a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-24)
  • Test (13-23)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-32)
  • Test (13-31)
Cutout.Tests/TemplateTests.Case5a#Test.TestWithConstantTemplate.wsr.g.verified.cs (2)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout/RenderUtilities.Source.cs (2)
  • RenderUtilities (11-24)
  • ApplyExtraWhitespace (13-23)
Cutout/TemplateAttribute.Source.cs (4)
Cutout.Tests/SharedTests.Case1#FileTemplateAttribute.g.verified.cs (1)
  • AttributeUsage (13-20)
Cutout/FileTemplateAttribute.Source.cs (1)
  • AttributeUsage (12-19)
Cutout.Sample/Examples.cs (3)
  • Template (7-8)
  • Template (12-13)
  • Template (31-32)
Cutout.Tests/CallStatementTests.cs (5)
  • Template (12-13)
  • Template (17-18)
  • Template (27-28)
  • Template (36-37)
  • Template (39-46)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (4)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case2a#Test.Test.g.verified.cs (2)
  • Test (11-24)
  • Test (13-23)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (2)
  • Test (11-32)
  • Test (13-31)
Cutout.Tests/IfStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-20)
  • Test (13-19)
Cutout/TemplateAttributeParts.cs (3)
Cutout/Parser/Parser.cs (3)
  • SyntaxList (23-36)
  • SyntaxList (44-170)
  • Parser (5-447)
Cutout/Lexer/Lexer.ApplyWhitespaceSuppression.cs (1)
  • Lexer (3-64)
Cutout/Lexer/Lexer.cs (1)
  • Lexer (3-164)
Cutout/FileTemplateAttribute.Source.cs (1)
Cutout/TemplateAttribute.Source.cs (1)
  • AttributeUsage (12-27)
Cutout.Tests/IfStatementTests.Case3a#Test.Test.g.verified.cs (3)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (2)
  • Test (11-32)
  • Test (13-31)
Cutout.Tests/IfStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-20)
  • Test (13-19)
Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.wsr.g.verified.cs (2)
Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.g.verified.cs (1)
  • TestWithTwoParameters (13-19)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout.Tests/IfStatementTests.Case1a#Test.Test.g.verified.cs (3)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/IfStatementTests.Case2a#Test.Test.g.verified.cs (2)
  • Test (11-24)
  • Test (13-23)
Cutout.Tests/IfStatementTests.Case3a#Test.Test.g.verified.cs (2)
  • Test (11-28)
  • Test (13-27)
Cutout.Tests/IfStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/IfStatementTests.Case2a#Test.Test.g.verified.cs (4)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/IfStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-20)
  • Test (13-19)
Cutout.Tests/IfStatementTests.Case3a#Test.Test.g.verified.cs (2)
  • Test (11-28)
  • Test (13-27)
Cutout/TemplateSourceGenerator.cs (1)
Cutout/TemplateAttributeParts.cs (2)
  • TemplateAttributeParts (13-28)
  • TemplateAttributeParts (30-34)
Cutout.Tests/IfStatementTests.Case2a#Test.Test.wsr.g.verified.cs (3)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/ForStatementTests.Case2a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-24)
  • Test (13-23)
Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.wsr.g.verified.cs (3)
Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.g.verified.cs (1)
  • TestWithModel (13-19)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout/RenderUtilities.Source.cs (2)
  • RenderUtilities (11-24)
  • ApplyExtraWhitespace (13-23)
Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.wsr.g.verified.cs (2)
Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.g.verified.cs (1)
  • TestWithParameter (13-17)
Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (2)
  • RenderUtilities (12-25)
  • ApplyExtraWhitespace (14-24)
Cutout/Renderer/Renderer.cs (1)
Cutout/Extensions/TokenListExtensions.cs (1)
  • ToString (7-36)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (2)
  • Test (11-18)
  • Test (13-17)
Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (2)
  • Test (11-23)
  • Test (13-22)
Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.g.verified.cs (1)
Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.wsr.g.verified.cs (1)
  • TestWithTwoParameters (13-19)
🔇 Additional comments (51)
Cutout.Tests/IfStatementTests.Case2a#Test.Test.g.verified.cs (1)

13-13: LGTM! Idiomatic type alias usage.

The parameter type has been updated to use the C# keyword alias string instead of String (System.String), which is the preferred idiomatic style in C#.

Cutout.Tests/IfStatementTests.Case3a#Test.Test.wsr.g.verified.cs (1)

13-13: LGTM! Consistent type alias usage.

The parameter types now consistently use the C# keyword alias string, aligning with idiomatic C# style.

Cutout.Tests/Extensions/GeneratorDriverExtensions.cs (1)

59-64: LGTM! Extends ignore list for new infrastructure.

The method now correctly ignores the newly introduced FileTemplateAttribute.g.cs and RenderUtilities.g.cs generated files, in addition to the existing TemplateAttribute.g.cs. This aligns with the PR's introduction of file-based templates and centralized whitespace handling utilities.

CODE_OF_CONDUCT.md (1)

118-128: LGTM! Improved markdown formatting.

The formatting changes make the attribution section more readable by placing links inline with their descriptive text, with no semantic changes to the content.

Cutout/TemplateSourceGenerator.TemplateMethodImpl.cs (2)

33-33: LGTM! Generates idiomatic type representations.

Using ToDisplayString() ensures generated code uses idiomatic C# type aliases (e.g., string instead of String, int instead of Int32). This change is the root cause of the consistent type alias improvements across all test verification files.


97-99: LGTM! Loop pattern changed while preserving behavior.

The iteration has been refactored from foreach to an indexed for loop. The behavior is preserved as the loop still processes each syntax element in order. The indexed access pattern may provide benefits for debugging or align with collection type constraints.

Cutout.Tests/IfStatementTests.Case2a#Test.Test.wsr.g.verified.cs (1)

13-13: LGTM! Idiomatic type alias usage.

The parameter types now use the C# keyword alias string, consistent with the systematic improvement across all generated code files.

Cutout.Tests/CallStatementTests.cs (2)

39-46: LGTM! Adds nested call template test case.

The new Case5 template demonstrates multi-level nesting by calling Case3, which in turn calls Case4. This provides valuable test coverage for nested call statement scenarios with proper whitespace handling.


84-102: LGTM! Validates nested call statement behavior.

The new test validates that multi-level nested call statements (Case5 → Case3 → Case4) produce correctly indented output, ensuring the whitespace handling works properly across nesting levels.

Cutout.Tests/IfStatementTests.Case1a#Test.Test.g.verified.cs (1)

13-13: LGTM! Consistent type alias usage.

The parameter type uses the idiomatic C# keyword alias string, completing the systematic consistency improvement across all generated code verification files.

Cutout.Tests/ForStatementTests.Case2a#Test.Test.g.verified.cs (1)

13-13: LGTM - Type alias improvement.

The change from String to string follows C# conventions by using the built-in type alias instead of the BCL type name.

Cutout.Tests/CallStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1)

13-16: LGTM - Proper whitespace parameter propagation.

The changes correctly:

  • Use the string type alias (line 13)
  • Thread the whitespace parameter through to the nested Case2 call (line 16)

This aligns with the centralized whitespace handling approach introduced in this PR.

Cutout/TemplateAttributeParts.cs (1)

27-44: LGTM - Clean refactoring with new constructor.

The extraction of BuildSyntax() (lines 36-44) eliminates duplication between the two constructors and properly encapsulates the lazy initialization logic. The new public constructor (lines 30-34) enables programmatic template creation, which aligns with the file-based template feature.

Cutout.Sample/.editorconfig (1)

1-2: LGTM - Template configuration.

The EditorConfig entry correctly associates the template file with the target method, enabling the file-based template feature introduced in this PR.

Cutout.Tests/ForStatementTests.Case3a#Test.Test.g.verified.cs (1)

13-13: LGTM - Consistent type alias usage.

The change from String to string maintains consistency with other test files in this PR and follows C# conventions.

Cutout.Sample/Cutout.Sample.csproj (1)

14-16: LGTM - Required for source generator.

The AdditionalFiles entry correctly makes SampleTemplate.cs.liquid available to the source generator, which is necessary for the file-based template feature.

Cutout/.editorconfig (1)

1-6: LGTM - Embedding configuration.

The EditorConfig entries correctly mark the three source files for embedding in the generator, enabling them to be included in the generator assembly and emitted to consumer projects.

Cutout.Tests/SharedTests.Case1#TemplateAttribute.g.verified.cs (1)

24-28: LGTM! Enforcing required template parameter.

The removal of the parameterless constructor ensures that TemplateAttribute always receives a template string, which aligns with its purpose. This prevents misuse where the attribute might be applied without an actual template.

Cutout.Sample/Examples.cs (1)

36-41: LGTM! Clear demonstration of file-based templating.

The new Test4 method effectively demonstrates the FileTemplateAttribute feature and follows the established pattern of the other example methods. The region name clearly indicates this is an external file template example.

Cutout.Tests/IfStatementTests.Case3a#Test.Test.g.verified.cs (1)

13-13: LGTM! Consistent type alias usage.

The change from String to string improves code consistency by using the idiomatic C# keyword alias. This is part of a broader update across the generated test files.

Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.g.verified.cs (1)

13-13: LGTM! Improved type qualification.

The change from SomeModel to Test.SomeModel makes the type reference explicit and fully qualified, improving clarity and avoiding potential ambiguity. This is the non-whitespace-sensitive version, correctly using direct Append calls, while the .wsr.g.verified.cs variant uses RenderUtilities for whitespace handling.

Parent.Directory.Packages.props (2)

14-14: LGTM! Release version update.

The version bump from 0.0.0-beta.1 to 1.0.0 indicates this PR is preparing for a stable release. The change is appropriate given the new features being added (FileTemplateAttribute, RenderUtilities).


16-16: LGTM! New dependency addition.

The addition of the Pasted package at version 1.0.0 with the appropriate mono-repo condition is consistent with the existing project structure. Based on the AI summary, this package is used for analyzer purposes in the Cutout project.

Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.wsr.g.verified.cs (1)

13-19: LGTM! Excellent whitespace handling refactor.

The changes improve the code in two ways:

  1. Type aliases: Using int and string instead of Int32 and String is more idiomatic C#.
  2. Centralized whitespace handling: Using RenderUtilities.ApplyExtraWhitespace consolidates whitespace logic into a reusable utility, replacing per-parameter inline handling. This improves maintainability and consistency across the codebase.

The whitespace-sensitive rendering (.wsr variant) correctly uses the utility, while the standard version (.g variant) uses direct Append calls.

Cutout.Tests/CallStatementTests.Case1a#Test.Test.g.verified.cs (1)

13-13: LGTM! Consistent type alias usage.

The change from String to string aligns with idiomatic C# conventions and improves consistency across the generated test files. This is part of the broader generator improvements in this PR.

Cutout.Tests/SharedTests.Case1#FileTemplateAttribute.g.verified.cs (1)

14-20: No issues found—template discovery mechanism is working correctly.

The FileTemplateAttribute correctly has no constructor parameters. Template files are discovered via .editorconfig configuration, as evidenced by:

  • .editorconfig in Cutout.Sample contains template_method = Cutout.Sample.Examples.Test4
  • SampleTemplate.cs.liquid is present and mapped to the Test4 method via this configuration
  • TemplateSourceGenerator combines embedded files, config options, and decorated methods to process template files
  • The Test4 method in Examples.cs is properly decorated with [FileTemplate]

The design is correct and working as intended.

Cutout.Sample/SampleTemplate.cs.liquid (1)

1-10: LGTM! Well-structured liquid template.

The template correctly uses the {{parameter}} placeholder for both the class name and within the method's return string. The syntax is valid and the structure follows standard C# conventions.

Cutout.Tests/TemplateTests.Case5a#Test.TestWithConstantTemplate.wsr.g.verified.cs (1)

15-17: LGTM! Centralized whitespace handling applied correctly.

The refactoring successfully consolidates whitespace normalization into a single ApplyExtraWhitespace call, improving maintainability and consistency across the codebase.

Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.g.verified.cs (1)

13-13: LGTM! Type alias standardization.

The change from Int32 to int aligns with C# coding conventions and improves code consistency across the generated files.

Cutout.Tests/TemplateTests.Case3a#Test.TestWithTwoParameters.g.verified.cs (1)

13-13: LGTM! Type alias standardization.

The change from Int32 to int and String to string aligns with C# coding conventions and improves consistency across the codebase.

Cutout.Tests/ForStatementTests.Case1a#Test.Test.g.verified.cs (1)

13-13: LGTM! Type alias standardization.

The change from String to string aligns with C# coding conventions and maintains consistency with the broader refactoring in this PR.

Cutout.Tests/ForStatementTests.Case3a#Test.Test.wsr.g.verified.cs (2)

13-13: LGTM! Type alias standardization.

The parameter type change from String to string aligns with C# coding conventions.


26-28: LGTM! Centralized whitespace handling applied correctly.

The refactoring successfully applies ApplyExtraWhitespace to both the loop index and tag values, ensuring consistent whitespace normalization across interpolated content.

Cutout.Tests/TemplateTests.Case2a#Test.TestWithParameter.wsr.g.verified.cs (2)

13-13: LGTM! Signature updated for centralized whitespace handling.

The parameter type change to int aligns with C# conventions, and the additional whitespace parameter enables the centralized whitespace normalization pattern.


16-16: LGTM! Centralized whitespace handling applied correctly.

The parameter value is now properly wrapped with ApplyExtraWhitespace, ensuring consistent whitespace normalization for interpolated values.

Cutout.Tests/SharedTests.Case1#RenderUtilities.g.verified.cs (1)

12-24: LGTM! Well-designed utility for whitespace normalization.

The RenderUtilities.ApplyExtraWhitespace implementation correctly handles:

  • Null values (returns null)
  • String values (passes through without conversion)
  • Other types (uses ToString())
  • Newline indentation (prefixes each newline with the specified whitespace)

This centralized approach improves maintainability and ensures consistent whitespace handling across all generated render methods.

Cutout.Tests/IfStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1)

13-13: LGTM! Type alias normalization.

The parameter type has been correctly normalized from String to string, aligning with C# conventions that prefer primitive type aliases.

Cutout.Tests/ForStatementTests.Case1a#Test.Test.wsr.g.verified.cs (1)

13-18: LGTM! Type normalization and centralized whitespace handling.

The changes correctly normalize the parameter type alias and adopt the centralized RenderUtilities.ApplyExtraWhitespace utility for consistent whitespace handling across the codebase.

Cutout/Cutout.csproj (2)

37-48: LGTM! Proper conditional dependency configuration.

The conditional references correctly handle both mono-repo and standalone builds:

  • NuGet package reference with PrivateAssets=all for standalone builds
  • Analyzer-only project reference for mono-repo builds

This ensures the Pasted dependency is available for source generation without leaking to consumers.


50-52: LGTM! Embedded source files configuration.

The AdditionalFiles configuration correctly includes all *.Source.cs files, making them available to the source generator for embedding into consuming projects.

Cutout/FileTemplateAttribute.Source.cs (1)

8-19: LGTM! Clean marker attribute design.

The FileTemplateAttribute is appropriately designed as a marker attribute for file-based templates. The parameterless constructor and absence of properties align with the design where template content is sourced from external files rather than attribute parameters.

Cutout.Tests/ForStatementTests.Case2a#Test.Test.wsr.g.verified.cs (1)

13-20: LGTM! Consistent pattern adoption.

The changes correctly apply both the type alias normalization and centralized whitespace handling pattern using RenderUtilities.ApplyExtraWhitespace for both expressions within the loop.

Cutout.Tests/TemplateTests.Case4a#Test.TestWithModel.wsr.g.verified.cs (1)

13-18: LGTM! Enhanced signature and whitespace handling.

The changes correctly:

  • Add the whitespace parameter to support whitespace handling
  • Fully qualify the nested Test.SomeModel type
  • Apply the centralized RenderUtilities.ApplyExtraWhitespace utility for both model properties
Cutout/Renderer/Renderer.cs (3)

111-123: LGTM! Centralized whitespace handling in WriteRawText.

The refactoring correctly:

  • Extracts the renderable variable for clarity
  • Conditionally applies ApplyExtraWhitespace only when whitespace receiver is included and text contains newlines
  • Maintains backward compatibility for standard cases

133-145: LGTM! Consistent whitespace handling pattern.

The refactoring applies the same centralized whitespace handling pattern as WriteRawText, extracting the renderable expression and conditionally applying ApplyExtraWhitespace based on the whitespace receiver flag.


203-222: LGTM! Cleaner whitespace parameter logic.

The refactoring introduces a hasWhitespace boolean that makes the conditional logic more readable and correctly handles all combinations:

  • Pass runtime whitespace parameter when receiver is included
  • Pass literal whitespace string when available
  • Concatenate both when necessary

The logic is clearer and maintains correct behavior.

Cutout/TemplateSourceGenerator.cs (5)

35-60: LGTM: Dual-pipeline architecture is well-structured.

The separation between attribute-based and file-based template providers is clear and maintainable. Both pipelines correctly feed into the same GenerateTemplate method.


119-129: Consider reporting diagnostics for missing template method references.

When template_method is specified in the config but doesn't match any [FileTemplateAttribute]-annotated method, the configuration is silently ignored. This could lead to confusion during development.

Consider adding diagnostic reporting:

if (!methodLookup.TryGetValue(method, out var methodContext))
{
    context.ReportDiagnostic(
        Diagnostic.Create(
            new DiagnosticDescriptor(
                "CUTOUT002",
                "Template method not found",
                $"Method '{method}' specified in template_method option not found or not decorated with [FileTemplateAttribute]",
                "Cutout",
                DiagnosticSeverity.Warning,
                isEnabledByDefault: true
            ),
            Location.None
        )
    );
    continue;
}

Note: You'll need to adjust the signature to accept SourceProductionContext or use a different diagnostic reporting mechanism appropriate for the SelectMany context.


109-115: Verify file type/extension filtering for template files.

The code processes all AdditionalText files without filtering by extension or path pattern. While the template_method option check (line 119) acts as a filter, you may want to verify that unrelated additional files (e.g., JSON configs, documentation) don't incur unnecessary processing overhead.

Optionally, add extension filtering for clarity:

foreach (var file in ctx.Static.Files)
{
    // Only process .txt or .template files (adjust extensions as needed)
    if (!file.Path.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) 
        && !file.Path.EndsWith(".template", StringComparison.OrdinalIgnoreCase))
    {
        continue;
    }
    
    if (file.GetText(token)?.ToString() is not { } templateText)
    {
        continue;
    }
    // ...
}

141-159: LGTM: Clean refactor that enables code reuse.

Delegating to BuildTemplateDetailsFromSyntax extracts common logic and maintains consistency between attribute-based and file-based template handling.


85-92: Verify case-sensitive method name matching is intended.

The methodLookup dictionary uses StringComparer.Ordinal, requiring exact case-sensitive matches between template_method config values and method full names. Ensure this aligns with the expected .editorconfig usage pattern—any casing mismatch will result in silent failure to match methods.

If case-insensitive matching is preferred, use:

         Dictionary<
             string,
             (
                 SemanticModel semanticModel,
                 MethodDeclarationSyntax methodDeclarationSyntax,
                 IMethodSymbol methodSymbol
             )
-        > methodLookup = new(StringComparer.Ordinal);
+        > methodLookup = new(StringComparer.OrdinalIgnoreCase);

Comment thread Cutout/RenderUtilities.Source.cs
Comment thread Cutout/TemplateAttribute.Source.cs
Comment thread Cutout/TemplateAttributeParts.cs
Comment thread Cutout/TemplateSourceGenerator.cs Outdated
Comment thread Cutout/TemplateSourceGenerator.cs
Comment thread Cutout/TemplateSourceGenerator.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f160ff and b7f1e42.

📒 Files selected for processing (2)
  • Cutout.Docs/articles/file-templates.md (1 hunks)
  • Cutout.Docs/toc.yml (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
Cutout.Docs/articles/file-templates.md

9-9: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


41-41: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)

🔇 Additional comments (2)
Cutout.Docs/toc.yml (1)

6-7: LGTM!

Navigation entry is well-placed and properly formatted. The new "File Templates" section logically precedes the "Template" section.

Cutout.Docs/articles/file-templates.md (1)

1-42: Comprehensive and well-structured documentation.

The documentation effectively explains the file-based templating workflow with clear, practical examples covering project file setup, C# method definitions, and .editorconfig binding. Content aligns well with the PR objectives and the new FileTemplateAttribute feature.

Comment thread Cutout.Docs/articles/file-templates.md Outdated
@bmazzarol bmazzarol force-pushed the feat/file-templating branch from 047d327 to 2b65799 Compare October 25, 2025 11:06
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
55.1% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@bmazzarol bmazzarol merged commit 6da5018 into main Oct 25, 2025
8 of 10 checks passed
@bmazzarol bmazzarol deleted the feat/file-templating branch October 25, 2025 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant