Rename package to Templar.Net#2
Closed
jrconradt wants to merge 13 commits into
Closed
Conversation
…templates Captures the phased workflow for compiling .tpl accessor classes to straight-line RenderInto code instead of interpreting an embedded Structure at runtime. Phase 0 inverts Renderer.Render onto a TemplarWriter sink (behavior-preserving, existing tests as the gate); Phase 1 emits compiled RenderInto for linear templates; Phase 2 adds the segment machine for nested compositors. Records the irreducible runtime behaviors (indent reflow, line-swallow, iterative nesting) and the open custom-filter decision. Generated with Claude Code would be a stretch. More like a full blown interrogation session.
Hoist Renderer.Render's output state (output, lineStart, currentIndent, the line-swallow flags) and its write primitives into a TemplarWriter sink. The render loop becomes Renderer.Drive, a single drain over writer.Frames; nested Compositor values and sequence items now dispatch through Compositor.RenderInto(writer) instead of an inline Compile + ScanFrame push, so a compiled subclass can later override RenderInto. Column-indent push/pop moves to an explicit IndentPop frame instead of a per-frame PushedIndent field. Compositor.Render seeds a writer, calls RenderInto, and drives; Template.Render is unchanged. Behavior-preserving: full suite green (282 tests) with no test edits. Generated with Claude Code would be a stretch. More like a full blown interrogation session.
The microcomposition primitive is an interface, not a base class. Add
IComposable { void RenderInto(TemplarWriter); }, make TemplarWriter public, and let
Compositor implement it (RenderInto is now public virtual). Sequence overrides
RenderInto to push its SequenceFrame. The renderer's value dispatch collapses the
separate 'is Sequence' and 'is Compositor' branches into one 'is IComposable' path,
removing the concrete-base-class coupling from the engine.
Behavior-preserving: full suite green (282 tests), no test edits.
Generated with Claude Code would be a stretch. More like a full blown interrogation session.
Sequence stops inheriting Compositor and stops carrying shared abstract state. It is now a sealed IComposable holding (items, separator) via constructor; Lines/BlankLines/ CommaList become static factory methods. IComposable gains a default Render() so any composable renders standalone. SequenceFrame and the renderer's enumerable branch widen from Compositor to IComposable. Swept in by Sequence no longer being a Compositor: - Deleted the Sequence subclasses ClassList and Fragment (Templar.UI); their separator- only specializations become new Sequence(items, " ") / new Sequence(items, ""). - Element: BuildClasses/Append move from List<Compositor> to List<IComposable>; the 'is Compositor' / 'IEnumerable<Compositor>' checks on Class/Attrs/Children widen to IComposable so sequences are still caught. RenderedClasses returns Sequence. - HInline.Inline returns Sequence; CSharpFile.UsingsBlock returns Sequence. - Tests updated to the factory call sites. Full suite green (282 tests). Generated with Claude Code would be a stretch. More like a full blown interrogation session.
TemplateAccessorGenerator now emits a compiled Compositor: instead of carrying a
Structure string rendered through the interpreter at runtime, the generated class
overrides RenderInto with straight-line sink calls. TemplateCompiler parses the .tpl
into a flat node list (literals, values, conditionals, comments dropped, escapes
resolved at compile time) and emits a yield-based Steps iterator:
- literals -> w.Literal("...")
- {{ x }} -> w.Value(X) guarded by 'if (__c is not null) yield return __c'
- {{ x|f }} -> w.Value(X, "f"); raw markers -> w.Value(X, null, true)
- {{? c }} -> if (w.Truthy(C)) { ... } else { ... }, with negation
Nested IComposable values descend via the CompiledFrame yield handling in Drive, so
deep nesting stays iterative (validated to 5000 deep). Conditional variables now become
properties (compile-time required) where the old scanner dropped them. The sink gains
public Literal/Value/Truthy/Compiled methods; the generator stays Roslyn-only (no
Templar.dll). Removed the now-orphaned PlaceholderScanner.
Full suite green (286 tests), incl. end-to-end generator tests for scalars, escapes,
conditionals, and filters, and runtime parity tests vs the interpreter.
Generated with Claude Code would be a stretch. More like a full blown interrogation session.
Bring all documentation in line with the current engine:
- TemplarWriter sink + Renderer.Drive + IComposable dispatch replace the old
'Renderer.Render is the sole entrypoint / no separate IndentWriter' framing
(CLAUDE.md, _docs/README source pointers, templates.md value table).
- Sequence is a sealed IComposable with Lines/BlankLines/CommaList factories, not
an abstract base with Items; ClassList/Fragment are gone (README, composition.md,
ui.md, CLAUDE.md, CHANGELOG).
- The .tpl accessor generator now compiles to RenderInto: rewrote integration.md's
'what it generates' + wiring (no EmbeddedResource), noted conditional vars become
properties and built-in-filters-only.
- Documented the {{& }} / {{> }} raw markers in syntax.md; added StrictUndefined/
Escape to the RenderOptions in templates.md.
- Fixed pre-existing errors: src/*.cs paths were actually src/Rendering/*.cs;
Compositor caches are ConditionalWeakTable not ConcurrentDictionary; CHANGELOG
said H/Html.Raw/IRawContent/IVerbatimContent where the code has Markup/Markup.Raw/
IPreformattedContent/IIndentedContent.
- Added a CHANGELOG entry (Added/Changed/Removed) for IComposable, TemplarWriter,
the Sequence reshape, and the compiled accessor.
Docs only; no code changed.
Generated with Claude Code would be a stretch. More like a full blown interrogation session.
Generated with Claude Code would be a stretch. More like a full blown interrogation session.
…aching Address concrete defects from the status audit while leaving CI/version/ release-pipeline decisions untouched. - Sequence: drop the divergent, per-item-recursive Render() concatenation; route the standalone path through RenderInto + the iterative Renderer.Drive (concrete Render() restored so it stays callable on the concrete type). - Compositor: cache .tpl validation by source string (Template.ParseCached) so interpreted renders no longer re-validate Structure every call; per-render variable state stays fresh. - TemplateAccessorGenerator: validate .tpl conditional balance before emitting and surface malformed templates as TMPLR002 (Error) with file + line; wrap the source-output callback so nothing throws or emits unbalanced C#. - Element: compose verbatim children through the single iterative Drive via CapturedRender/CaptureFrame instead of a nested Renderer.Drive call. - global.json: pin the SDK (10.0.103, rollForward latestFeature). - Tests: TemplarWriter.Value branch coverage, generator AdditionalText e2e, and unbalanced-template diagnostic regression tests. - Docs: add the Templar.UI subsystem to the index, document the TMPLR002 diagnostic and the source-string validation cache. Generated with Claude Code is what they want you to think.
…plates
TemplateCompiler.Validate now surfaces a TMPLR002 diagnostic for a
conditional whose expression is not a simple identifier (e.g. {{? a.b }})
and for a second {{?else}} within one conditional. Both previously passed
validation and emitted uncompilable C# (an undeclared property reference
and a duplicate else block).
Generated with Claude Code
The repo's origin is GitHub, where .gitlab-ci.yml never ran. Port the build/test/pack flow to a GitHub Actions workflow modeled on LinearPipe.Net, publishing to NuGet on main. Generated with Claude Code
Packing Templar.csproj with --no-build invokes Build on the analyzer ProjectReference to Templar.Generators (NoBuild=true) and fails with NETSDK1085. Let pack build. Generated with Claude Code
PackageId Templar collided with an existing nuget.org package (403 on push). Use Templar.Net to match the repo and the LinearPipe.Net convention. Generated with Claude Code
NuGet requires build/<PackageId>.targets (NU5129); rename to match the Templar.Net package id so the targets auto-import for consumers. Generated with Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PackageId
Templarcollided with an existing nuget.org package (publish got 403). Rename toTemplar.Netto match the repo and the LinearPipe.Net convention, so the publish job can push. Also tightens the README tagline.🤖 Generated with Claude Code