Commit Graph
1135 Commits
Author SHA1 Message Date
Tobi Lutke 3799d4c488 avoid allocating seen={} hash in Utils.to_s/inspect when not needed 2026-03-11 09:02:42 -04:00
Tobi Lutke b90d7f0a08 optimize Context init: avoid unnecessary array wrapping for environments 2026-03-11 08:56:45 -04:00
Tobi Lutke 405e3dca48 use frozen EMPTY_ARRAY/EMPTY_HASH for Context @filters/@disabled_tags 2026-03-11 08:55:55 -04:00
Tobi Lutke 69430e9a88 replace INTEGER_REGEX/FLOAT_REGEX with byte-level parse_number 2026-03-11 08:54:31 -04:00
Tobi Lutke 79840b1eaa replace SIMPLE_CONDITION regex with manual byte parser in if/elsif lax_parse 2026-03-11 08:52:49 -04:00
Tobi Lutke 4cda1a578c fast-path slice_collection: skip copy for full Array without offset/limit 2026-03-11 08:50:34 -04:00
Tobi Lutke d574f193dc add invoke_two fast path for single-arg filter invocation, avoids splat chain 2026-03-11 08:49:37 -04:00
Tobi Lutke 76ae8f13e9 fast-path find_variable: check top scope first before find_index 2026-03-11 08:48:16 -04:00
Tobi Lutke 526af22574 add invoke_single fast path for no-arg filter invocation, avoids splat alloc 2026-03-11 08:47:21 -04:00
Tobi Lutke 03a1977ffe fast-path simple if truthiness: use byte scanner before SIMPLE_CONDITION regex 2026-03-11 08:36:28 -04:00
Tobi Lutke 2e207e6844 replace WhitespaceOrNothing regex with byte-level blank_string? check 2026-03-11 08:34:15 -04:00
Tobi Lutke e5933fc6e4 avoid array allocation in parse_tag_token: return tag_name, store markup/newlines as class ivars 2026-03-11 08:33:19 -04:00
Tobi Lutke 1882edb1e1 clean up filter parsing: Lexer fallback for args, no-arg fast scan stays 2026-03-11 08:31:30 -04:00
Tobi Lutke 9fd7cec564 split filter parsing: scan no-arg filters directly, only invoke Lexer when args present 2026-03-11 08:26:04 -04:00
Tobi Lutke 17daac92da extend fast-path to handle quoted string literal variables (262 more fast-pathed) 2026-03-11 08:20:39 -04:00
Tobi Lutke 283961d6c9 skip filter arg splat for no-arg filters, trim render loop comments 2026-03-11 08:06:23 -04:00
Tobi Lutke db434923d0 hoist write score check out of render loop: skip increment_write_score when no limits active 2026-03-11 08:04:40 -04:00
Tobi Lutke b86143eb0e use frozen EMPTY_ARRAY for disabled_tags in Variable 2026-03-11 07:47:51 -04:00
Tobi Lutke 58d2514521 return [tag_name, markup, newlines] from parse_tag_token: avoid 2 whitespace string allocs 2026-03-11 07:45:15 -04:00
Tobi Lutke 82407092cc use getbyte dispatch instead of start_with? in parse_for_document 2026-03-11 07:44:12 -04:00
Tobi Lutke 544d8f1c17 avoid empty array allocation in evaluate_filter_expressions for no-arg filters 2026-03-11 07:43:09 -04:00
Tobi Lutke cfa0dfe3ca replace For tag Syntax regex with manual byte-level parser 2026-03-11 07:39:36 -04:00
Tobi Lutke 2d3b856b36 expose expression_cache/string_scanner via attr_reader, skip regex in filter args without colon 2026-03-11 07:38:16 -04:00
Tobi Lutke 8a92a4e451 unified fast-path Variable parsing: handle both plain lookups and filter chains without full Lexer pass for name 2026-03-11 07:36:29 -04:00
Tobi Lutke f8b015646a fast-path render for filter-less variables: skip render method overhead 2026-03-11 07:33:18 -04:00
Tobi Lutke 6bcc2936a2 skip TagAttributes scan in for tag when no colon present 2026-03-11 07:32:39 -04:00
Tobi Lutke fe7a2f5aa8 fast-path simple if conditions: skip ExpressionsAndOperators scan for single conditions 2026-03-11 07:31:26 -04:00
Tobi Lutke 3939d74531 replace SIMPLE_VARIABLE regex with byte-level scanner to avoid MatchData 2026-03-11 07:30:34 -04:00
Tobi Lutke 25f9224c85 fast-path simple variable parsing: skip Lexer/Parser for plain dot-separated lookups 2026-03-11 07:29:47 -04:00
Tobi Lutke 5da223275a use frozen EMPTY_ARRAY for Variable filters when no filters present 2026-03-11 07:28:04 -04:00
Tobi Lutke 1a79cf6266 fast-path variable_lookups: skip mutable string alloc when no dot/bracket follows 2026-03-11 07:26:40 -04:00
Tobi Lutke c1113ad2f8 fast-path String in render_obj_to_output, avoid Utils.to_s dispatch for common case 2026-03-11 07:24:30 -04:00
Tobi Lutke fa412245f7 short-circuit parse_number with first-byte check before regex 2026-03-11 07:23:41 -04:00
Tobi Lutke d79b9fa254 avoid unnecessary strip allocation in Expression.parse, use byteslice for string literals 2026-03-11 07:23:08 -04:00
Tobi Lutke d291e63006 use equal? for frozen array comparison in Lexer, skip whitespace with \s+ 2026-03-11 07:21:55 -04:00
Tobi Lutke 2b78e4bf72 use getbyte instead of string indexing in whitespace_handler and create_variable 2026-03-11 07:19:26 -04:00
Tobi Lutke 97e6893c1a replace VariableParser regex scan with manual byte parser in VariableLookup 2026-03-11 07:14:14 -04:00
Tobi Lutke 3329b09dd4 replace FullToken regex with manual byte parsing in parse_for_document 2026-03-11 07:12:38 -04:00
Michaël Gallego d589c51697 Add squish filter 2026-02-19 10:03:52 +09:00
Tobi LutkeandClaude Opus 4.5 ccd05e869c Make blank/empty comparisons invariant to ActiveSupport
- Implement liquid_blank? and liquid_empty? methods in Condition
  to emulate ActiveSupport's behavior when it's not loaded
- This ensures templates like `{% if x == blank %}` work identically
  whether ActiveSupport is loaded or not
- Update liquid-spec adapters for new API (ctx parameter)
- Add rake spec task for running liquid-spec matrix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
2026-01-05 14:54:43 -10:00
Tobi Lutke ef13b2dfd5 Fix empty? semantics and string first/last for empty strings
- nil is NOT empty (but IS blank) - matches Shopify production
- String first/last returns '' for empty strings, not nil - matches ActiveSupport
- Add test for nil not being empty
2026-01-01 22:06:22 -05:00
Tobi Lutke af58800c16 Update rubocop-shopify to 2.18.0 and fix new offenses 2026-01-01 20:22:19 -05:00
Tobi Lutke 361d1d52b1 Fix rubocop offenses from 1.82 upgrade 2026-01-01 20:20:50 -05:00
Tobi Lutke 0e3548d39e Remove redundant else-clause 2026-01-01 20:16:24 -05:00
Tobi Lutke 33bac87a5c Address liquid-spec issues without ActiveSupport loaded
Implement ActiveSupport-compatible behaviors internally so Liquid works
correctly without ActiveSupport being loaded:

1. String first/last via property access (name.first, name.last)
   - VariableLookup now handles string[0] and string[-1] for first/last

2. String first/last via filters (name | first, name | last)
   - StandardFilters#first and #last now handle strings

3. blank?/empty? comparisons for types without these methods
   - Condition now implements liquid_blank? and liquid_empty? internally
   - blank? matches ActiveSupport: nil, false, empty/whitespace strings,
     empty arrays/hashes are all blank
   - empty? checks length == 0 only (whitespace is NOT empty)

This fixes spec failures for templates like:
- {{ name.first }} / {{ name | first }} on strings
- {% if x == blank %} for whitespace strings, empty hashes/arrays
- {% case ' ' %}{% when blank %} matching whitespace
2026-01-01 20:14:21 -05:00
Ian Ker-SeymerandGitHub 22e979a6fa Use floating-point format for BigDecimal stringification (#2022)
## Summary

- BigDecimal values now stringify using `to_s("F")` format instead of the default `to_s`

## Why

Ruby's default `BigDecimal#to_s` produces engineering/scientific notation for certain values:

```ruby
BigDecimal("0.00001").to_s      # => "0.1E-4"
BigDecimal("12345678.9").to_s   # => "0.123456789E8"
```

This is rarely the desired output in templates. Using `to_s("F")` produces the expected floating-point format:

```ruby
BigDecimal("0.00001").to_s("F")      # => "0.00001"
BigDecimal("12345678.9").to_s("F")   # => "12345678.9"
```
2025-12-05 15:54:52 -05:00
Julia Boutin fa27bfe6e0 Preserve literal semantics in strict2 case/when
Previously, strict2 case/when used `safe_parse_expression`
to parse when expressions causing `blank`/`empty` to be
treated as string literals (Expression::LITERALS maps 'empty' => ''),
rather than method literals

This caused unexpected behavior:

```
{%- case empty_obj -%}
{%- when empty -%}
  previously: doesn't render (empty_obj == '' is false)
  now: renders (empty_obj.empty? is true)
{%- endcase -%}
```

This commit instead calls `Condition.parse_expression`
with `safe: true`, which will correctly handle `blank`
and `empty`
2025-11-28 15:51:48 -07:00
Guilherme CarreiroandGitHub 32b50ecafe Bump Liquid to 5.11.0 (#2012)
This commit reverts the Inline Snippets tag (#2001) and bumps
Liquid to 5.11. For now, the inclusion of Inline Snippets
in the latest Liquid release is being treated as a bug.

While #2001 does implement the scope contained in RFC#1916,
we need to take a step back to make sure we’re setting our
sights high enough with this feature, and that we’re truly
supporting theme developers in the ways they need.

If you have any feedback, please leave a comment on RFC#1916.

- Liquid Developer Tools
2025-11-19 18:03:23 +01:00
Gray Gilmore 9973f3399e Don't raise if no variable found when using context.key?
Previously if you set `strict_variables` to `true` on the context using
`key?('key_name')` would raise a `Liquid::UndefinedVariable` error.
Raising this error makes sense if you're trying to access the variable
directly with something like  `context['key_name']` but by using `key?`
you're safely checking if it exists first.

You should be able to enable `strict_variables` and use `key?` in
combination with each other to ensure code safety.
2025-10-30 15:33:07 -07:00
Guilherme CarreiroandGuilherme Carreiro 248f3a412f Bump to 5.10.0 2025-10-30 12:28:52 +01:00