Skip to content

Latest commit

 

History

History
653 lines (552 loc) · 42.5 KB

File metadata and controls

653 lines (552 loc) · 42.5 KB

Release Notes

Unreleased

1.8.1 (2026-02-27)

Performance

  • Template Rendering: ~25% faster, ~54% less memory, ~27% fewer allocations in template rendering benchmarks.
    • Cache compiled scanner regex instead of recompiling per Scan() call
    • Reuse forloop variable map across loop iterations instead of allocating a new map per iteration
    • Add fast paths for string, int, float64, and bool in writeObject, avoiding fmt.Sprint and reflection
    • Reuse expression evaluation context across {{ }} expressions instead of allocating per expression
    • Use stack-allocated array for filter arguments, avoiding heap allocation for filters with ≤4 args
    • Use maps.Copy with pre-sized maps for bindings copies

Fixed

  • String-to-Number Conversion in Arithmetic Filters: Fixed regression where string values from bindings were not converted to numbers in plus, minus, times, and divided_by filters. For example, {{ str_var | plus: 1 }} where str_var = "10" now correctly returns 11 instead of 1. This was introduced in v1.8.0 when filter signatures changed from float64 to any (#124).

Changed

  • Replace custom intMin/intMax helpers with Go 1.21+ min/max builtins.

Tests

  • Expanded test coverage across render, parser, values, filters, and engine packages.

1.8.0 (2026-02-26)

Added

  • LaxFilters Option (#139, #9): Added Engine.LaxFilters() method that causes undefined filters to silently pass through the input value, matching Shopify Liquid behavior. By default, undefined filters still cause an error for backward compatibility. Also added --lax-filters CLI flag.

  • Date Timestamp Support (#137, #110): The date filter now accepts Unix timestamps as integers, unsigned integers, floats, and numeric strings. For example, {{ 1152098955 | date: "%Y-%m-%d" }} now works.

  • UnregisterTag (#130): Added Engine.UnregisterTag() method to remove tag definitions, including built-in tags. Thanks @jaime-amate

  • Unicode Identifier Support (#116): Added Unicode identifier support with major performance improvements. Thanks @uksarkar

  • Jekyll Extensions Support (#114): Added support for dot notation in assign tags (e.g., {% assign page.canonical_url = "/about/" %}) when JekyllExtensions config flag is enabled. This allows Jekyll-compatible template syntax while maintaining Shopify Liquid compatibility by default.

  • Auto-Escape Feature (#111): Implemented automatic HTML escaping for template output with opt-in/opt-out support via the safe filter. Output is automatically escaped by default when auto-escape is enabled, and can be marked as safe using {{ value | safe }}. Thanks @dop251

  • Template Loader (#107): Implemented custom template loader interface for flexible template storage. Thanks @chrisatbd

  • BasicEngine (#104): Added NewBasicEngine() function for simpler engine instantiation without standard tags/filters (#102). Thanks @jam3sn

  • JSON Filter (#84): Added json filter for JSON encoding. Thanks @prestonprice57

  • Strict Variables Mode (#74): Added support for strict variable checking to catch undefined variables. Thanks @jamesog

  • Custom Writer Support (#86): Added FRender to allow rendering into a custom io.Writer. Thanks @jamslinger

  • Template AST Access (#59, #66): Exposed template AST and lexical environment for introspection. Thanks @carolynvs, @aisbergg

  • For-Else Support (#93): Implemented else clauses in for loops. Thanks @codykrieger

  • Unless-Else Support (#68): Allow unless tags to have else clauses. Thanks @aisbergg

  • General Range Expressions (#65): Allow range expressions as general expressions, not only in loops. Thanks @aisbergg

  • Loop Modifier Expressions (#67): Allow loop modifiers to be general expressions, not just literals. Thanks @aisbergg

Changed

  • Go Version Support: Updated minimum Go version to 1.25. CI now tests against Go 1.25 and 1.26.

  • Dependencies: Updated github.com/osteele/tuesday to v1.0.4.

  • CI Generated File Verification (#138, #50): Added CI job to verify yacc-generated parser files are up to date.

  • CI Consolidation (#134): Consolidated CI workflows into a single test.yml with coverage, format, lint, vet, and mod verification jobs.

  • Modernized Build Tooling (#115): Updated golangci-lint configuration to v2 format, reorganized Makefile with comprehensive targets, and added pre-commit hooks for automated code quality checks. All existing lint and format issues have been resolved.

  • Modernization (#95): Various modernization improvements. Thanks @danog

  • GitHub Actions (#87): Bumped GitHub workflow actions to latest versions. Thanks @deining

Fixed

  • Slice Filter Enhancement (#126, #72): Enhanced slice filter with Unicode support and array slicing. Thanks @ofavre

  • Integer to Float Conversion (#124): Fixed issue where simple mathematical operations on integers transformed them into floats (#109). Thanks @GauthierHacout for reporting

  • Size Filter (#101): Count number of characters instead of bytes (#100). Thanks @jamslinger

  • Slice Bounds (#99): Don't panic when slicing with index out of bound (#98). Thanks @jamslinger

  • Division by Zero (#97): Don't panic in divided_by filter on division by zero (#96). Thanks @jamslinger

  • Nil Pointer (#94): Fix panic in ValueOf with nil pointer. Thanks @stephanejais

  • Nil Check (#91): Add nil check for grammar field before BlockSyntax call. Thanks @magiusdarrigo

  • Whitespace Control (#88, #78): Fix whitespace control and trimming (#79). Thanks @jamslinger, @chrisghill for reporting, @danog

  • Multiline Slice (#82): Fix slice on multiline strings. Thanks @danog

  • Block Errors (#81): Bug fixes for WrapError(), Errorf() and SourceFile() in block context (#80). Thanks @wttw

  • Map Filter (#71): Fix map filter with slice of structs. Thanks @ofavre

  • Documentation (#69): Fix example filter URL in documentation. Thanks @peteraba

  • Windows Tests (#61): Fixed include tag test cases on Windows

  • Fixed trailing whitespace issues in test files

  • Resolved all golangci-lint v2 compatibility issues

Documentation

  • Security Documentation (#119): Added comprehensive security documentation.

  • Loop Semantics (#117): Documented and compared loop semantics with Ruby implementation.

  • FRender Documentation (#118): Added documentation for FRender feature (#85).

1.3.0 (2020-02-13)

Contributions:

1.2.4 (2018-06-05)

Contributors:

Bug Fixes and Compatibility

  • Returning proper error type causes less panics during expression eval. (c32908a)
  • Properly handle implicit conversion to integer types. (4354d48)
  • Properly handle variadic functions. (1a2066b)
  • map[unhashable] returns nil instead of panic (b6c65ff)
  • join filter: default sep is space; omit nil entries (cb6efbf)
  • Match Ruby string split semantics (8874615)
  • Convert MapSlice -> map (1a12f12)
  • list filters operate on MapSlice (bb24f32)

Docs

  • Re-organize README (dbf0f7d)
  • Add Contributors section; add nsf as contributor; adopt All Contributors and all-contributors-cli (d2be34e)
  • Minor formatting fixes in the README (aadc886)

Test Coverage

Build and CI

  • Add make pre-commit; lint before testing (6e1f41e)
  • Add go 1.9 to travis build matrix (ba2ecf9)
  • Travis: add go 1.10; drop 1.8 (e30a0e2)

Code Internals

1.2.3 (2017-08-18)

  • Default time format is compatible w/ Liquid (5ebf31a)
  • Define IterationKeyedMap (4bc4c8a)
  • Move strftime to a separate repo (cdb0e44)
  • Nil pointers are equal, even if different types (fd4d34c)
  • Rearrange tests (804e3d6)
  • Rearrange value methods w/in file (62f44fa)
  • Rename rbstrftime package (c49d979)
  • Tests; implement map[nil] (6b15fbf)

Contributions:

1.2.2 (2017-08-08)

Bug Fixes

  • Fix array[nil] (e39a1fe)
  • Fix file not found tests for Windows (068afef)
  • Restore m['str'] where m map[any]any (9852226)

Docs

Tests

Build and CI

  • README: add Appveyor badge (0adf6e7)
  • Appveyor: remove mingw (1b3e55a)

Code Internals

  • Remove (commented-out) Strptime and tests (8d53a6b)
  • Replace extern "C" strftime by go implementation (85bd1dd)

1.2.1 (2017-08-03)

Contributors: @osteele, @thessem

  • "type" filters works on nil (96307fa)
  • Actually cache the drop resolution (83652f5)
  • Add comments and update tests (dd4d967)
  • Add engine.ParseString (5151799)
  • Add forwarders from evaluator pkg (fb70314)
  • Add setting to customise delimiters (9dd9191)
  • Add some tests (a07e5fa)
  • Add test (3d99b41)
  • Add top-level test cases for &map, struct (f670bfc), closes #23
  • Allow value to be a pointer (222559a)
  • Benchmarks (023fca4)
  • Change name of repository in README to liquid from goliquid (08cf333)
  • Consolidate {expressions,values}/drops.go (516182a)
  • Document values, including new struct behavior (1bc9726)
  • Fix struct PropertyValue attempting to use an invalid pointer (b2f5f1f)
  • gitgnore *.test (605d883)
  • Implement #11 contains on hashes (1b0f0cf), closes #11
  • make lint includes tests (dd0fcda)
  • Match Liquid/Ruby array[float] (fa5de60)
  • Move pkg evaluator -> values (6269836)
  • Move structValue to own file (bbdb40e)
  • Obey struct field tags (303027b)
  • Property access to struct pointers (de5fffa)
  • Property access to struct values (2cdd59d)
  • Pull loop renderer into separate method (eac67c3)
  • Race condition (9866cbf)
  • Race test, benchmarks, for drop resolution (7f501ce)
  • Recognize yaml.MapSlice as a value (46807c4)
  • remove fmt.Stringer render case (474edc1)
  • Remove generic Index, ObjectProperty (8040e9e)
  • Remove obsolete generic predicates (cf54755)
  • Remove obsolete note re Awesome Go (df3f7b2)
  • Return errors applying filters as Render errors (8ee8cef)
  • Store original stacktrace in re-thrown errors (a1c5927)
  • Support delimiters of any length (b7ef67f)
  • Support registering variadic functions as filters (82a1a6e)
  • teach iteration about MapSlice (306be63)
  • Test cases for new code (17def25)
  • test liquid:"-", not liquid:"" (both work, though) (7634673)
  • Tests (fd230ed)
  • Treat []byte as string, for some purposes (fd7b1f0)
  • Value layer recognizes, resolves drops (560c55e)
  • Wrap values instead of using generic functions (85cd6c9)

1.1.2 (2017-07-20)

1.1.1 (2017-07-17)

  • Iterating over hash yields [key, value] pairs (67cb2e0)
  • Quote tag names in error messages (2c497e3)

1.1.0 (2017-07-16)

  • CLI script to run shopify liquid for cf. (534c0e3)
  • Disable interfacer linter 😦 (6701199)
  • Implement whitespace control (f9ac12b)
  • Numbers can't start or end with a dot (f1412b6)
  • README (9fe6a96)
  • README filters and variables (cfc8a8c)
  • Report the line only if != 0 (af93d57)
  • Scan whitespace control (bf43fb8)
  • Warn on too many filter args (de4f81d)
  • Whitespace control uses byte.Buffer (dd49b22)

1.0.0 (2017-07-16)

  • Add appveyor.yml (06e0833)
  • Add expression.ParseStatement, statement selector literals (c864f3c)
  • Add FromDrop func (8efaada)
  • Add ParseTemplateLocation (16c3b6e)
  • Allow float index into array (247c1b1)
  • Close #18 loop range (271f637), closes #18
  • Combine CompilationError -> parser.Error (816b46a)
  • Complete #14 and #15 url{en,de}code filters (2e5cc60), closes #14 #15
  • Complete #17 sort_natural filter (3c242c4), closes #17
  • Complete #19 when a or b (2880ef4), closes #19
  • Complete #4 case…else (26bdd09), closes #4
  • Consolidate render.Error -> parser.Error (198f6bf)
  • Coverage (a2a4a1a)
  • Coverage (d6d6929)
  • Coverage (29c902f)
  • Cycle uses Statement; steps towards cycle groups (7444118)
  • docs (4317bfc)
  • Error.Filename -> Path (b95775c)
  • fun w/ time zones (4163dfa)
  • Implement #15 truncate_words filter (fdfc5d3), closes #15
  • Implement tablerow (cd23447)
  • Improve strftime error test (55cf56e)
  • Loop uses the statement record (110fee6)
  • Make harmless iterating over value (bad5593)
  • make install-dev-tools -> setup (0808c10)
  • make setup installs dependencies (68a3e9b)
  • Move control flow tags to separate file (c3c9de7)
  • Move interpreter ops into evaluator package (c11cf2a)
  • Move package expression -> expressions (6ff5721)
  • New ParseStatement returns record with different statement parse types (8964daf)
  • Parse in local time; switch to stdlib strftime (f39a2d2)
  • ParseError -> parser.Error; takes Locatable (8995782)
  • Prep loop for ranges (22d583f)
  • Property names can end in ? (dbba680)
  • ranges…but need to separated by .. (497a932)
  • README (ce7cc8f)
  • Remove a test that fails on Travis (55ec347)
  • Remove dependency on strptime (da541ab)
  • Remove IsTemplateError (724da61)
  • Rename branch -> clause (and remove Governs) (5547532)
  • Rename Config.Filename -> SourcePath (df80e8c)
  • Rename files -> standard_tags, standard_filters (8882a7d)
  • Rename loop_tag -> iteration_tags (55eb5b4)
  • rename node.Branch -> Clause too (5a12245)
  • Rename xxxTagParser -> xxxTagCompiler (6b8f76c)
  • Reorganize docs and examples (bfc7ced)
  • Replace render switch by polymorphism (1c94b61)
  • set travis email notification freq (9701daa)
  • Source location is an initialization parameter (92a4f2d)
  • Start #2 cycle tag (a637d27), closes #2
  • Test case for main (6a3a853)
  • TIL io.WriteString (41e7b29)
  • try disabling strptime (bb0590d)
  • Update README to v1 (f1cddfa)

0.2.0 (2017-07-10)

  • Change Engine, Template from Interface -> struct (ebb37f8)
  • comments (328d84f)
  • docs (163290b)
  • errors return source location, phase 1 (342a8b3)
  • gopkg; docs (635383b)
  • Implement hash.size (c2b7157)
  • Parser grammar is distinct from (and embedded in) config (b269138)
  • README (c291b2f)
  • Rename ParseTime -> ParseDate (a3a3473)
  • Tests (bfad047)
  • Update remaining public API to return SourceError (378c0b2)

0.1.0 (2017-07-09)

  • "contains" tests for arrays too (24d83f1)
  • (Some) relationship operators (d03efed)
  • a.b syntax (5dbd972)
  • a[b] for invalid a or b (50d11a6)
  • Add a Grammar interface for parsing (f313e6f)
  • Add a Travis file (8e673ac)
  • Add an executable (f1b2777)
  • Add an type filter; inspect is more robust (3a1506b)
  • Add contribution guidelines (1b7564d)
  • Add coverage status (6297319)
  • Add docs; remove unused UnimplementedError (983b9f5)
  • Add engine.DefineControlTag; currently does nothing (8f7bcae)
  • Add error line number (4472b15)
  • Add goveralls to travis (c415f89)
  • Add install-dev-toolsl to travis (008f1ed)
  • Add IsTemplateError (2161bb6)
  • Add Makefile (29c9ad8)
  • Add more dependencies to credits (97b36ab)
  • Add more parse time formats (77c5dc9)
  • Add MustConvertItem; convert bool -> int (80d58dc)
  • Add nil; distinguish between identifier and property patterns (7a2b28c)
  • Add public DefineTag (e21d2a7)
  • Add references to README (ac12225)
  • Add RenderContext.ParseTagArgs (7c48138)
  • Add reverse filter; improve generics (54b9f13)
  • Add status badges to the README (465a681)
  • Add strptime for time parsing (8ea72e4)
  • Add Template.SetSourcePath (5425668)
  • Allow - in identifiers (af8c486)
  • Allow parens (607f4f4)
  • Catch unimplemented panics (b1cf056)
  • Chunk regex wasn't sufficiently non-greedy (f8b5503)
  • Chunk scanner test cases (fc6d96e)
  • Closure.Bind copies the original bindings (4e96c15)
  • Compiler copies the syntax tree (8f63cb7)
  • contains operates on strings not arrays (9dda87f)
  • Control tag parsers can return an error (61663ab)
  • Control tags actions are table-driven (20e4df3)
  • Convert -> map[string] (767f1f4)
  • Convert map -> [] (6075f39)
  • Convert maps (2fed70b)
  • Convert returns an error; create MustConvert (4df3f04)
  • Coverage (6f7b67f)
  • Coverage (36929af)
  • Coverage (caca7a2)
  • Coverage (78526e7)
  • Coverage; simplify (a8afb01)
  • Create an Expression interface; add some docs (2a2f333)
  • Create LICENSE (e3425cc)
  • Create top-level interface to liquid package (514559e)
  • Docs (f15de87)
  • Docs (803fbbc)
  • Embed the Chunk in the AST nodes (089a0c8)
  • Expression evaluator tests; fix revealed bugs (1f805d5)
  • Filters are an engine configuration (2e9903f)
  • Filters can have (single) parameters (70aa70d)
  • Filters support multiple argument, including expressions (a93848a)
  • Finish generic comparison (dbdcca4)
  • Fix forloop.last with offset modifier (394036d)
  • Fix generic equality with nil (229059c)
  • Fix previous (87b8198)
  • Fix the raw tag (e2bb7c6)
  • for over a map iterates over its keys (decd8dd)
  • Functional is constructed within parser, not scanner (c02fbd5)
  • FunctionalNode -> TagNode (18e2540)
  • Generic Convert handles conversion to time (2083747)
  • Generics (87708a0)
  • GitHub templates (7bd8a8d)
  • gometalinter doesn't have a config in this repo (28db298)
  • identifiers can include '-' (606870e)
  • If tag parses during parse stage (621992c)
  • Implement {% else %}, {% elsif %} (cab7845)
  • Implement {% if %} (60d2f78)
  • Implement {% unless %} (6a06665)
  • Implement <=, >=, contains (6c56efd)
  • Implement a big chunk of filters (1630af7)
  • Implement a[n] (555991c)
  • Implement and, or, != (a5a3ad2)
  • Implement ar.first, ar.list (c648a70)
  • Implement booleans (6af4fca)
  • Implement break, continue (a1784cd)
  • Implement capture tag (055e789)
  • Implement case (w/out else) (c5e7e6c)
  • Implement comment tag (eb7a18e)
  • Implement date formats (61b651c)
  • Implement drops (ba874de)
  • Implement expression scanner (57be549)
  • Implement filters: default; date (w/out format) (d849e74)
  • Implement forloop variables (e9c35a3)
  • Implement include (fab31d9)
  • Implement loop modifiers (53a41f3)
  • Implement loop reversed (383db45)
  • Implement loop tag (babfc3e)
  • Implement obj['name'] (63e2c5c)
  • Implement raw tag (c09652b)
  • Implement remaining numeric filters (5ec1f66)
  • Implement some filters (30211ac)
  • Implement sort: key (612f456)
  • Implement string literals (without escapes) (ed150c5)
  • Implement uniq filter (585cc5d)
  • Implement variable assignment (cd15950)
  • Improve docs (a077502)
  • Improve some internal names (1da9d40)
  • Initial (58395a8)
  • lint (a824673)
  • Lint (e71bc95)
  • Lint (09d3650)
  • Lint (c4bd99b)
  • Lint; remove dead code (fb26bb3)
  • make install-dev-tools doesn't update packages (9714544)
  • Makefile default target is ci (3dba4ee)
  • Match print object to observed (d924e0b)
  • Match split filter to observed (6a8127a)
  • More filters (910d4b2)
  • More filters (c433c08)
  • More generic.Less; tests (43bedef)
  • More time formats (2f0f6ba)
  • Move assign tag -> tags package (d31fe04)
  • Move chunk marshalling to separate file (b367592)
  • Move chunks -> render (6161e6d)
  • Move chunks to sub-package (2e61304)
  • Move expression parser to sub-package (373b2fb)
  • Move expressions -> expression (9691dc2)
  • Move filters to own package (4189f03)
  • Move generics -> evaluator (a434a75)
  • Move generics to own package (f52d00f)
  • Move tag compilation to compiler stage (54e840c)
  • Move tags to own package (83503a1)
  • Negative integer indexes from end of list (c1fd00c)
  • New top-level Context wrapper (d6bc456)
  • Optional filter arguments declared as functions (8397c5e)
  • Parse control tag forms at parse time (5dddabe)
  • Parse object expressions during parse stage; report error source (d4c895d)
  • Rationalize some filenames (c4ff3d2)
  • README (d29e4b2)
  • README (c67d027)
  • README links to godoc (a4b1835)
  • Record source line number (08fcc4e)
  • remove a debug print (e332e53)
  • Remove else/elsif from unless (12045b5)
  • Remove gratuitous Context wrapper (cb8911a)
  • Rename (594ec99)
  • Rename chunk -> token (69d26a2)
  • Rename render.(Context,RenderContext) -> (NodeContext,Context) (411a2f0)
  • Rename renderError -> render.Error (315af1a)
  • Rename Settings -> Config (405c5bf)
  • Rename some files (bcef4dc)
  • Rename to match Liquid terminology (2e8f51a)
  • Render tree is distinct type from parse AST (803471c)
  • Render uses a switch instead of polymorphism (0559730)
  • Renderers return a string, rather than taking an io.writer (8d9df82)
  • Replace GetVariableMap -> UpdateBindings, RenderFile (a7cbb9b)
  • Restore tag tests (db5a3af)
  • Separate interface.go from engine.go (ebc29dc)
  • simplify (af95c44)
  • simplify (846987d)
  • simplify (c599761)
  • Simplify external tag interface (f6c4299)
  • slice, truncate use runes not bytes (a3c646c)
  • SortByProperty can sort nil first or last (e2fd3bb)
  • Split package render->parser (903acb8)
  • Start to separate parser and compiler (c7d9af2)
  • Tags are an engine configuration (e6f8eac)
  • Tags are called within a RenderContext (41da3f9)
  • tavis uses makefile lint (8f148dc)
  • tests (d435cf5)
  • Uh-oh – strftime gets the day of week wrong! (25e97ed)
  • Un-export ControlTagDefinition; create builder (0c7a8d2)
  • Unconfuse unless/endunless (9b8da4f)
  • Undefined tags, filters are errors not panics (9a807d0)
  • Update Contributing to point to the project boards (dd41a36)
  • Update guidelines to refer to issues board (aad76bd)
  • Use C strptime to format dates (247bec3)
  • Work around missing %-H in strftime (fc227aa)
  • Yacc expression parsing (9c64c5a)
  • Yacc, ragel source match package moves (a7a1ee5)