The %s handler read LiquidDate.getTime(), which returns the
displayDate deliberately shifted by the display timezone offset for
wall-clock getters. With a timezone argument or timezoneOffset
option set, %s produced an epoch shifted by (server offset - display
offset) instead of the true Unix timestamp.
Expose the unshifted time as LiquidDate.dateValue() and use it for
%s. Also switch Math.round to Math.floor so fractional seconds
truncate toward the epoch like Ruby strftime.
Fixes#931
* docs(readme): lead with quick start and scannable structure
Restructure the README to match common OSS conventions: tagline and
badges above the fold, copy-paste Quick start, Features list, and a
compact Used by section. Remove the star plea, centered logo, and
per-project marketing blurbs that pushed useful content down.
Co-authored-by: Cursor <[email protected]>
* docs(readme): playground GIF, used-by grid, and docs homepage sync
Add data/used-by.json with build:used-by for README and docs homepage, playground demo capture, and shared home-section layout. Used by lists products with site logos; Financial Support keeps org and individual sponsors.
Co-authored-by: Cursor <[email protected]>
* chore: use .local for playground capture scratch files
Co-authored-by: Cursor <[email protected]>
* fix: satisfy eslint in build-used-by and capture scripts
Co-authored-by: Cursor <[email protected]>
* chore: drop one-off playground capture script
Co-authored-by: Cursor <[email protected]>
* refactor(docs): copy Used by from README like financial contributors
Drop data/used-by.json and build-used-by.js; build-contributors.js now extracts USED-BY-BEGIN/END to used-by.swig.
Co-authored-by: Cursor <[email protected]>
* refactor(docs): inline Used by section, drop home-section partial
Co-authored-by: Cursor <[email protected]>
* fix(docs): drop redundant logo styles from .contributors
Co-authored-by: Cursor <[email protected]>
* fix(docs): build liquid bundle before hexo serve
Co-authored-by: Cursor <[email protected]>
* refactor(docs): drop playground window chrome from capture demo
Co-authored-by: Cursor <[email protected]>
* refactor(docs): revert playground capture changes to master behavior
Restore Ace output pane, drop Prism and output-preview styling. Simplify docs:dev to rely on docs prestart.
Co-authored-by: Cursor <[email protected]>
* refactor(docs): rely on docs prebuild for liquid bundle and contributors
Co-authored-by: Cursor <[email protected]>
* feat(docs): show playground output as Prism-highlighted HTML code
Co-authored-by: Cursor <[email protected]>
* feat(docs): polish playground layout and regenerate README demo GIF
* fix(docs): align playground GIF capture with live editor styling
* fix(docs): unify playground pane padding and hold output on errors
Match editor inset to the output panel, drop Prism from output preview,
keep the last render while typing invalid template/context, and refresh
the README demo GIF.
* fix(docs): regenerate playground GIF with held output during typing
* feat(docs): sync Used by logos and polish playground
Inline README Used by grid on the docs homepage, refine playground layout and live output behavior, and drop the unused build-used-by script from package scripts.
Co-authored-by: Cursor <[email protected]>
* fix(docs): restore Rock RMS logo and remove duplicate entry
Restore the official Rock RMS wordmark (GetImage.ashx?id=72534) instead of the SparkDevNetwork GitHub org avatar that was wrongly substituted for it.
Co-authored-by: Cursor <[email protected]>
* fix(docs): regenerate playground GIF with live indicator states
Restore the capture script for the new pane-indicator layout so the README demo shows correct idle/active/pending/ok colors and pulsing animations while typing.
* fix(docs): static playground GIF with correct indicator colors
Capture one frame per keystroke with animations disabled so dot states
(idle/active/pending/ok) match the live playground without pulsing.
Co-authored-by: Cursor <[email protected]>
* docs: use square Rock RMS icon in Used by section
Co-authored-by: Cursor <[email protected]>
* fix(docs): ensure capture indicator colors apply instantly
Disable indicator transitions and cancel active animations before
setting data-state so pending yellow is not stuck on the prior ok green.
Co-authored-by: Cursor <[email protected]>
* docs: point Microsoft Used by link to microsoft.com
The merged tile title covers Power Pages and Azure API Management; href should go to Microsoft home, not Power Pages only.
Co-authored-by: Cursor <[email protected]>
* docs: remove Dailycontributors from Used by section
No evidence they run on LiquidJS; they are an OpenCollective sponsor only.
Co-authored-by: Cursor <[email protected]>
* docs: reword intro to say Liquid, not Shopify Liquid
Move Shopify into the compatibility list and drop the shopify/liquid link from README; align package.json description.
Co-authored-by: Cursor <[email protected]>
* fix(docs): restore playground output as Prism-highlighted HTML
Co-authored-by: Cursor <[email protected]>
* docs: add extensible to README intro and package description
EOF
Co-authored-by: Cursor <[email protected]>
* chore: move playground capture script to .local
Co-authored-by: Cursor <[email protected]>
* fix(docs): drop unused Ace mode-html from playground
Output pane uses Prism, not Ace; template and context editors still need liquid/json modes and basePath for themes.
Co-authored-by: Cursor <[email protected]>
* docs: sync intro sentence across package and site metadata
Align package.json, docs config, manifest, llms.txt, and AGENTS.md tagline to the README canonical description.
Co-authored-by: Cursor <[email protected]>
* docs: trim verbose intro in intro-to-liquid tutorial
Remove README tagline and repo-purpose copy duplicated by the recent metadata sync.
Co-authored-by: Cursor <[email protected]>
* docs: shorten homepage banner subtitle
Trim docs site banner and short taglines after the em dash; keep full description for meta tags and npm/README.
* docs: simplify playground GIF caption in README
Co-authored-by: Cursor <[email protected]>
* docs: dedupe homepage subtitle and description into _config.yml
Remove redundant front matter from index.pug; theme falls back to site config for banner and meta tags.
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
* docs: polish theme, playground, and reference pages
Improve readability of the docs site with updated light/dark tokens, shared
code-block styling, and playground editors that follow system color scheme.
Skip CookieHub on localhost, serve the browser bundle from theme source, and
use backtick titles on filter/tag reference pages for consistent navigation.
Co-authored-by: Cursor <[email protected]>
* docs: highlight npx in bash blocks and polish English copy
Use Prism insertBefore for CLI commands like npx, tighten tutorial and reference wording, and keep YAML titles free of backticks so sidebar and page headings stay correct.
Co-authored-by: Cursor <[email protected]>
* docs: restore lowercase filter and tag titles
Titles should match actual filter/tag identifiers (e.g. abs, append), not capitalized English labels.
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
* docs: add GitHub buttons and improve option docs
* chore: replace husky with prepush check
* docs: revamp homepage and switch to custom GitHub buttons
- Make the docs English-only by removing all zh-cn content, the language switcher UI, and related JS/config
- Rework homepage feature cards (Safe & Typed, Pure JavaScript, Shopify & Jekyll, Streaming) and refresh section colors/layout
- Replace buttons.github.io with custom Star/Sponsor buttons featuring a live star count and dark-mode support
- Drop the buttons.js script and tidy banner, header, footer, and share partials
Co-authored-by: Cursor <[email protected]>
* fix: restore tsconfig settings and changelog build
Re-add suppressImplicitAnyIndexErrors and downlevelIteration removed in
a75033e2c, which broke the rollup TypeScript build on CI. Drop zh-cn
changelog output now that translations were removed.
Co-authored-by: Cursor <[email protected]>
* fix: resolve TS errors without deprecated tsconfig options
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
* fix(security): block Object.prototype filter/tag lookups (RCE)
`liquid.filters` and `liquid.tags` were plain `{}` so bracket access on
template-controlled keys inherited from `Object.prototype`. Most damaging:
`{{ x | valueOf }}` resolved to `Object.prototype.valueOf`, which the
filter pipeline called as a handler with `this = FilterImpl`; valueOf
returns its receiver, leaking `context`, `liquid`, `token` (and via them
parser, loader, fs) into the template — chain that with `group_by`/`where`
gadgets and an attacker reaches `Function`/`child_process` for RCE.
Same shape on the tag side: `{% constructor %}` bypassed the
"tag not found" assertion and crashed with a confusing message.
Use null-prototype storage so `liquid.filters[name]` / `liquid.tags[name]`
only resolve to explicitly registered entries. The existing
`assert(impl || !strictFilters)` and `assert(TagClass, ...)` now do the
right thing for `valueOf`, `toString`, `constructor`, `__proto__`,
`hasOwnProperty`, `isPrototypeOf`, `__defineGetter__`, etc.
Co-authored-by: Cursor <[email protected]>
* test: fold prototype-registry regressions into register + e2e
Co-authored-by: Cursor <[email protected]>
* test: assert null-prototype registries vs all Object.prototype keys
Co-authored-by: Cursor <[email protected]>
* test: dedupe registry checks; merge filter prototype loop
Co-authored-by: Cursor <[email protected]>
* fix(context): use null-prototype scope and register objects
Add createScope(); use for bottom scope, spawn default, getAll merge, ctx.push frames, filter loops, include/layout blocks registers, and cycle groups. registers uses Object.create(null) and getRegister uses ??.
For-loop continue register defaults to 0 (not {}): Array.slice coerces plain {} but not null-prototype objects.
Export createScope from the package entry.
Co-authored-by: Cursor <[email protected]>
* revert(context): plain {} registers and getRegister ||
Registers are only mutated by tag implementations, not templates; keep null-prototype scopes/createScope for push frames.
Co-authored-by: Cursor <[email protected]>
* test(context): assert scope isolation without probing prototypes
Replace Object.getPrototypeOf checks for bottom() and getAll() with
'in' checks on typical Object.prototype names plus a merge assertion.
Co-authored-by: Cursor <[email protected]>
* test(e2e): assert constructor filter/tag lookups (node + UMD)
Co-authored-by: Cursor <[email protected]>
* test(context): cover Object.prototype keys under ownPropertyOnly
- Add getSync cases for constructor and valueOf on plain objects
- Remove scope storage tests that used the in operator
Co-authored-by: Cursor <[email protected]>
* refactor: remove createScope helper
Drop the exported helper and finish migrating call sites. Revert incidental context/for/include/layout churn so behavior matches mainline aside from the removal. Trim duplicate e2e and heavy Object.prototype loops in registry tests.
Co-authored-by: Cursor <[email protected]>
* docs: document ownPropertyOnly and Drop security in security model
Co-authored-by: Cursor <[email protected]>
* docs(zh-cn): sync security model with ownPropertyOnly and Drop notes
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
* fix(date): cap strftime widths and account padding in memoryLimit
- Clamp numeric strftime pad widths to MAX_STRFTIME_PAD (1024)
- Export estimateStrftimePaddingMemory for the date filter to charge memoryLimit
- Replace unbounded pad() concatenation loop with ch.repeat + single concat
- Add regression tests for clamping and memoryLimit on huge %width directives
Co-authored-by: Cursor <[email protected]>
* fix(date): harden strftime memory accounting and document security model
Move strftime memory charging into the same formatting path used for padding, enforce pre-allocation checks, and add regression tests for non-string date format PoCs. Add dedicated docs clarifying that memoryLimit is cooperative DoS mitigation and not strict heap isolation.
Co-authored-by: Cursor <[email protected]>
* docs(zh-cn): add security model docs for DoS limits
Add a Chinese security-model tutorial and link it from the Chinese DoS guide to clarify that memoryLimit is cooperative accounting, list uncounted custom conversion cases, and recommend avoiding fully user-defined templates in online services.
Co-authored-by: Cursor <[email protected]>
* docs: consolidate DoS docs into security-model pages
Merge DoS guidance into security-model docs in both English and Chinese, and remove the placeholder dos.md pages to avoid duplicate/redirect-only docs.
Co-authored-by: Cursor <[email protected]>
* docs: merge DoS details into security-model docs
Move the detailed parseLimit/renderLimit/memoryLimit explanations and examples into the English and Chinese security-model pages so content from the removed dos pages is preserved.
Co-authored-by: Cursor <[email protected]>
* docs: reorganize security-model structure for clarity
Restructure English and Chinese security-model docs into a consistent flow: security boundary, limits overview, per-limit details, and online service guidance.
Co-authored-by: Cursor <[email protected]>
* refactor(strftime): simplify %N width parsing logic
Use regex-backed width assumptions to simplify %N width normalization and padding memory accounting while keeping behavior equivalent.
Co-authored-by: Cursor <[email protected]>
* refactor(strftime): rely on memoryLimit for width control
Remove MAX_STRFTIME_PAD hard capping and rely on memoryLimit enforcement before padding allocation. Update strftime/date tests and security-model docs to match the new boundary and renderLimit caveats.
Co-authored-by: Cursor <[email protected]>
* fix(strftime): use add() once for padding, minimize churn
- pad(): replace per-char loop with a single add(str, ch.repeat(n)) call.
The earlier `probe[0] === ch` heuristic was wrong when ch happened to
equal a leading char of 'probe' (e.g. ch === 'p').
- strftime.ts: revert unrelated typing/structural refactors so the diff
contains only the memoryLimit threading and the %N memory charge.
- docs: rewire the deleted dos.html sidebar entry to security-model.html
(with localized labels) so the deleted page does not 404 from the
sidebar.
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
* fix: use realpath for fs.contains
* chore: reset file mode changes
Made-with: Cursor
* fix: Windows compat for contains/containsSync and toLiquidAsync arg order
Made-with: Cursor
DISCLAIMER: This may not be the proper way to approach the issue.
Although the Markdown code is proper, on the website itself it is incorrectly rendered as "{{` and `}}".
The reason for the disclaimer above is that I’m imagining this may be an issue at the content rendering level, and my fix here is just a workaround of that issue. — Given this, I’ll not be offended if this PR of mine is rejected and closed. 🙂
* feat: static variable analysis
* Accept any iterable from `children`, `arguments`, etc.
* Test analysis of standard tags
* Use `TagToken.tokenizer` instead of creating a new one
* Test analysis of netsted tags
* Group variables by their root value
* Test analysis of nested globals and locals
* Analyze included and rendered templates WIP
* Use existing tokenizer when constructing `Hash`
* Improve test coverage
* Analyze variables from `layout` and `block` tags
* Test analysis of Jekyll style includes
* Handle variables that start with a nested variable
* Async analysis
* Test non-standard tag end to end
* Implement convenience analysis methods on the `Liquid` class
* More analysis convenience methods
* Accept string or template array
* Draft static analysis docs
* Deduplicate variables names
* Fix isolated scope global variable map
* Coerce variables to strings instead of extending String
* Private map instead of extending Map
* Fix e2e test
* Tentatively implement analysis of aliased variables
* Fix nested variable segments array
* Update docs sidebar