trellis 0.3.0
trellis: ^0.3.0 copied to clipboard
Template engine for Dart, using natural HTML templates. Fragment-first for hypermedia-driven frameworks like HTMX. Inspired by Thymeleaf.
Changelog #
All notable changes to trellis are documented here. This project follows Semantic Versioning.
0.3.0 #
Added #
- Processor interface & pipeline:
Processorabstract class,ProcessorPriorityenum (8 priority slots),ProcessorContextclass — all built-in processors implement the interface; pipeline iterates a sorted processor list - Custom processor registration:
DomProcessor(processors: [...])registers customProcessorinstances with auto-prefixed attributes, priority-sorted merge, error wrapping, andautoProcessChildrencontrol - Dialect system:
Dialectabstract class andStandardDialect;DomProcessor(dialects: [...], includeStandard: false)composes processors and filters across multiple dialects - Filter arguments:
| filterName:arg1:arg2syntax for parameterized filters; supports string (\'escape), int, double, bool, null, and bare identifier args; backward compatible with existingFunction(dynamic)filters - i18n message expressions:
#{key}expression type withMessageSourceabstract class andMapMessageSourceimplementation; parameterized messages#{key(arg1, arg2)}with{0}/{1}positional replacement; locale support via engine config and_localecontext override; strict/lenient missing-key behavior AssetLoader: loads templates from Dart package assets viaIsolate.resolvePackageUriCompositeLoader: tries delegate loaders in order, falling back onTemplateNotFoundExceptionTrellisconstructor params:processors,dialects,includeStandard,messageSource,locale- Framework Integration Guide:
doc/guides/framework-integration.mdcovering shelf, dart_frog, and HTMX patterns - Todo app example:
example/todo_app/— full Shelf + HTMX app demonstrating v0.3 features
Changed #
example/restructured intoexample/basic/andexample/todo_app/sub-packages
0.2.1 #
Fixed #
tl:blockself-closing:<tl:block/>no longer swallows subsequent siblings — normalizer now uses a quote-aware scanner instead of a regex, correctly handling>inside attribute values (e.g.tl:if="${count > 0}")tl:fragmentontl:block:renderFragment()andrenderFragments()now correctly unwrap block elements, returning inner content instead of empty outputtl:eachwith null/missing iterable: gracefully removes the host element instead of throwing; consistent with lenient-mode semantics
Added #
!negation operator:!is now supported as an alias fornotin expressions (e.g.tl:if="!${active}")
0.2.0 #
Added #
- Expression enhancements: arithmetic operators (
+ - * / %), literal substitution (|Hello, ${name}!|), dynamic index expressions (${list[index]}), selection expressions (*{field}withtl:object), comparison aliases (gt,lt,ge,le,eq,ne), no-op token (_) tl:switch/tl:case: multi-branch conditional renderingtl:classappend/tl:styleappend: append to existing class/style attributestl:block: virtual element that renders only its children (no host element in output)tl:remove: remove elements or content from output (all,body,tag,all-but-first,none)tl:inline: inline expression processing in text, JavaScript, and CSS contexts ([[${expr}]]escaped,[(${expr})]unescaped)tl:object/*{}: object context and selection expressions for scoped field access; auto-conversion viatoMap()/toJson()- Parameterized fragments:
tl:fragment="card(title, body)"with argument passing at inclusion time - CSS selector targeting:
tl:insert="~{file :: #id}"andtl:insert="~{file :: .class}" - Cycle detection: fragment inclusion stack replaces depth-only guard — recursive inclusions detected immediately
renderFragments(): render multiple named fragments from a single template string in one callrenderFileFragments(): async variant loading from the filesystem- Strict mode:
Trellis(strict: true)— undefined variables, members, and keys throwExpressionException - LRU cache: configurable max cache size via
maxCacheSizeparameter; evicts least-recently-used entries CacheStats: expose cache hit/miss/size metrics viaengine.cacheStatsclearCache(): clear DOM cache and reset statisticsTrellisContext: fluent builder for constructing rendering context mapsdata-tl-*prefix mode:Trellis(prefix: 'data-tl')for strict HTML5-valid attribute names
Fixed #
- Expression parser: alias/keyword words (
gt,eq,and,true, etc.) now work as member names after.— e.g.${obj.eq},${stats.gt} - README: corrected
TrellisContextexample,renderFragmentsreturn types,tl:switchcase syntax,tl:classappendternary,maxCacheSizedefault, removed nonexistentseparatorparameter
Changed #
- Fragment registry entries now carry parameter names for parameterized fragment resolution
- Inclusion depth guard replaced by cycle detection stack (still enforces max depth 32 as hard limit)
0.1.0 #
Added #
- Core template engine with 15
tl:*attributes for natural HTML templating - Text substitution:
tl:text(escaped) andtl:utext(unescaped HTML) - Conditionals:
tl:ifandtl:unless - Iteration:
tl:eachwith status variables (index, count, size, first, last, odd, even, current) - Fragment system:
tl:fragment,tl:insert,tl:replacewith cross-file inclusion - Local variable binding:
tl:with - Attribute setting:
tl:attr,tl:href,tl:src,tl:value,tl:class,tl:id - Expression evaluator:
${var}variables,@{/url}URL expressions, string literals, ternary, Elvis, comparisons, boolean operators - Four public API methods:
render(),renderFile(),renderFragment(),renderFileFragment() - DOM caching with deep-clone for performance
- Configurable attribute prefix (default
tl) FileSystemLoaderwith security boundary enforcement (path traversal, symlink escape protection)MapLoaderfor in-memory templates and testing- Typed exception hierarchy:
TemplateException,ExpressionException,FragmentNotFoundException,TemplateNotFoundException,TemplateSecurityException