Compare commits

...
175 Commits
Author SHA1 Message Date
semantic-release-bot 463a165e5e chore(release): 9.37.0 [skip ci]
# [9.37.0](https://github.com/harttle/liquidjs/compare/v9.36.2...v9.37.0) (2022-04-21)

### Bug Fixes

* support integer arithmetic for `divided_by`, closes [#465](https://github.com/harttle/liquidjs/issues/465) ([e69a510](https://github.com/harttle/liquidjs/commit/e69a51025efa7dec7d60d0067200a1466988ebbc))

### Features

* automatic output escaping, closes [#500](https://github.com/harttle/liquidjs/issues/500) ([f88490c](https://github.com/harttle/liquidjs/commit/f88490cd3cd0b5316c43c3ca76837544d99ce0b0))
2022-04-21 18:23:02 +00:00
Harttle f88490cd3c feat: automatic output escaping, closes #500 2022-04-22 02:19:36 +08:00
Harttle e69a51025e fix: support integer arithmetic for divided_by, closes #465 2022-04-22 02:19:36 +08:00
allcontributors[bot]andJun Yang ace5309c08 docs: update .all-contributorsrc [skip ci] 2022-04-19 23:55:10 +08:00
allcontributors[bot]andJun Yang 5a90c5bf74 docs: update README.md [skip ci] 2022-04-19 23:55:10 +08:00
semantic-release-bot f6e047867e chore(release): 9.36.2 [skip ci]
## [9.36.2](https://github.com/harttle/liquidjs/compare/v9.36.1...v9.36.2) (2022-04-19)

### Bug Fixes

* lazy createRequire to allow exceptions being catched, fixes [#497](https://github.com/harttle/liquidjs/issues/497) ([b377dad](https://github.com/harttle/liquidjs/commit/b377dad9e34c3de3e0eedc1ee6f17a0e9d919669))
2022-04-19 15:51:00 +00:00
Yahang WuandGitHub c467630e0b docs: fix a broken link for abstract file interface (#498) 2022-04-19 23:48:25 +08:00
Harttle b377dad9e3 fix: lazy createRequire to allow exceptions being catched, fixes #497 2022-04-19 23:44:14 +08:00
semantic-release-bot ecc04c99c5 chore(release): 9.36.1 [skip ci]
## [9.36.1](https://github.com/harttle/liquidjs/compare/v9.36.0...v9.36.1) (2022-04-17)

### Bug Fixes

* contains operator does not support Drop, fixes [#492](https://github.com/harttle/liquidjs/issues/492) ([9e024ff](https://github.com/harttle/liquidjs/commit/9e024ff2bcf17e7ac19c718389d4cef39b8a51f7))
* responsive header ([a56af6b](https://github.com/harttle/liquidjs/commit/a56af6bbfb5b698db55fbeb87e8e0872688fbe19))
* use `createRequire` for ESM, fixes [#334](https://github.com/harttle/liquidjs/issues/334) ([eec381e](https://github.com/harttle/liquidjs/commit/eec381ec72db3858452799b7a3264e240be3044d))
2022-04-17 16:45:54 +00:00
Harttle 9e024ff2bc fix: contains operator does not support Drop, fixes #492 2022-04-18 00:43:18 +08:00
Harttle eec381ec72 fix: use createRequire for ESM, fixes #334 2022-04-18 00:43:17 +08:00
dependabot[bot]andJun Yang c7216c6358 chore(deps): bump ansi-regex from 4.1.0 to 4.1.1 in /docs
Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-04-18 00:43:02 +08:00
dependabot[bot]andJun Yang fe78890d35 chore(deps): bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-04-17 23:54:16 +08:00
dependabot[bot]andJun Yang d5771ba42c chore(deps): bump moment from 2.24.0 to 2.29.2 in /docs
Bumps [moment](https://github.com/moment/moment) from 2.24.0 to 2.29.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.24.0...2.29.2)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-04-17 22:02:49 +08:00
dependabot[bot]andJun Yang 776d235fca chore(deps): bump async from 3.1.0 to 3.2.3
Bumps [async](https://github.com/caolan/async) from 3.1.0 to 3.2.3.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/master/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v3.1.0...v3.2.3)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-04-17 21:55:18 +08:00
Harttle a56af6bbfb fix: responsive header 2022-03-17 16:19:57 +08:00
semantic-release-bot 1af8553651 chore(release): 9.36.0 [skip ci]
# [9.36.0](https://github.com/harttle/liquidjs/compare/v9.35.2...v9.36.0) (2022-03-05)

### Features

* Access array item by negative index, closes [#486](https://github.com/harttle/liquidjs/issues/486) ([049685b](https://github.com/harttle/liquidjs/commit/049685b9a0271ba03875e24ff2f6c7870cae62a7))
* allow strip filter with specified char, closes [#390](https://github.com/harttle/liquidjs/issues/390) ([c503cb2](https://github.com/harttle/liquidjs/commit/c503cb23dfbdd6f146d6dea16a84eab3df1f7aa9))
* appropriate error for malformed filters, fixes [#271](https://github.com/harttle/liquidjs/issues/271) ([01014ed](https://github.com/harttle/liquidjs/commit/01014edc491e12d38981045442da9faee598cdf7))
2022-03-05 16:56:21 +00:00
Harttle 049685b9a0 feat: Access array item by negative index, closes #486 2022-03-06 00:52:22 +08:00
Harttle c503cb23df feat: allow strip filter with specified char, closes #390 2022-03-06 00:20:51 +08:00
Harttle 01014edc49 feat: appropriate error for malformed filters, fixes #271 2022-03-05 23:24:16 +08:00
Harttle 27e579e0e2 test: case for {% assign %} invalid value, closes #446 2022-03-05 22:09:36 +08:00
semantic-release-bot d3e3fecf53 chore(release): 9.35.2 [skip ci]
## [9.35.2](https://github.com/harttle/liquidjs/compare/v9.35.1...v9.35.2) (2022-03-02)

### Bug Fixes

* corner case for concat filter without argument, [#481](https://github.com/harttle/liquidjs/issues/481) ([aa95517](https://github.com/harttle/liquidjs/commit/aa955173d4c7adc585e862934429f1f4c5f64969))
* export all builtin tags from LiquidJS, [#464](https://github.com/harttle/liquidjs/issues/464) ([33009bb](https://github.com/harttle/liquidjs/commit/33009bb988eb74c58f390992750d91b967cb3428))
2022-03-02 13:26:07 +00:00
Harttle 33009bb988 fix: export all builtin tags from LiquidJS, #464 2022-03-02 21:21:45 +08:00
Harttle aa955173d4 fix: corner case for concat filter without argument, #481 2022-03-02 21:21:25 +08:00
semantic-release-bot 15b78ebd9d chore(release): 9.35.1 [skip ci]
## [9.35.1](https://github.com/harttle/liquidjs/compare/v9.35.0...v9.35.1) (2022-02-26)

### Bug Fixes

* some filters throw on nil input, see [#481](https://github.com/harttle/liquidjs/issues/481) ([7dfb620](https://github.com/harttle/liquidjs/commit/7dfb620d30f8818685e1cfb8e7492313a0d036ab))
2022-02-26 18:12:38 +00:00
Harttle 575f3e2338 docs: add missing tag/filter links on sidebar/table, #482 2022-02-27 02:07:59 +08:00
Harttle 7dfb620d30 fix: some filters throw on nil input, see #481 2022-02-27 02:07:59 +08:00
dependabot[bot]andJun Yang 21b78d9ba0 chore(deps): bump prismjs from 1.25.0 to 1.27.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.25.0 to 1.27.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.25.0...v1.27.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-27 02:06:04 +08:00
Harttle 5d077f461a chore: add liquid.min.js into Github release 2022-02-24 01:39:27 +08:00
semantic-release-bot 13343040c6 chore(release): 9.35.0 [skip ci]
# [9.35.0](https://github.com/harttle/liquidjs/compare/v9.34.1...v9.35.0) (2022-02-23)

### Bug Fixes

* `url_encode` throws on undefined value, fixes [#479](https://github.com/harttle/liquidjs/issues/479) ([ca3240c](https://github.com/harttle/liquidjs/commit/ca3240c2c4d157095d2ebe0024d0c71bc5e435f8))

### Features

* expose all tags/filters and TimezoneDate, closes [#464](https://github.com/harttle/liquidjs/issues/464) ([dab8a29](https://github.com/harttle/liquidjs/commit/dab8a29070b2508f2e6532717b7663966f610bec))
2022-02-23 17:20:40 +00:00
Harttle ca3240c2c4 fix: url_encode throws on undefined value, fixes #479 2022-02-24 01:14:46 +08:00
Harttle 2b0c5696bc docs: introduce JS script to escape for Hexo, fixes #480 2022-02-24 01:04:50 +08:00
Harttle dab8a29070 feat: expose all tags/filters and TimezoneDate, closes #464 2022-02-23 23:38:21 +08:00
semantic-release-bot f395295721 chore(release): 9.34.1 [skip ci]
## [9.34.1](https://github.com/harttle/liquidjs/compare/v9.34.0...v9.34.1) (2022-02-20)

### Bug Fixes

* array output now join with "" instead of "," ([ab5e245](https://github.com/harttle/liquidjs/commit/ab5e245fba9a0f6936275319d4e5e25aadb0f7c1))
* sort filter unexpectedly modifies original array, [#475](https://github.com/harttle/liquidjs/issues/475) ([dbc0497](https://github.com/harttle/liquidjs/commit/dbc049738633b1b6f578d9d20f830b548ba67a22))
2022-02-20 07:59:53 +00:00
Harttle 200f6648aa style: fix lint 2022-02-20 15:56:23 +08:00
dependabot[bot]andJun Yang 31aa4ec318 chore(deps): bump ssri from 6.0.1 to 6.0.2
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: ssri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-20 13:04:22 +08:00
dependabot[bot]andJun Yang 231574903f chore(deps): bump y18n from 3.2.1 to 3.2.2
Bumps [y18n](https://github.com/yargs/y18n) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

---
updated-dependencies:
- dependency-name: y18n
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-20 13:04:12 +08:00
Harttle dbc0497386 fix: sort filter unexpectedly modifies original array, #475 2022-02-20 13:03:40 +08:00
Harttle ab5e245fba fix: array output now join with "" instead of "," 2022-02-20 13:03:40 +08:00
dependabot[bot]andJun Yang 78ce5662df chore(deps): bump ini from 1.3.5 to 1.3.8
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

---
updated-dependencies:
- dependency-name: ini
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-20 12:53:30 +08:00
dependabot[bot]andJun Yang 8b880f65a2 chore(deps): bump hosted-git-info from 2.8.8 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-20 12:30:08 +08:00
dependabot[bot]andJun Yang d605158f96 chore(deps): bump tar from 4.4.13 to 4.4.19
Bumps [tar](https://github.com/npm/node-tar) from 4.4.13 to 4.4.19.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v4.4.13...v4.4.19)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-20 12:29:48 +08:00
dependabot[bot]andJun Yang 1a44b908ce chore(deps): bump npm-user-validate from 1.0.0 to 1.0.1
Bumps [npm-user-validate](https://github.com/npm/npm-user-validate) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/npm/npm-user-validate/releases)
- [Commits](https://github.com/npm/npm-user-validate/compare/v1.0.0...v1.0.1)

---
updated-dependencies:
- dependency-name: npm-user-validate
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-02-20 12:29:42 +08:00
Santi AlboandJun Yang a0817e5dd7 docs: fix uniq filter example in the docs 2022-02-18 19:06:01 +08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
703675e1e0 chore(deps): bump pathval from 1.1.0 to 1.1.1 (#467)
Bumps [pathval](https://github.com/chaijs/pathval) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/chaijs/pathval/releases)
- [Changelog](https://github.com/chaijs/pathval/blob/master/CHANGELOG.md)
- [Commits](https://github.com/chaijs/pathval/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: pathval
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 17:57:12 +08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
819d060a92 chore(deps): bump ajv from 6.12.0 to 6.12.6 in /docs (#468)
Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.12.0 to 6.12.6.
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.0...v6.12.6)

---
updated-dependencies:
- dependency-name: ajv
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 17:57:00 +08:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
c3d7ecbde1 docs: add santialbo as a contributor for doc (#470)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2022-02-16 17:56:46 +08:00
Jun YangandGitHub 8bdb70878f Merge pull request #469 from santialbo/patch-1
docs: fix example in main docs page
2022-02-16 17:54:10 +08:00
Santi AlboandGitHub 2e1537d50c docs: fix example in main docs page 2022-02-16 10:13:41 +01:00
HarttleandHarttle d4afbc038f docs: add support button on navbar 2022-02-13 15:12:16 +08:00
Damian NowakandGitHub 58d03890b4 docs: whitespace-control: correct typo (#462) 2022-01-29 11:50:37 +08:00
semantic-release-bot e3fb47a90b chore(release): 9.34.0 [skip ci]
# [9.34.0](https://github.com/harttle/liquidjs/compare/v9.33.1...v9.34.0) (2022-01-28)

### Bug Fixes

* where-filter null handling ([#457](https://github.com/harttle/liquidjs/issues/457)) ([9da41c8](https://github.com/harttle/liquidjs/commit/9da41c8a37d9c49ee4a16d5bd520fd6ae01c14ec))

### Features

* `ownPropertyOnly` option to protect prototype, [#454](https://github.com/harttle/liquidjs/issues/454) ([7e99efc](https://github.com/harttle/liquidjs/commit/7e99efc5131e20cf3f59e1fc2c371a15aa4109db))
2022-01-28 17:37:13 +00:00
dependabot[bot]andJun Yang e4ad93ee8c chore(deps): bump node-fetch from 2.6.1 to 2.6.7
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-01-29 01:32:26 +08:00
HarttleandHarttle 0bdf6792d1 docs: add @tbdrz as contributor 2022-01-29 01:30:48 +08:00
HarttleandHarttle 7e99efc513 feat: ownPropertyOnly option to protect prototype, #454 2022-01-29 01:22:34 +08:00
HarttleandHarttle 527858fc14 docs: better PWA, more responsive, better description 2022-01-29 00:37:43 +08:00
Martin SchusterandGitHub 9da41c8a37 fix: where-filter null handling (#457) 2022-01-28 22:43:38 +08:00
tbdrzandJun Yang 2717dae127 Clear unusefull comments 2022-01-28 22:41:11 +08:00
Harttle 8db6c7b28d docs: tutorial for render tag content 2022-01-23 14:24:58 +08:00
dependabot[bot]andJun Yang 298db97b84 chore(deps): bump shelljs from 0.8.4 to 0.8.5
Bumps [shelljs](https://github.com/shelljs/shelljs) from 0.8.4 to 0.8.5.
- [Release notes](https://github.com/shelljs/shelljs/releases)
- [Changelog](https://github.com/shelljs/shelljs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/shelljs/shelljs/compare/v0.8.4...v0.8.5)

---
updated-dependencies:
- dependency-name: shelljs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-01-23 00:02:46 +08:00
dependabot[bot]andJun Yang bd8e2b0f96 chore(deps): bump trim-off-newlines from 1.0.1 to 1.0.3
Bumps [trim-off-newlines](https://github.com/stevemao/trim-off-newlines) from 1.0.1 to 1.0.3.
- [Release notes](https://github.com/stevemao/trim-off-newlines/releases)
- [Commits](https://github.com/stevemao/trim-off-newlines/compare/v1.0.1...v1.0.3)

---
updated-dependencies:
- dependency-name: trim-off-newlines
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-01-23 00:02:32 +08:00
HarttleandHarttle 117eaf57c3 docs: add additional filters/tags as differences, closes #331 2022-01-22 23:24:06 +08:00
HarttleandHarttle 1e69d86b0c chore: build docs on master push 2022-01-22 21:59:02 +08:00
HarttleandHarttle cc6b66216d docs: support dark mode 2022-01-22 21:51:49 +08:00
HarttleandHarttle ca82416dea docs: apply network-first cache strategy 2022-01-22 19:04:12 +08:00
HarttleandHarttle 394d5a1ae2 docs: add tutorials for custom filters and tags 2022-01-22 18:52:37 +08:00
HarttleandHarttle 371da3da74 docs: add jekyllInclude to tutorials 2022-01-20 02:04:54 +08:00
semantic-release-bot 7814285479 chore(release): 9.33.1 [skip ci]
## [9.33.1](https://github.com/harttle/liquidjs/compare/v9.33.0...v9.33.1) (2022-01-19)

### Bug Fixes

* liquidjs.version on npm package ([53824a2](https://github.com/harttle/liquidjs/commit/53824a2d00f978214fcd83a48118b7900cf97449))
2022-01-19 17:19:58 +00:00
HarttleandHarttle 53824a2d00 fix: liquidjs.version on npm package 2022-01-20 01:16:52 +08:00
semantic-release-bot 9966d846b5 chore(release): 9.33.0 [skip ci]
# [9.33.0](https://github.com/harttle/liquidjs/compare/v9.32.1...v9.33.0) (2022-01-19)

### Features

* support `offset:continue`, see [#439](https://github.com/harttle/liquidjs/issues/439) ([8c27a84](https://github.com/harttle/liquidjs/commit/8c27a84059384ae730eb0fa1524df04e122e27a0))
* support Jekyll-like include syntax, see [#441](https://github.com/harttle/liquidjs/issues/441) ([388d0fb](https://github.com/harttle/liquidjs/commit/388d0fbbc42fe8cd69faba61c1dc29e9bb5ec2d0))
2022-01-19 16:56:49 +00:00
HarttleandHarttle 8c27a84059 feat: support offset:continue, see #439 2022-01-20 00:12:18 +08:00
HarttleandHarttle 388d0fbbc4 feat: support Jekyll-like include syntax, see #441 2022-01-19 23:07:25 +08:00
semantic-release-bot d71d0a0c20 chore(release): 9.32.1 [skip ci]
## [9.32.1](https://github.com/harttle/liquidjs/compare/v9.32.0...v9.32.1) (2022-01-12)

### Bug Fixes

* remove limit on operator char length ([7677f84](https://github.com/harttle/liquidjs/commit/7677f848c0c57335dd1c4f1e3ec251fbf9b1663f))
2022-01-12 13:27:40 +00:00
allcontributors[bot]andJun Yang 191a0130d2 docs: update .all-contributorsrc [skip ci] 2022-01-12 21:25:24 +08:00
allcontributors[bot]andJun Yang 2c3ebaca0c docs: update README.md [skip ci] 2022-01-12 21:25:24 +08:00
Ameya ApteandJun Yang 7677f848c0 fix: remove limit on operator char length
The matchOperator function has a default value of str.length for the end parameter
2022-01-12 21:24:08 +08:00
semantic-release-bot c7d2e1f1f4 chore(release): 9.32.0 [skip ci]
# [9.32.0](https://github.com/harttle/liquidjs/compare/v9.31.0...v9.32.0) (2022-01-02)

### Features

* support allow_false for `default` filter, see [#435](https://github.com/harttle/liquidjs/issues/435) ([c756191](https://github.com/harttle/liquidjs/commit/c756191f49f9c2b823048367abfdf0adf2bdb875))
2022-01-02 08:35:53 +00:00
HarttleandHarttle c756191f49 feat: support allow_false for default filter, see #435 2022-01-02 16:31:21 +08:00
HarttleandHarttle e94e386c46 docs: update liquidjs.com and README for demo link 2021-12-31 17:49:27 +08:00
semantic-release-bot b7c782b10a chore(release): 9.31.0 [skip ci]
# [9.31.0](https://github.com/harttle/liquidjs/compare/v9.30.0...v9.31.0) (2021-12-19)

### Features

* implement `liquid` and `echo` tags, see [#428](https://github.com/harttle/liquidjs/issues/428) ([fde9924](https://github.com/harttle/liquidjs/commit/fde9924ee622efae4c013d2aa01c6d705c8d5f46))
2021-12-19 14:35:13 +00:00
HarttleandHarttle 49d3f64873 docs: echo & liquid tags 2021-12-19 22:31:02 +08:00
HarttleandHarttle be3463c5f9 docs: add jg-rp as contributor 2021-12-19 21:42:46 +08:00
James PriorandJun Yang fde9924ee6 feat: implement liquid and echo tags, see #428 2021-12-19 21:09:26 +08:00
semantic-release-bot 5b2ea63b14 chore(release): 9.30.0 [skip ci]
# [9.30.0](https://github.com/harttle/liquidjs/compare/v9.29.0...v9.30.0) (2021-12-18)

### Features

* support jekyll-like include, see [#433](https://github.com/harttle/liquidjs/issues/433) ([23279a8](https://github.com/harttle/liquidjs/commit/23279a816a0582ade7f3b15c1c65c74bc147d134))
2021-12-18 07:31:17 +00:00
HarttleandHarttle 23279a816a feat: support jekyll-like include, see #433 2021-12-18 15:26:15 +08:00
HarttleandHarttle 2c14a9541d chore: update node to 14 for check pipeline 2021-12-12 20:10:15 +08:00
HarttleandHarttle c474649748 chore: update node to 14 on pipeline 2021-12-12 11:11:03 +08:00
HarttleandHarttle fad17cfbb3 docs: fix apidoc generation for typescript@4 2021-12-11 21:30:19 +08:00
semantic-release-bot 6322acb88c chore(release): 9.29.0 [skip ci]
# [9.29.0](https://github.com/harttle/liquidjs/compare/v9.28.6...v9.29.0) (2021-12-11)

### Features

* customize globals & strictVariables when calling render, see [#432](https://github.com/harttle/liquidjs/issues/432) ([6801552](https://github.com/harttle/liquidjs/commit/6801552fe6829770cbbfdda051731c8b466ed9ec))
2021-12-11 12:32:58 +00:00
HarttleandHarttle 95fc705b5d chore: upgrade typescript 2021-12-11 20:23:09 +08:00
HarttleandHarttle 6801552fe6 feat: customize globals & strictVariables when calling render, see #432 2021-12-11 20:22:58 +08:00
HarttleandHarttle 6023d9ba10 docs: path traversal vulnerabilities when customizing FS 2021-12-11 12:31:08 +08:00
semantic-release-bot cc4628d804 chore(release): 9.28.6 [skip ci]
## [9.28.6](https://github.com/harttle/liquidjs/compare/v9.28.5...v9.28.6) (2021-12-07)

### Bug Fixes

* size filter does not respect Objects, fixes [#385](https://github.com/harttle/liquidjs/issues/385) ([6c11426](https://github.com/harttle/liquidjs/commit/6c114267a526ef764dfd9bd94de199d2932ad91a))
* throws when using `preserveTimezones` on Node.js, fixes [#431](https://github.com/harttle/liquidjs/issues/431) ([e2ef236](https://github.com/harttle/liquidjs/commit/e2ef236f68273b72a0b1293b0d13728cdb9aa4b8))
2021-12-07 15:50:25 +00:00
HarttleandHarttle 69286c6909 test: coverage to 100% 2021-12-07 23:34:53 +08:00
HarttleandHarttle 6c114267a5 fix: size filter does not respect Objects, fixes #385 2021-12-07 23:05:46 +08:00
HarttleandHarttle e2ef236f68 fix: throws when using preserveTimezones on Node.js, fixes #431 2021-12-07 22:43:47 +08:00
semantic-release-bot 80c2280ee6 chore(release): 9.28.5 [skip ci]
## [9.28.5](https://github.com/harttle/liquidjs/compare/v9.28.4...v9.28.5) (2021-11-05)

### Bug Fixes

* always allow './' and '../' to be relative, even on windows ([44f6b52](https://github.com/harttle/liquidjs/commit/44f6b520d53ba984ecb5fc430d70f698837d1802))
2021-11-05 19:39:58 +00:00
HarttleandHarttle 44f6b520d5 fix: always allow './' and '../' to be relative, even on windows 2021-11-06 03:36:39 +08:00
semantic-release-bot 3d71d9e35a chore(release): 9.28.4 [skip ci]
## [9.28.4](https://github.com/harttle/liquidjs/compare/v9.28.3...v9.28.4) (2021-10-31)

### Bug Fixes

* allow `{%render%}` to reassign argument, [#404](https://github.com/harttle/liquidjs/issues/404) ([124f4c4](https://github.com/harttle/liquidjs/commit/124f4c4485270a5fdfca610808a56ecd98d98417))
2021-10-31 08:36:55 +00:00
AleksandrHovhannisyanandHarttle 124f4c4485 fix: allow {%render%} to reassign argument, #404 2021-10-31 16:28:33 +08:00
dependabot[bot]andJun Yang 432d1c7ccb chore(deps): bump path-parse from 1.0.6 to 1.0.7
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-10-28 00:14:13 +08:00
HarttleandHarttle 4b42e63601 docs: update liquidjs for demo/nodejs 2021-10-28 00:03:18 +08:00
semantic-release-bot f809c716eb chore(release): 9.28.3 [skip ci]
## [9.28.3](https://github.com/harttle/liquidjs/compare/v9.28.2...v9.28.3) (2021-10-27)

### Bug Fixes

* relative root (by default) yields LookupError, fixes [#419](https://github.com/harttle/liquidjs/issues/419), [#424](https://github.com/harttle/liquidjs/issues/424), also related to [#395](https://github.com/harttle/liquidjs/issues/395) ([aebeae9](https://github.com/harttle/liquidjs/commit/aebeae9e1bbb8472af7788dfd09a08cb6de58e1c))
2021-10-27 16:01:07 +00:00
HarttleandHarttle aebeae9e1b fix: relative root (by default) yields LookupError, fixes #419, #424, also related to #395 2021-10-27 23:55:39 +08:00
Harttle 564972ba74 docs: add version info in playground.html 2021-10-20 23:20:23 +08:00
semantic-release-bot d0c3cc8b47 chore(release): 9.28.2 [skip ci]
## [9.28.2](https://github.com/harttle/liquidjs/compare/v9.28.1...v9.28.2) (2021-10-16)

### Bug Fixes

* cache ongoing parseFile() calls, fixes [#416](https://github.com/harttle/liquidjs/issues/416) ([8894cbf](https://github.com/harttle/liquidjs/commit/8894cbfe6e0dbad4c07439adcefb6b3e2056be11))
2021-10-16 14:40:58 +00:00
Harttleandharttle b5b2a98d5e chore: fix types 2021-10-16 22:36:46 +08:00
Harttleandharttle 8894cbfe6e fix: cache ongoing parseFile() calls, fixes #416 2021-10-16 21:07:48 +08:00
semantic-release-bot c58a116513 chore(release): 9.28.1 [skip ci]
## [9.28.1](https://github.com/harttle/liquidjs/compare/v9.28.0...v9.28.1) (2021-10-16)

### Bug Fixes

* hardcoded '/' in normalized `options.fs`, fixes [#412](https://github.com/harttle/liquidjs/issues/412), [#408](https://github.com/harttle/liquidjs/issues/408) ([9cfa43b](https://github.com/harttle/liquidjs/commit/9cfa43b8aee6a980f39d99f1cdb2be730ca21731))
2021-10-16 04:32:51 +00:00
Harttleandharttle d4df3a0b53 refactor: make loader.shouldLoadRelative public 2021-10-16 12:30:09 +08:00
Harttleandharttle 9cfa43b8ae fix: hardcoded '/' in normalized options.fs, fixes #412, #408
Changes including:
- will not call fs.resolve when normalizing `fs`
- removed hardcoded `/`
- mandatory `fs.dirname` for relative reference
- mandatory `fs.sep`, defaults to '/'
2021-10-16 12:10:55 +08:00
harttle df6d62fd59 docs: add @JaKXz and @dphm to contributor list, #406, #407 2021-10-15 22:57:04 +08:00
d pham (they/them)andharttle 2438f4b018 docs: typo fix an -> can 2021-10-15 22:55:22 +08:00
Jason KurianandJun Yang 8321a8e982 docs: fix async/await typos in render-file 2021-10-15 22:52:47 +08:00
Harttle 1de6adf308 test: cases for parse(<tpl>, <relative filepath>), #395 2021-10-10 20:37:26 +08:00
Harttle a525f45b46 docs: update filters order on sidebar, fixes #397 2021-10-06 19:17:33 +08:00
semantic-release-bot 529e6d769b chore(release): 9.28.0 [skip ci]
# [9.28.0](https://github.com/harttle/liquidjs/compare/v9.27.1...v9.28.0) (2021-10-06)

### Bug Fixes

* skip root check for renderFile() ([822ba0b](https://github.com/harttle/liquidjs/commit/822ba0be0f1cfbedd50376aff8ac49eee71bd48c))
* support timezoneOffset for date from scope, [#401](https://github.com/harttle/liquidjs/issues/401) ([fd5ef47](https://github.com/harttle/liquidjs/commit/fd5ef474c36212e6a2446012dcd26bca93f84c7b))

### Features

* `relativeReference` for render/include/layout, [#395](https://github.com/harttle/liquidjs/issues/395) ([a3455eb](https://github.com/harttle/liquidjs/commit/a3455ebd0b207141c34630c0af44d917db2ca1dd))
* implement `forloop.name` as found in ruby shopify/liquid ([6dc7fad](https://github.com/harttle/liquidjs/commit/6dc7fada72467418806c1ee4bd7eaf3003690fe6))
2021-10-06 10:45:13 +00:00
Harttle 822ba0be0f fix: skip root check for renderFile() 2021-10-06 18:38:58 +08:00
Harttle a3455ebd0b feat: relativeReference for render/include/layout, #395
- `relativeReference` is enabled by default, set to `false` to disable
- Referenced files are still constrained within root/partias/layouts
- fix: relative filenames are not constrained (which allows arbitrary filesystem read)

Example Usage:

{% render "../foo/bar.html" %}

Note:

../foo/bar.html' should also be within `partials` (or `root` if `partials` not set)
2021-10-06 17:36:37 +08:00
Harttle 24a19c092a docs: add doc entry for concat filter #397 2021-10-06 16:10:09 +08:00
Harttle fd5ef474c3 fix: support timezoneOffset for date from scope, #401 2021-10-06 15:45:41 +08:00
Harttleandharttle 4f6b88c154 docs: add @bglw as contributor 2021-10-04 21:37:37 +08:00
Liam BigelowandJun Yang 6dc7fada72 feat: implement forloop.name as found in ruby shopify/liquid 2021-10-04 21:33:46 +08:00
semantic-release-bot 3b9c7d6fbe chore(release): 9.27.1 [skip ci]
## [9.27.1](https://github.com/harttle/liquidjs/compare/v9.27.0...v9.27.1) (2021-10-04)

### Bug Fixes

* directory info in lookupError message, [#395](https://github.com/harttle/liquidjs/issues/395) ([92bfc65](https://github.com/harttle/liquidjs/commit/92bfc65e0b1d937c00a8368b272223c702132d23))
2021-10-04 04:16:07 +00:00
Harttle 92bfc65e0b fix: directory info in lookupError message, #395 2021-10-04 12:11:54 +08:00
semantic-release-bot 8348036d45 chore(release): 9.27.0 [skip ci]
# [9.27.0](https://github.com/harttle/liquidjs/compare/v9.26.0...v9.27.0) (2021-10-03)

### Bug Fixes

* remove "stream" dependency in browser bundles, [#396](https://github.com/harttle/liquidjs/issues/396) ([3b5eb66](https://github.com/harttle/liquidjs/commit/3b5eb6664f673c29d74cb7645e01dcbdf43c8343))
* renderToNodeStream() now emit 'error' event instead of throw ([afeef1d](https://github.com/harttle/liquidjs/commit/afeef1d7450b2799b3441b0241d2466b892a27ff))

### Features

* add `layouts`, `partials` apart from `root`, [#395](https://github.com/harttle/liquidjs/issues/395) ([b9ae479](https://github.com/harttle/liquidjs/commit/b9ae479b653a34fadb98c324c4683dd1fdd31af1))
* renderFileToNodeStream(filepath, scope) ([68c4cfc](https://github.com/harttle/liquidjs/commit/68c4cfcfb647c22225dd6edede53ad7a5d7c4485))

### Performance Improvements

* make the most of streamed rendering ([aea3441](https://github.com/harttle/liquidjs/commit/aea34418de24cb85ea1acddf68c3683ce7fc9fa8))
2021-10-03 14:41:57 +00:00
harttle afeef1d745 fix: renderToNodeStream() now emit 'error' event instead of throw 2021-10-03 22:32:00 +08:00
harttle 3b5eb6664f fix: remove "stream" dependency in browser bundles, #396 2021-10-03 21:21:35 +08:00
harttle 68c4cfcfb6 feat: renderFileToNodeStream(filepath, scope) 2021-10-03 21:21:25 +08:00
harttle dd325362f9 chore: perf check, will fail if regression > 3% 2021-10-03 19:07:51 +08:00
harttle b9ae479b65 feat: add layouts, partials apart from root, #395 2021-10-03 18:51:14 +08:00
harttle 0cb520d2d1 chore: perf diff against latest release 2021-10-02 22:17:03 +08:00
Harttle 1689576913 docs: add @n1ru4l and @mattvague to contributors for doc 2021-10-01 19:21:03 +08:00
Harttleandharttle aea34418de perf: make the most of streamed rendering 2021-10-01 18:36:57 +08:00
Harttleandharttle 4358c9630f test: coverage to 100% 2021-10-01 15:55:31 +08:00
Harttleandharttle 9a96b4aba3 docs: update badges 2021-10-01 12:39:02 +08:00
Harttleandharttle 70fdb7af48 chore: try fix ci 2021-10-01 00:52:51 +08:00
semantic-release-bot 5099597634 chore(release): 9.26.0 [skip ci]
# [9.26.0](https://github.com/harttle/liquidjs/compare/v9.25.1...v9.26.0) (2021-09-30)

### Features

* orderedFilterParameters, closes [#312](https://github.com/harttle/liquidjs/issues/312) ([10e8c8f](https://github.com/harttle/liquidjs/commit/10e8c8ff7e1cca6df43087953cd8daf4bd618563))
* stream rendering, closed [#361](https://github.com/harttle/liquidjs/issues/361) fixes [#360](https://github.com/harttle/liquidjs/issues/360) ([9012133](https://github.com/harttle/liquidjs/commit/9012133e0717b1813c6a74a6a282f43ba14d0ada))
* timezoneOffset option to specify output timezone, see [#375](https://github.com/harttle/liquidjs/issues/375) ([6b9f872](https://github.com/harttle/liquidjs/commit/6b9f872bccb4b0c636dc7be2088cafa9bc6c900a))

### Performance Improvements

* improve performance by 4x by simplified parseFile ([24f5346](https://github.com/harttle/liquidjs/commit/24f534608489fccc155f30bbaf37397c46278da6))
* parse filenames in parse() insteadof render() ([8273c17](https://github.com/harttle/liquidjs/commit/8273c17dab3dc09858330ce45e3617a650e7fcaa))
2021-09-30 15:57:39 +00:00
Harttleandharttle d742de79ba docs: update docs for website 2021-09-30 23:52:26 +08:00
Harttleandharttle f0e2e07f0b docs: add @c412216887 and @labnol for docs, see #393 #394 2021-09-30 22:33:52 +08:00
一饮一啄皆是人生andJun Yang 4e5dbe120d Update upcase.md
upcase中文描述中,应该是 对已经是大写的字符没有影响
2021-09-30 22:18:10 +08:00
Amit AgarwalandJun Yang 6a1db537d2 Typo fixed
Staring -> Starring
2021-09-30 22:17:46 +08:00
dependabot[bot]andJun Yang 9517f82caf chore(deps): bump prismjs from 1.24.0 to 1.25.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.24.0 to 1.25.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.24.0...v1.25.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-09-30 22:16:34 +08:00
HarttleandJun Yang 10e8c8ff7e feat: orderedFilterParameters, closes #312 2021-09-30 22:15:09 +08:00
Steve StedmanandJun Yang fb787e8847 Fix: respect parameter order when using "for ... reversed" (#231)
* fix: spelling

* fix: respect param order for reversed

* docs: add for-reversed order details

* perf: improve performance by 4x by simplified parseFile

BREAKING CHANGES:
- previously deprecated `getTemplate()` and `getTemplateSync()` not no longer supported
- `opts` no longer support dynamic set in `parseFile()`, `renderFile()` arguments

* perf: parse filenames in parse() insteadof render()

* docs: update description of LiquidJS

Co-authored-by: harttle <[email protected]>
2021-09-30 22:15:09 +08:00
HarttleandJun Yang 9012133e07 feat: stream rendering, closed #361 fixes #360 2021-09-30 22:15:09 +08:00
harttle abaf4af465 docs: update description of LiquidJS 2021-09-30 22:15:09 +08:00
harttle 8273c17dab perf: parse filenames in parse() insteadof render() 2021-09-30 22:15:09 +08:00
harttle 24f5346084 perf: improve performance by 4x by simplified parseFile
- previously deprecated `getTemplate()` and `getTemplateSync()` not no longer supported
- `opts` no longer support dynamic set in `parseFile()`, `renderFile()` arguments
2021-09-27 23:04:41 +08:00
Harttleandharttle 6b9f872bcc feat: timezoneOffset option to specify output timezone, see #375 2021-09-27 01:54:31 +08:00
dependabot[bot]andJun Yang 91c721e650 chore(deps): bump path-parse from 1.0.6 to 1.0.7 in /docs
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-09-26 20:44:44 +08:00
dependabot[bot]andJun Yang 500d397a5a chore(deps): bump prismjs from 1.23.0 to 1.24.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.23.0 to 1.24.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.23.0...v1.24.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-07-26 16:52:01 +08:00
harttle 2e004eddf6 docs: add @ilhamdev0 as contributors 2021-07-26 16:40:03 +08:00
ilhamdev0andJun Yang e3bfe86181 Update layout.md 2021-07-25 23:19:10 +08:00
ilhamdev0andJun Yang 804947ebb9 Update layout.md
Fix typo
2021-07-25 23:19:10 +08:00
Raymond CamdenandJun Yang 4fa5313acc Update options.md
Fix typo
2021-07-24 14:23:26 +08:00
harttle f7313fe563 docs: support data field in playground.html 2021-06-20 21:26:16 +08:00
semantic-release-bot 1c64ff051e chore(release): 9.25.1 [skip ci]
## [9.25.1](https://github.com/harttle/liquidjs/compare/v9.25.0...v9.25.1) (2021-06-20)

### Performance Improvements

* add cross-engines benchmark ([cdceb25](https://github.com/harttle/liquidjs/commit/cdceb25d007b3d30a85e51ac538e12297c73bfcf))
2021-06-20 06:23:36 +00:00
harttle c470d1fe9b chore: migrate from Travis CI to Github Actions 2021-06-20 14:21:34 +08:00
harttle cdceb25d00 perf: add cross-engines benchmark 2021-06-20 13:25:08 +08:00
dependabot[bot]andJun Yang cc9b28307c chore(deps): bump striptags from 3.1.1 to 3.2.0 in /docs
Bumps [striptags](https://github.com/ericnorris/striptags) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/ericnorris/striptags/releases)
- [Commits](https://github.com/ericnorris/striptags/compare/v3.1.1...v3.2.0)

---
updated-dependencies:
- dependency-name: striptags
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-06-19 12:10:02 +08:00
dependabot[bot]andJun Yang f2ddd6e459 chore(deps): bump glob-parent from 5.1.1 to 5.1.2 in /docs
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-06-12 16:42:19 +08:00
dependabot[bot]andJun Yang ecc40a6012 chore(deps): bump normalize-url from 4.3.0 to 4.5.1
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.3.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-06-12 16:42:08 +08:00
dependabot[bot]andJun Yang 659cfde8e1 chore(deps): bump ws from 6.2.1 to 6.2.2
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2021-06-08 21:35:56 +08:00
dependabot[bot]andJun Yang 0acfb8de4d chore(deps): bump hosted-git-info from 2.7.1 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.7.1 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.7.1...v2.8.9)

Signed-off-by: dependabot[bot] <[email protected]>
2021-05-09 20:04:52 +08:00
dependabot[bot]andJun Yang c4b2bfb29b chore(deps): bump lodash from 4.17.19 to 4.17.21 in /docs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <[email protected]>
2021-05-07 22:36:25 +08:00
semantic-release-bot 0d41f7467e chore(release): 9.25.0 [skip ci]
# [9.25.0](https://github.com/harttle/liquidjs/compare/v9.24.2...v9.25.0) (2021-05-07)

### Features

* when tag with multiple values ([8f9639f](https://github.com/harttle/liquidjs/commit/8f9639f))
2021-05-07 06:03:44 +00:00
dependabot[bot]andJun Yang 1d35e3fcfb chore(deps): bump handlebars from 4.5.3 to 4.7.7
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.5.3 to 4.7.7.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.5.3...v4.7.7)

Signed-off-by: dependabot[bot] <[email protected]>
2021-05-07 14:00:30 +08:00
dependabot[bot]andJun Yang 04c874b174 chore(deps): bump underscore from 1.9.1 to 1.13.1
Bumps [underscore](https://github.com/jashkenas/underscore) from 1.9.1 to 1.13.1.
- [Release notes](https://github.com/jashkenas/underscore/releases)
- [Commits](https://github.com/jashkenas/underscore/compare/1.9.1...1.13.1)

Signed-off-by: dependabot[bot] <[email protected]>
2021-05-07 14:00:01 +08:00
allcontributors[bot]andJun Yang 29f42847a5 docs: update .all-contributorsrc [skip ci] 2021-05-06 22:53:24 +08:00
allcontributors[bot]andJun Yang 426863a9b4 docs: update README.md [skip ci] 2021-05-06 22:53:24 +08:00
Memmie LengletandJun Yang 8f9639f1d6 feat: when tag with multiple values 2021-05-06 22:52:22 +08:00
semantic-release-bot 3e130e01a7 chore(release): 9.24.2 [skip ci]
## [9.24.2](https://github.com/harttle/liquidjs/compare/v9.24.1...v9.24.2) (2021-05-04)

### Bug Fixes

* operator boundary not correctly recognized, fixes [#342](https://github.com/harttle/liquidjs/issues/342) ([3e3d84a](https://github.com/harttle/liquidjs/commit/3e3d84a))
2021-05-04 10:16:44 +00:00
Jun Yang 3e3d84a5ed fix: operator boundary not correctly recognized, fixes #342 2021-05-04 18:13:02 +08:00
dependabot[bot]andJun Yang 69f1a394b1 chore(deps): bump ssri from 6.0.1 to 6.0.2
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

Signed-off-by: dependabot[bot] <[email protected]>
2021-05-02 15:28:15 +08:00
249 changed files with 18406 additions and 8167 deletions
+135
View File
@@ -360,6 +360,141 @@
"contributions": [
"doc"
]
},
{
"login": "mems",
"name": "Memmie Lenglet",
"avatar_url": "https://avatars.githubusercontent.com/u/729275?v=4",
"profile": "https://memmie.lenglet.name",
"contributions": [
"code"
]
},
{
"login": "ilhamdev0",
"name": "ilhamdev0",
"avatar_url": "https://avatars.githubusercontent.com/u/57636145?v=4",
"profile": "https://github.com/ilhamdev0",
"contributions": [
"doc"
]
},
{
"login": "c412216887",
"name": "一饮一啄皆是人生",
"avatar_url": "https://avatars.githubusercontent.com/u/29691650?v=4",
"profile": "https://github.com/c412216887",
"contributions": [
"doc"
]
},
{
"login": "labnol",
"name": "Amit Agarwal",
"avatar_url": "https://avatars.githubusercontent.com/u/1344071?v=4",
"profile": "https://digitalinspiration.com/",
"contributions": [
"doc"
]
},
{
"login": "n1ru4l",
"name": "Laurin Quast",
"avatar_url": "https://avatars.githubusercontent.com/u/14338007?v=4",
"profile": "https://n1ru4l.cloud/",
"contributions": [
"code"
]
},
{
"login": "mattvague",
"name": "Matt Vague",
"avatar_url": "https://avatars.githubusercontent.com/u/64985?v=4",
"profile": "https://github.com/mattvague",
"contributions": [
"code"
]
},
{
"login": "bglw",
"name": "Liam Bigelow",
"avatar_url": "https://avatars.githubusercontent.com/u/40188355?v=4",
"profile": "https://github.com/bglw",
"contributions": [
"code"
]
},
{
"login": "JaKXz",
"name": "Jason Kurian",
"avatar_url": "https://avatars.githubusercontent.com/u/2642545?v=4",
"profile": "https://about.me/jasonkurian",
"contributions": [
"doc"
]
},
{
"login": "dphm",
"name": "d pham (they/them)",
"avatar_url": "https://avatars.githubusercontent.com/u/1707217?v=4",
"profile": "https://github.com/dphm",
"contributions": [
"doc"
]
},
{
"login": "AleksandrHovhannisyan",
"name": "Aleksandr Hovhannisyan",
"avatar_url": "https://avatars.githubusercontent.com/u/19352442?v=4",
"profile": "https://www.aleksandrhovhannisyan.com/",
"contributions": [
"code"
]
},
{
"login": "jg-rp",
"name": "jg-rp",
"avatar_url": "https://avatars.githubusercontent.com/u/72664870?v=4",
"profile": "https://github.com/jg-rp",
"contributions": [
"code"
]
},
{
"login": "ameyaapte1",
"name": "Ameya Apte",
"avatar_url": "https://avatars.githubusercontent.com/u/16054747?v=4",
"profile": "https://github.com/ameyaapte1",
"contributions": [
"code"
]
},
{
"login": "tbdrz",
"name": "tbdrz",
"avatar_url": "https://avatars.githubusercontent.com/u/50599116?v=4",
"profile": "https://github.com/tbdrz",
"contributions": [
"doc"
]
},
{
"login": "santialbo",
"name": "Santi Albo",
"avatar_url": "https://avatars.githubusercontent.com/u/1557563?v=4",
"profile": "http://santialbo.com",
"contributions": [
"doc"
]
},
{
"login": "YahangWu",
"name": "Yahang Wu",
"avatar_url": "https://avatars.githubusercontent.com/u/12295975?v=4",
"profile": "https://github.com/YahangWu",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7,
+30
View File
@@ -0,0 +1,30 @@
name: Check
on: [push, pull_request]
jobs:
release:
name: Check
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build
run: |
npm ci
npm run build
- name: Test
run: |
npm run lint
npm run test
- name: Coverage
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Performance
run: |
npm run perf:diff
+27
View File
@@ -0,0 +1,27 @@
name: Docs
on:
push:
branches:
- master
jobs:
docs:
name: Docs
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build
run: |
npm ci
npm run build:docs
- name: Publish
uses: JamesIves/[email protected]
with:
branch: gh-pages
folder: docs/public
+32
View File
@@ -0,0 +1,32 @@
name: Release
on: workflow_dispatch
jobs:
release:
name: Release
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build
run: |
npm ci
npm run build:dist
- name: Test
run: |
npm run lint
npm run test
- name: Coverage
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
require: "ts-node/register/transpile-only",
reporter: "spec"
}
+4
View File
@@ -0,0 +1,4 @@
{
"exclude": ["dist", "test"],
"reporter": ["html", "lcov"]
}
-28
View File
@@ -1,28 +0,0 @@
language: node_js
node_js:
- "10"
- "8"
jobs:
include:
- stage: test
name: 'Linting'
script:
- npm run lint
- name: 'Coverage'
script: npm run coverage-coveralls
- stage: release
name: 'Publish'
if: branch = master
script: npm run build
deploy:
provider: script
skip_cleanup: true
script: npx semantic-release
- name: 'Document'
if: branch = master
script: npm run build-docs
deploy:
skip_cleanup: true
provider: pages
github_token: $GH_TOKEN
local_dir: docs/public
+253
View File
@@ -1,3 +1,256 @@
# [9.37.0](https://github.com/harttle/liquidjs/compare/v9.36.2...v9.37.0) (2022-04-21)
### Bug Fixes
* support integer arithmetic for `divided_by`, closes [#465](https://github.com/harttle/liquidjs/issues/465) ([e69a510](https://github.com/harttle/liquidjs/commit/e69a51025efa7dec7d60d0067200a1466988ebbc))
### Features
* automatic output escaping, closes [#500](https://github.com/harttle/liquidjs/issues/500) ([f88490c](https://github.com/harttle/liquidjs/commit/f88490cd3cd0b5316c43c3ca76837544d99ce0b0))
## [9.36.2](https://github.com/harttle/liquidjs/compare/v9.36.1...v9.36.2) (2022-04-19)
### Bug Fixes
* lazy createRequire to allow exceptions being catched, fixes [#497](https://github.com/harttle/liquidjs/issues/497) ([b377dad](https://github.com/harttle/liquidjs/commit/b377dad9e34c3de3e0eedc1ee6f17a0e9d919669))
## [9.36.1](https://github.com/harttle/liquidjs/compare/v9.36.0...v9.36.1) (2022-04-17)
### Bug Fixes
* contains operator does not support Drop, fixes [#492](https://github.com/harttle/liquidjs/issues/492) ([9e024ff](https://github.com/harttle/liquidjs/commit/9e024ff2bcf17e7ac19c718389d4cef39b8a51f7))
* responsive header ([a56af6b](https://github.com/harttle/liquidjs/commit/a56af6bbfb5b698db55fbeb87e8e0872688fbe19))
* use `createRequire` for ESM, fixes [#334](https://github.com/harttle/liquidjs/issues/334) ([eec381e](https://github.com/harttle/liquidjs/commit/eec381ec72db3858452799b7a3264e240be3044d))
# [9.36.0](https://github.com/harttle/liquidjs/compare/v9.35.2...v9.36.0) (2022-03-05)
### Features
* Access array item by negative index, closes [#486](https://github.com/harttle/liquidjs/issues/486) ([049685b](https://github.com/harttle/liquidjs/commit/049685b9a0271ba03875e24ff2f6c7870cae62a7))
* allow strip filter with specified char, closes [#390](https://github.com/harttle/liquidjs/issues/390) ([c503cb2](https://github.com/harttle/liquidjs/commit/c503cb23dfbdd6f146d6dea16a84eab3df1f7aa9))
* appropriate error for malformed filters, fixes [#271](https://github.com/harttle/liquidjs/issues/271) ([01014ed](https://github.com/harttle/liquidjs/commit/01014edc491e12d38981045442da9faee598cdf7))
## [9.35.2](https://github.com/harttle/liquidjs/compare/v9.35.1...v9.35.2) (2022-03-02)
### Bug Fixes
* corner case for concat filter without argument, [#481](https://github.com/harttle/liquidjs/issues/481) ([aa95517](https://github.com/harttle/liquidjs/commit/aa955173d4c7adc585e862934429f1f4c5f64969))
* export all builtin tags from LiquidJS, [#464](https://github.com/harttle/liquidjs/issues/464) ([33009bb](https://github.com/harttle/liquidjs/commit/33009bb988eb74c58f390992750d91b967cb3428))
## [9.35.1](https://github.com/harttle/liquidjs/compare/v9.35.0...v9.35.1) (2022-02-26)
### Bug Fixes
* some filters throw on nil input, see [#481](https://github.com/harttle/liquidjs/issues/481) ([7dfb620](https://github.com/harttle/liquidjs/commit/7dfb620d30f8818685e1cfb8e7492313a0d036ab))
# [9.35.0](https://github.com/harttle/liquidjs/compare/v9.34.1...v9.35.0) (2022-02-23)
### Bug Fixes
* `url_encode` throws on undefined value, fixes [#479](https://github.com/harttle/liquidjs/issues/479) ([ca3240c](https://github.com/harttle/liquidjs/commit/ca3240c2c4d157095d2ebe0024d0c71bc5e435f8))
### Features
* expose all tags/filters and TimezoneDate, closes [#464](https://github.com/harttle/liquidjs/issues/464) ([dab8a29](https://github.com/harttle/liquidjs/commit/dab8a29070b2508f2e6532717b7663966f610bec))
## [9.34.1](https://github.com/harttle/liquidjs/compare/v9.34.0...v9.34.1) (2022-02-20)
### Bug Fixes
* array output now join with "" instead of "," ([ab5e245](https://github.com/harttle/liquidjs/commit/ab5e245fba9a0f6936275319d4e5e25aadb0f7c1))
* sort filter unexpectedly modifies original array, [#475](https://github.com/harttle/liquidjs/issues/475) ([dbc0497](https://github.com/harttle/liquidjs/commit/dbc049738633b1b6f578d9d20f830b548ba67a22))
# [9.34.0](https://github.com/harttle/liquidjs/compare/v9.33.1...v9.34.0) (2022-01-28)
### Bug Fixes
* where-filter null handling ([#457](https://github.com/harttle/liquidjs/issues/457)) ([9da41c8](https://github.com/harttle/liquidjs/commit/9da41c8a37d9c49ee4a16d5bd520fd6ae01c14ec))
### Features
* `ownPropertyOnly` option to protect prototype, [#454](https://github.com/harttle/liquidjs/issues/454) ([7e99efc](https://github.com/harttle/liquidjs/commit/7e99efc5131e20cf3f59e1fc2c371a15aa4109db))
## [9.33.1](https://github.com/harttle/liquidjs/compare/v9.33.0...v9.33.1) (2022-01-19)
### Bug Fixes
* liquidjs.version on npm package ([53824a2](https://github.com/harttle/liquidjs/commit/53824a2d00f978214fcd83a48118b7900cf97449))
# [9.33.0](https://github.com/harttle/liquidjs/compare/v9.32.1...v9.33.0) (2022-01-19)
### Features
* support `offset:continue`, see [#439](https://github.com/harttle/liquidjs/issues/439) ([8c27a84](https://github.com/harttle/liquidjs/commit/8c27a84059384ae730eb0fa1524df04e122e27a0))
* support Jekyll-like include syntax, see [#441](https://github.com/harttle/liquidjs/issues/441) ([388d0fb](https://github.com/harttle/liquidjs/commit/388d0fbbc42fe8cd69faba61c1dc29e9bb5ec2d0))
## [9.32.1](https://github.com/harttle/liquidjs/compare/v9.32.0...v9.32.1) (2022-01-12)
### Bug Fixes
* remove limit on operator char length ([7677f84](https://github.com/harttle/liquidjs/commit/7677f848c0c57335dd1c4f1e3ec251fbf9b1663f))
# [9.32.0](https://github.com/harttle/liquidjs/compare/v9.31.0...v9.32.0) (2022-01-02)
### Features
* support allow_false for `default` filter, see [#435](https://github.com/harttle/liquidjs/issues/435) ([c756191](https://github.com/harttle/liquidjs/commit/c756191f49f9c2b823048367abfdf0adf2bdb875))
# [9.31.0](https://github.com/harttle/liquidjs/compare/v9.30.0...v9.31.0) (2021-12-19)
### Features
* implement `liquid` and `echo` tags, see [#428](https://github.com/harttle/liquidjs/issues/428) ([fde9924](https://github.com/harttle/liquidjs/commit/fde9924ee622efae4c013d2aa01c6d705c8d5f46))
# [9.30.0](https://github.com/harttle/liquidjs/compare/v9.29.0...v9.30.0) (2021-12-18)
### Features
* support jekyll-like include, see [#433](https://github.com/harttle/liquidjs/issues/433) ([23279a8](https://github.com/harttle/liquidjs/commit/23279a816a0582ade7f3b15c1c65c74bc147d134))
# [9.29.0](https://github.com/harttle/liquidjs/compare/v9.28.6...v9.29.0) (2021-12-11)
### Features
* customize globals & strictVariables when calling render, see [#432](https://github.com/harttle/liquidjs/issues/432) ([6801552](https://github.com/harttle/liquidjs/commit/6801552fe6829770cbbfdda051731c8b466ed9ec))
## [9.28.6](https://github.com/harttle/liquidjs/compare/v9.28.5...v9.28.6) (2021-12-07)
### Bug Fixes
* size filter does not respect Objects, fixes [#385](https://github.com/harttle/liquidjs/issues/385) ([6c11426](https://github.com/harttle/liquidjs/commit/6c114267a526ef764dfd9bd94de199d2932ad91a))
* throws when using `preserveTimezones` on Node.js, fixes [#431](https://github.com/harttle/liquidjs/issues/431) ([e2ef236](https://github.com/harttle/liquidjs/commit/e2ef236f68273b72a0b1293b0d13728cdb9aa4b8))
## [9.28.5](https://github.com/harttle/liquidjs/compare/v9.28.4...v9.28.5) (2021-11-05)
### Bug Fixes
* always allow './' and '../' to be relative, even on windows ([44f6b52](https://github.com/harttle/liquidjs/commit/44f6b520d53ba984ecb5fc430d70f698837d1802))
## [9.28.4](https://github.com/harttle/liquidjs/compare/v9.28.3...v9.28.4) (2021-10-31)
### Bug Fixes
* allow `{%render%}` to reassign argument, [#404](https://github.com/harttle/liquidjs/issues/404) ([124f4c4](https://github.com/harttle/liquidjs/commit/124f4c4485270a5fdfca610808a56ecd98d98417))
## [9.28.3](https://github.com/harttle/liquidjs/compare/v9.28.2...v9.28.3) (2021-10-27)
### Bug Fixes
* relative root (by default) yields LookupError, fixes [#419](https://github.com/harttle/liquidjs/issues/419), [#424](https://github.com/harttle/liquidjs/issues/424), also related to [#395](https://github.com/harttle/liquidjs/issues/395) ([aebeae9](https://github.com/harttle/liquidjs/commit/aebeae9e1bbb8472af7788dfd09a08cb6de58e1c))
## [9.28.2](https://github.com/harttle/liquidjs/compare/v9.28.1...v9.28.2) (2021-10-16)
### Bug Fixes
* cache ongoing parseFile() calls, fixes [#416](https://github.com/harttle/liquidjs/issues/416) ([8894cbf](https://github.com/harttle/liquidjs/commit/8894cbfe6e0dbad4c07439adcefb6b3e2056be11))
## [9.28.1](https://github.com/harttle/liquidjs/compare/v9.28.0...v9.28.1) (2021-10-16)
### Bug Fixes
* hardcoded '/' in normalized `options.fs`, fixes [#412](https://github.com/harttle/liquidjs/issues/412), [#408](https://github.com/harttle/liquidjs/issues/408) ([9cfa43b](https://github.com/harttle/liquidjs/commit/9cfa43b8aee6a980f39d99f1cdb2be730ca21731))
# [9.28.0](https://github.com/harttle/liquidjs/compare/v9.27.1...v9.28.0) (2021-10-06)
### Bug Fixes
* skip root check for renderFile() ([822ba0b](https://github.com/harttle/liquidjs/commit/822ba0be0f1cfbedd50376aff8ac49eee71bd48c))
* support timezoneOffset for date from scope, [#401](https://github.com/harttle/liquidjs/issues/401) ([fd5ef47](https://github.com/harttle/liquidjs/commit/fd5ef474c36212e6a2446012dcd26bca93f84c7b))
### Features
* `relativeReference` for render/include/layout, [#395](https://github.com/harttle/liquidjs/issues/395) ([a3455eb](https://github.com/harttle/liquidjs/commit/a3455ebd0b207141c34630c0af44d917db2ca1dd))
* implement `forloop.name` as found in ruby shopify/liquid ([6dc7fad](https://github.com/harttle/liquidjs/commit/6dc7fada72467418806c1ee4bd7eaf3003690fe6))
## [9.27.1](https://github.com/harttle/liquidjs/compare/v9.27.0...v9.27.1) (2021-10-04)
### Bug Fixes
* directory info in lookupError message, [#395](https://github.com/harttle/liquidjs/issues/395) ([92bfc65](https://github.com/harttle/liquidjs/commit/92bfc65e0b1d937c00a8368b272223c702132d23))
# [9.27.0](https://github.com/harttle/liquidjs/compare/v9.26.0...v9.27.0) (2021-10-03)
### Bug Fixes
* remove "stream" dependency in browser bundles, [#396](https://github.com/harttle/liquidjs/issues/396) ([3b5eb66](https://github.com/harttle/liquidjs/commit/3b5eb6664f673c29d74cb7645e01dcbdf43c8343))
* renderToNodeStream() now emit 'error' event instead of throw ([afeef1d](https://github.com/harttle/liquidjs/commit/afeef1d7450b2799b3441b0241d2466b892a27ff))
### Features
* add `layouts`, `partials` apart from `root`, [#395](https://github.com/harttle/liquidjs/issues/395) ([b9ae479](https://github.com/harttle/liquidjs/commit/b9ae479b653a34fadb98c324c4683dd1fdd31af1))
* renderFileToNodeStream(filepath, scope) ([68c4cfc](https://github.com/harttle/liquidjs/commit/68c4cfcfb647c22225dd6edede53ad7a5d7c4485))
### Performance Improvements
* make the most of streamed rendering ([aea3441](https://github.com/harttle/liquidjs/commit/aea34418de24cb85ea1acddf68c3683ce7fc9fa8))
# [9.26.0](https://github.com/harttle/liquidjs/compare/v9.25.1...v9.26.0) (2021-09-30)
### Features
* orderedFilterParameters, closes [#312](https://github.com/harttle/liquidjs/issues/312) ([10e8c8f](https://github.com/harttle/liquidjs/commit/10e8c8ff7e1cca6df43087953cd8daf4bd618563))
* stream rendering, closed [#361](https://github.com/harttle/liquidjs/issues/361) fixes [#360](https://github.com/harttle/liquidjs/issues/360) ([9012133](https://github.com/harttle/liquidjs/commit/9012133e0717b1813c6a74a6a282f43ba14d0ada))
* timezoneOffset option to specify output timezone, see [#375](https://github.com/harttle/liquidjs/issues/375) ([6b9f872](https://github.com/harttle/liquidjs/commit/6b9f872bccb4b0c636dc7be2088cafa9bc6c900a))
### Performance Improvements
* improve performance by 4x by simplified parseFile ([24f5346](https://github.com/harttle/liquidjs/commit/24f534608489fccc155f30bbaf37397c46278da6))
* parse filenames in parse() insteadof render() ([8273c17](https://github.com/harttle/liquidjs/commit/8273c17dab3dc09858330ce45e3617a650e7fcaa))
## [9.25.1](https://github.com/harttle/liquidjs/compare/v9.25.0...v9.25.1) (2021-06-20)
### Performance Improvements
* add cross-engines benchmark ([cdceb25](https://github.com/harttle/liquidjs/commit/cdceb25d007b3d30a85e51ac538e12297c73bfcf))
# [9.25.0](https://github.com/harttle/liquidjs/compare/v9.24.2...v9.25.0) (2021-05-07)
### Features
* when tag with multiple values ([8f9639f](https://github.com/harttle/liquidjs/commit/8f9639f))
## [9.24.2](https://github.com/harttle/liquidjs/compare/v9.24.1...v9.24.2) (2021-05-04)
### Bug Fixes
* operator boundary not correctly recognized, fixes [#342](https://github.com/harttle/liquidjs/issues/342) ([3e3d84a](https://github.com/harttle/liquidjs/commit/3e3d84a))
## [9.24.1](https://github.com/harttle/liquidjs/compare/v9.24.0...v9.24.1) (2021-05-01)
+49 -16
View File
@@ -1,18 +1,12 @@
# liquidjs
[![npm version](https://img.shields.io/npm/v/liquidjs.svg)](https://www.npmjs.org/package/liquidjs)
[![npm downloads](https://img.shields.io/npm/dm/liquidjs.svg)](https://www.npmjs.org/package/liquidjs)
[![coveralls coverage](https://img.shields.io/coveralls/harttle/liquidjs.svg)](https://coveralls.io/github/harttle/liquidjs?branch=master)
[![travis Build Status](https://travis-ci.org/harttle/liquidjs.svg?branch=master)](https://travis-ci.org/harttle/liquidjs)
[![GitHub issues](https://img.shields.io/github/issues-closed/harttle/liquidjs.svg)](https://github.com/harttle/liquidjs/issues)
[![GitHub contributors](https://img.shields.io/github/contributors/harttle/liquidjs.svg)](https://github.com/harttle/liquidjs/graphs/contributors)
[![Open Collective contributors](https://img.shields.io/opencollective/all/liquidjs)](https://opencollective.com/liquidjs)
[![David dependencies](https://img.shields.io/david/harttle/liquidjs.svg)](https://david-dm.org/harttle/liquidjs)
[![David devDependencies](https://img.shields.io/david/dev/harttle/liquidjs.svg)](https://david-dm.org/harttle/liquidjs?type=dev)
[![DUB license](https://img.shields.io/dub/l/vibe-d.svg)](https://github.com/harttle/liquidjs/blob/master/LICENSE)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/harttle/liquidjs)
[![npm version](https://img.shields.io/npm/v/liquidjs.svg?logo=npm&style=flat-square)](https://www.npmjs.org/package/liquidjs)
[![npm downloads](https://img.shields.io/npm/dm/liquidjs.svg?style=flat-square)](https://www.npmjs.org/package/liquidjs)
[![Coverage](https://img.shields.io/coveralls/harttle/liquidjs.svg?style=flat-square)](https://coveralls.io/github/harttle/liquidjs?branch=master)
[![Build Status](https://img.shields.io/github/workflow/status/harttle/liquidjs/Check/master.svg?style=flat-square)](https://github.com/harttle/liquidjs/actions/workflows/check.yml?query=branch%3Amaster)
[![DUB license](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](https://github.com/harttle/liquidjs/blob/master/LICENSE)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/harttle/liquidjs)
A simple, expressive, safe and [Shopify][shopify/liquid] compatible template engine in pure JavaScript.
A simple, expressive and safe [Shopify][shopify/liquid] / Github Pages compatible template engine in pure JavaScript.
**The purpose of this repo** is to provide a standard Liquid implementation for the JavaScript community so that [Jekyll sites](https://jekyllrb.com), [Github Pages](https://pages.github.com/) and [Shopify templates](https://themes.shopify.com/) can be ported to Node.js without pain.
* [Documentation][doc]
@@ -21,12 +15,25 @@ A simple, expressive, safe and [Shopify][shopify/liquid] compatible template eng
<p align="center"><a href="https://liquidjs.com"><img height="155px" width="155px" src="https://liquidjs.com/icon/mstile-310x310.png" alt="logo"></a></p>
## What's it like?
Basically there're two types of Liquid syntax: tags enclosed by `{% %}` and outputs enclosed by `{{ }}`. A Liquid template looks like:
```liquid
{% if username %}
{{ username | append: ", welcome to LiquidJS!" | capitalize }}
{% endif %}
```
[A live demo](https://liquidjs.com/playground.html) is also available and here's a [quick tutorial](https://liquidjs.com/tutorials/intro-to-liquid.html) for Liquid syntax.
## Installation
Install from npm in Node.js:
```bash
npm install --save liquidjs
npm install liquidjs
```
Or use the UMD bundle from jsDelivr:
@@ -44,12 +51,19 @@ More details, refer to [The Setup Guide][setup].
* [react-liquid](https://github.com/aquibm/react-liquid#readme): Liquid templating language component for React
* [@11ty/eleventy](https://www.npmjs.com/package/@11ty/eleventy): A simpler static site generator. An alternative to Jekyll. Written in JavaScript. Transforms a directory of templates (of varying types) into HTML.
## Backers
## Financial Support
If you love LiquidJS or your company is using LiquidJS? Please consider [support us on Open Collective or Patreon][financial-support].
![backers from open-collective](https://opencollective.com/liquidjs/tiers/backer.svg?avatarHeight=97)
### Backers
If you personally like LiquidJS and find it's useful to you, you can become a backer!
<object type="image/svg+xml" data="https://opencollective.com/liquidjs/backers.svg?avatarHeight=72"></object>
### Sponsors
If LiquidJS is benefiting your business/company, please sponsor us to make it better!
<object type="image/svg+xml" data="https://opencollective.com/liquidjs/sponsors.svg?avatarHeight=72"></object>
## Contributors ✨
Want to contribute? see [Contribution Guidelines][contribution]. Thanks goes to these wonderful people:
@@ -107,6 +121,25 @@ Want to contribute? see [Contribution Guidelines][contribution]. Thanks goes to
<td align="center"><a href="https://github.com/Pixcell"><img src="https://avatars0.githubusercontent.com/u/4005291?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pixcell</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=Pixcell" title="Code">💻</a></td>
<td align="center"><a href="https://jasonet.co"><img src="https://avatars.githubusercontent.com/u/10660468?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jason Etcovitch</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=JasonEtco" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kayuapi"><img src="https://avatars.githubusercontent.com/u/10304328?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ZC</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=kayuapi" title="Documentation">📖</a></td>
<td align="center"><a href="https://memmie.lenglet.name"><img src="https://avatars.githubusercontent.com/u/729275?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Memmie Lenglet</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=mems" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ilhamdev0"><img src="https://avatars.githubusercontent.com/u/57636145?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ilhamdev0</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=ilhamdev0" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/c412216887"><img src="https://avatars.githubusercontent.com/u/29691650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>一饮一啄皆是人生</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=c412216887" title="Documentation">📖</a></td>
<td align="center"><a href="https://digitalinspiration.com/"><img src="https://avatars.githubusercontent.com/u/1344071?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Agarwal</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=labnol" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://n1ru4l.cloud/"><img src="https://avatars.githubusercontent.com/u/14338007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Laurin Quast</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=n1ru4l" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/mattvague"><img src="https://avatars.githubusercontent.com/u/64985?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Vague</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=mattvague" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/bglw"><img src="https://avatars.githubusercontent.com/u/40188355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Liam Bigelow</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=bglw" title="Code">💻</a></td>
<td align="center"><a href="https://about.me/jasonkurian"><img src="https://avatars.githubusercontent.com/u/2642545?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jason Kurian</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=JaKXz" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dphm"><img src="https://avatars.githubusercontent.com/u/1707217?v=4?s=100" width="100px;" alt=""/><br /><sub><b>d pham (they/them)</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=dphm" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.aleksandrhovhannisyan.com/"><img src="https://avatars.githubusercontent.com/u/19352442?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandr Hovhannisyan</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=AleksandrHovhannisyan" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jg-rp"><img src="https://avatars.githubusercontent.com/u/72664870?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jg-rp</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=jg-rp" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ameyaapte1"><img src="https://avatars.githubusercontent.com/u/16054747?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ameya Apte</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=ameyaapte1" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/tbdrz"><img src="https://avatars.githubusercontent.com/u/50599116?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tbdrz</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=tbdrz" title="Documentation">📖</a></td>
<td align="center"><a href="http://santialbo.com"><img src="https://avatars.githubusercontent.com/u/1557563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Santi Albo</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=santialbo" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/YahangWu"><img src="https://avatars.githubusercontent.com/u/12295975?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yahang Wu</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=YahangWu" title="Documentation">📖</a></td>
</tr>
</table>
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env node
const Benchmark = require('benchmark')
const data = require('./data/todolist.json')
const path = require('path')
const engines = {
handlebars: require('./engines/handlebars'),
liquid: require('./engines/liquid'),
react: require('./engines/react'),
swig: require('./engines/swig')
}
function crossEngines () {
console.log(' cross engines')
console.log('------------------------')
return new Promise(resolve => {
const suit = new Benchmark.Suite('cross engines')
for (const [name, { load, render }] of Object.entries(engines)) {
const tpl = load(path.resolve(__dirname, `templates/todolist`))
suit.add(name, () => render(tpl, data))
}
suit.on('cycle', event => console.log(String(event.target)))
suit.on('complete', resolve)
suit.run({ async: true })
})
}
module.exports = { crossEngines }
+28
View File
@@ -0,0 +1,28 @@
{
"categories": [{
"color": "red",
"id": "CAT1",
"title": "work"
}, {
"color": "red",
"id": "CAT2",
"title": "emergency"
}, {
"color": "green",
"id": "CAT3",
"title": "sport"
}],
"todos": [{
"title": "fork and clone",
"id": "TODO1",
"category": "work"
}, {
"title": "make it better",
"id": "TODO2",
"category": "sport"
}, {
"title": "make a pull request",
"id": "TODO3",
"category": "work"
}]
}
Regular → Executable
+6 -18
View File
@@ -1,8 +1,10 @@
const Benchmark = require('benchmark')
const { Liquid } = require('..')
const ctx = require('./data/todolist.json')
const { resolve } = require('path')
const engine = new Liquid({
root: __dirname,
root: resolve(__dirname, 'templates'),
extname: '.liquid'
})
@@ -17,28 +19,14 @@ engine.registerTag('header', {
}
})
const ctx = {
todos: ['fork and clone', 'make it better', 'make a pull request'],
title: 'Welcome to liquidjs!'
}
const template = `
{%header content: "welcome to liquid" | capitalize%}
<ul>
{% for todo in todos %}
<li>{{forloop.index}} - {{todo}}</li>
{% endfor %}
</ul>
`
function demo () {
console.log('--- demo ---')
console.log(' demo')
console.log('------------------------')
return new Promise(resolve => {
new Benchmark.Suite('demo')
.add('demo', {
defer: true,
fn: d => engine.parseAndRender(template, ctx).then(x => d.resolve(x))
fn: d => engine.renderFile('todolist', ctx).then(x => d.resolve(x))
})
.on('cycle', event => console.log(String(event.target)))
.on('complete', resolve)
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env node
const { performance } = require('perf_hooks')
const path = require('path')
const FILE_LOCAL = process.argv[2]
const FILE_LATEST = process.argv[3]
console.log(`Local: ${FILE_LOCAL}`)
console.log(`Latest: ${FILE_LATEST}`)
const { createEngine } = require('./engines/create-liquid')
const local = createEngine(require(path.resolve(__dirname, '..', FILE_LOCAL)))
const latest = createEngine(require(path.resolve(__dirname, '..', FILE_LOCAL)))
const data = require('./data/todolist.json')
const tpl = path.resolve(__dirname, `templates/todolist`)
const begin = performance.now()
const tplLocal = local.load(tpl)
const tplLatest = latest.load(tpl)
const tasks = [
{
cycles: 0,
time: 0,
fn: () => latest.render(tplLatest, data)
},
{
cycles: 0,
time: 0,
fn: () => local.render(tplLocal, data)
}
]
while (performance.now() - begin < 20e3) {
const task = tasks[Math.floor(Math.random() * 2)]
task.time -= performance.now()
task.fn()
task.time += performance.now()
task.cycles++
}
const [ latestResult, localResult ] = tasks.map(task => {
task.perf = task.cycles * 1000 / task.time
return task
})
const diff = (localResult.perf - latestResult.perf) / latestResult.perf
console.log(`Local: ${localResult.perf.toFixed(3)} ops/s (${localResult.cycles} cycles)`)
console.log(`Latest: ${latestResult.perf.toFixed(3)} ops/s (${latestResult.cycles} cycles)`)
console.log(`Diff: ${(diff * 100).toFixed(3)}%`)
const THRESHOLD_PERCENT = -3
process.exit(diff * 100 < THRESHOLD_PERCENT ? 1 : 0)
+17
View File
@@ -0,0 +1,17 @@
const { readFileSync } = require('fs')
const { join } = require('path')
function createEngine (pkg) {
const liquid = new pkg.Liquid({
root: join(__dirname, '../templates'),
cache: true,
extname: '.liquid'
})
liquid.registerFilter('url', path => `http://example.com${path}`)
return {
load: path => liquid.parse(readFileSync(path + '.liquid', 'utf8')),
render: (tpl, data) => liquid.renderSync(tpl, data)
}
}
module.exports = { createEngine }
+33
View File
@@ -0,0 +1,33 @@
const handlebars = require('handlebars')
const { readFileSync } = require('fs')
const { join } = require('path')
handlebars.registerPartial(
'todo-icon',
readFileSync(join(__dirname, '../templates/todo-icon.hbs'), 'utf8')
)
handlebars.registerHelper('concat', function (...args) {
return args.filter(x => typeof x === 'string').join('')
})
handlebars.registerHelper('url', function (path) {
return `http://example.com${path}`
})
handlebars.registerHelper('inc', function (num) {
return Number(num) + 1
})
handlebars.registerHelper('capitalize', function (str) {
return str[0].toUpperCase() + str.slice(1).toLowerCase()
})
handlebars.registerHelper('upcase', function (str) {
return str.toUpperCase()
})
module.exports = {
load: path => handlebars.compile(readFileSync(path + '.hbs', 'utf8')),
render: (tpl, data) => tpl(data)
}
+3
View File
@@ -0,0 +1,3 @@
const { createEngine } = require('./create-liquid')
module.exports = createEngine(require('../../dist/liquid.node.cjs'))
+20
View File
@@ -0,0 +1,20 @@
const { readFileSync } = require('fs')
const React = require('react')
const ReactDOMServer = require('react-dom/server')
const babel = require('@babel/core')
const requireFromString = require('require-from-string')
const babelConfig = {
presets: ['@babel/preset-react', '@babel/preset-env']
}
module.exports = {
load: path => {
const src = readFileSync(path + '.jsx', 'utf8')
const transformed = babel.transform(src, babelConfig)
return requireFromString(transformed.code)
},
render: (Component, data) => {
return ReactDOMServer.renderToString(React.createElement(Component, data))
}
}
+30
View File
@@ -0,0 +1,30 @@
const swig = require('swig')
swig.setFilter('url', function (path) {
return `http://example.com${path}`
})
swig.setFilter('prepend', function (input, arg) {
return arg + input
})
swig.setFilter('append', function (input, arg) {
return input + arg
})
swig.setFilter('inc', function (num) {
return Number(num) + 1
})
swig.setFilter('capitalize', function (str) {
return str[0].toUpperCase() + str.slice(1).toLowerCase()
})
swig.setFilter('upcase', function (str) {
return str.toUpperCase()
})
module.exports = {
load: path => swig.compileFile(path + '.swig'),
render: (tpl, data) => tpl(data)
}
Regular → Executable
+2
View File
@@ -3,6 +3,7 @@ const { tag } = require('./tag')
const { demo } = require('./demo')
const { layout } = require('./layout')
const { memory } = require('./memory')
const { crossEngines } = require('./cross-engines')
async function main () {
await output()
@@ -10,6 +11,7 @@ async function main () {
await demo()
await layout()
await memory()
await crossEngines()
}
main()
Regular → Executable
+2 -1
View File
@@ -18,7 +18,8 @@ const template = `
`
function layout () {
console.log('--- layout ---')
console.log(' layout')
console.log('------------------------')
return new Promise(resolve => {
new Benchmark.Suite('layout')
.add('cache=false', {
Regular → Executable
+7 -6
View File
@@ -13,7 +13,8 @@ const engine = new Liquid(engineOptions)
const SAMPLE_COUNT = 1024
function memory () {
console.log('--- memory ---')
console.log(' memory')
console.log('------------------------')
html()
todolist()
}
@@ -29,11 +30,11 @@ function html () {
templates.push(engine.parse(str))
}
const diff1 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
console.log(`${h(str.length)} lorem-html before GC x ${h(diff1)}/tpl (${SAMPLE_COUNT} instances sampled)`)
console.log(`[lorem-html ${h(str.length)}][before GC] ${h(diff1)}/tpl (${SAMPLE_COUNT} runs sampled)`)
global.gc()
const diff2 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
console.log(`${h(str.length)} lorem-html after GC x ${h(diff2)}/tpl (${SAMPLE_COUNT} instances sampled)`)
console.log(`[lorem-html ${h(str.length)}][after GC] ${h(diff2)}/tpl (${SAMPLE_COUNT} runs sampled)`)
}
function todolist () {
@@ -47,15 +48,15 @@ function todolist () {
templates.push(engine.parse(str))
}
const diff1 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
console.log(`${h(str.length)} todolist before GC x ${h(diff1)}/tpl (${SAMPLE_COUNT} instances sampled)`)
console.log(`[todolist ${h(str.length)}][before GC] ${h(diff1)}/tpl (${SAMPLE_COUNT} runs sampled)`)
global.gc()
const diff2 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
console.log(`${h(str.length)} todolist after GC x ${h(diff2)}/tpl (${SAMPLE_COUNT} instances sampled)`)
console.log(`[todolist ${h(str.length)}][after GC] ${h(diff2)}/tpl (${SAMPLE_COUNT} runs sampled)`)
}
function h (size) {
return (size / 1024).toFixed(3) + ' kB'
return (size / 1024).toFixed(3) + ' KB'
}
module.exports = { memory }
Regular → Executable
+2 -1
View File
@@ -4,7 +4,8 @@ const { Liquid } = require('..')
const liquid = new Liquid()
function output () {
console.log('--- output ---')
console.log(' output')
console.log('------------------------')
return new Promise(resolve => {
new Benchmark.Suite('output')
.add('literal', test('{{false}}{{"foo"}}{{32.322}}'))
+3380
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
{
"name": "benchmark",
"private": true,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node --expose-gc index",
"engines": "node -e 'require(\"./cross-engines\").crossEngines()'"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.13.14",
"@babel/preset-env": "^7.13.12",
"@babel/preset-react": "^7.13.13",
"handlebars": "^4.7.7",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"require-from-string": "^2.0.2",
"swig": "^1.4.2"
}
}
Regular → Executable
+2 -1
View File
@@ -4,7 +4,8 @@ const { Liquid } = require('..')
const liquid = new Liquid()
function tag () {
console.log('--- tag ---')
console.log(' tag')
console.log('------------------------')
return new Promise(resolve => {
new Benchmark.Suite('tag')
.add('if', test('{% if "foobar" %}foo{% endif %}'))
+1
View File
@@ -0,0 +1 @@
<img title="risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices" src="http://images.example.com/{{id}}.png">
+1
View File
@@ -0,0 +1 @@
<img title="risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices" src="http://images.example.com/{{id}}.png">
+1
View File
@@ -0,0 +1 @@
<img title="risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices" src="http://images.example.com/{{todo.id}}.png">
+44
View File
@@ -0,0 +1,44 @@
<section class="todo-list">
<h1>
posuere cubilia Curae; Vestibulum hendrerit malesuada odio. Fusce ut elit
ut augue sollicitudin blandit. Phasellus volutpat lorem. Duis non pede et
neque luctus tincidunt. Duis interdum tempus elit.
<small>Aenean metus. Vestibulum ac lacus. Vivamus porttitor, massa ut.</small>
</h1>
<a href={{url "/add"}} class="todo-add"><i class="fa fa-plus-square"></i>Add Todo</a>
<ul class="filter-category">
{{#each categories }}
<li style="background: {{ color }}">
<a href="/todos/category/{{ id }}">{{ title }}</a>
</li>
{{/each}}
</ul>
{{#each todos }}
<div>
<h2>
Todo {{inc @index}}:
<span class="todo-item content" data-todo-index="{{@index}}">
{{ upcase (concat 'TODO: ' title) }}
</span>
</h2>
{{> todo-icon id=id }}
<p class="description">
Purus eu mi. Proin commodo, massa commodo dapibus elementum,
libero lacus pulvinar eros, ut tincidunt nisl elit ut velit. Cras rutrum
porta purus. Vivamus lorem. Sed turpis enim, faucibus quis, pharetra in,
sagittis sed, magna. Curabitur ultricies felis ut libero. Nullam tincidunt
enim eu nibh. Nunc eget ipsum in sem facilisis convallis. Proin fermentum
</p>
<div class="todo-meta">
{{# if category }}
<span>{{ capitalize category }}</span>
{{/if}}
</div>
<a class="btn btn-primary" href={{ url (concat "/edit/" id) }}><i class="fa fa-pencil"></i> Edit</a>
<a class="btn btn-default"><i class="fa fa-check"></i> Check</a>
<a class="btn ben-danger" href={{ url (concat "/delete/" id) }}><i class="fa fa-trash-o"</i> Trash</a>
</div>
{{/each}}
</section>
+57
View File
@@ -0,0 +1,57 @@
// eslint-disable-next-line
const React = require('react')
function capitalize (str) {
return str[0].toUpperCase() + str.slice(1).toLowerCase()
}
function url (path) {
return `http://example.com${path}`
}
function renderTodoIcon (id) {
return <img title="risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices" src="http://images.example.com/{id}.png"/>
}
module.exports = ({ categories, todos }) => {
return <section className="todo-list">
<h1>
posuere cubilia Curae; Vestibulum hendrerit malesuada odio. Fusce ut elit
ut augue sollicitudin blandit. Phasellus volutpat lorem. Duis non pede et
neque luctus tincidunt. Duis interdum tempus elit.
<small>Aenean metus. Vestibulum ac lacus. Vivamus porttitor, massa ut.</small>
</h1>
<a href={url('/add')} className="todo-add"><i className="fa fa-plus-square"></i>Add Todo</a>
<ul className="filter-category">
{categories.map((item, i) => {
return <li key={i} style={{ background: item.color }}>
<a href={'/todos/category/' + item.id }>{ item.title }</a>
</li>
})}
</ul>
{todos.map((todo, index0) => {
return <div key={index0}>
<h2>
Todo { index0 + 1 }:
<span className="todo-item content" data-todo-index="{{ forloop.index0 }}">
{ ('TODO: ' + todo.title).toUpperCase() }
</span>
</h2>
{ renderTodoIcon(todo.id) }
<p className="description">
Purus eu mi. Proin commodo, massa commodo dapibus elementum,
libero lacus pulvinar eros, ut tincidunt nisl elit ut velit. Cras rutrum
porta purus. Vivamus lorem. Sed turpis enim, faucibus quis, pharetra in,
sagittis sed, magna. Curabitur ultricies felis ut libero. Nullam tincidunt
enim eu nibh. Nunc eget ipsum in sem facilisis convallis. Proin fermentum
</p>
<div className="todo-meta">
{ todo.category ? <span>{capitalize(todo.category)}</span> : '' }
</div>
<a className="btn btn-primary" href={url('/edit/' + todo.id)}><i className="fa fa-pencil"></i> Edit</a>
<a className="btn btn-default"><i className="fa fa-check"></i> Check</a>
<a className="btn ben-danger" href={url('/delete/' + todo.id)}><i className="fa fa-trash-o"></i> Trash</a>
</div>
})}
</section>
}
+5 -10
View File
@@ -7,8 +7,7 @@
</h1>
<a href={{"/add" | url}} class="todo-add"><i class="fa fa-plus-square"></i>Add Todo</a>
<ul class="filter-category">
{% for i in (0..categories.length) %}
{% assign item=categories[i] %}
{% for item in categories %}
<li style="background: {{ item.color }}">
<a href="/todos/category/{{ item.id }}">{{ item.title }}</a>
</li>
@@ -22,11 +21,7 @@
{{ todo.title | prepend: 'TODO: ' | upcase }}
</span>
</h2>
<img
title="risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices"
src="{% include "todo-icon", id=todo.id }} %}"
>
{% render "todo-icon", id:todo.id %}
<p class="description">
Purus eu mi. Proin commodo, massa commodo dapibus elementum,
@@ -38,12 +33,12 @@
<div class="todo-meta">
{% if todo.category %}
<span>{{ todo.category.title | capitalize }}</span>
<span>{{ todo.category | capitalize }}</span>
{% endif %}
</div>
<a class="btn btn-primary" href={{"/edit/" | append todo.id | url }}><i class="fa fa-pencil"></i> Edit</a>
<a class="btn btn-primary" href={{"/edit/" | append: todo.id | url }}><i class="fa fa-pencil"></i> Edit</a>
<a class="btn btn-default"><i class="fa fa-check"></i> Check</a>
<a class="btn ben-danger" href={{"/delete/" | append todo.id | url }}><i class="fa fa-trash-o"</i> Trash</a>
<a class="btn ben-danger" href={{"/delete/" | append: todo.id | url }}><i class="fa fa-trash-o"</i> Trash</a>
</div>
{% endfor %}
</section>
+44
View File
@@ -0,0 +1,44 @@
<section class="todo-list">
<h1>
posuere cubilia Curae; Vestibulum hendrerit malesuada odio. Fusce ut elit
ut augue sollicitudin blandit. Phasellus volutpat lorem. Duis non pede et
neque luctus tincidunt. Duis interdum tempus elit.
<small>Aenean metus. Vestibulum ac lacus. Vivamus porttitor, massa ut.</small>
</h1>
<a href={{"/add" | url}} class="todo-add"><i class="fa fa-plus-square"></i>Add Todo</a>
<ul class="filter-category">
{% for item in categories %}
<li style="background: {{ item.color }}">
<a href="/todos/category/{{ item.id }}">{{ item.title }}</a>
</li>
{% endfor %}
</ul>
{% for todo in todos %}
<div>
<h2>
Todo {{ loop.index }}:
<span class="todo-item content" data-todo-index="{{ loop.index0 }}">
{{ todo.title | prepend('TODO: ') | upcase }}
</span>
</h2>
{% include "todo-icon.swig" %}
<p class="description">
Purus eu mi. Proin commodo, massa commodo dapibus elementum,
libero lacus pulvinar eros, ut tincidunt nisl elit ut velit. Cras rutrum
porta purus. Vivamus lorem. Sed turpis enim, faucibus quis, pharetra in,
sagittis sed, magna. Curabitur ultricies felis ut libero. Nullam tincidunt
enim eu nibh. Nunc eget ipsum in sem facilisis convallis. Proin fermentum
</p>
<div class="todo-meta">
{% if todo.category %}
<span>{{ todo.category | capitalize }}</span>
{% endif %}
</div>
<a class="btn btn-primary" href={{"/edit/" | append(todo.id) | url }}><i class="fa fa-pencil"></i> Edit</a>
<a class="btn btn-default"><i class="fa fa-check"></i> Check</a>
<a class="btn ben-danger" href={{"/delete/" | append(todo.id) | url }}><i class="fa fa-trash-o"</i> Trash</a>
</div>
{% endfor %}
</section>
+4 -6
View File
@@ -1,7 +1,9 @@
#!/usr/bin/env bash
set -ex
rm -rf docs/source/api docs/source/zh-cn/api
typedoc ./src --gitRevision master --out docs/source/api --plugin typedoc-plugin-markdown --theme vuepress
typedoc ./src --gitRevision master --out docs/source/api --plugin typedoc-plugin-markdown --ignoreCompilerErrors true --theme vuepress
rm docs/source/api/README.md
for file in $(find docs/source/api -name "*.md"); do
@@ -9,8 +11,6 @@ for file in $(find docs/source/api -name "*.md"); do
-e 's/\(\]([^_)]*\)\/_/\1\//g' \
-e 's/\(\]([^)]*\.\)md/\1html/g' \
-e 's/\](_/\](/g' \
-e 's/{%/{% raw %}{%{% endraw %}/g' \
-e 's/{{/{% raw %}{{{% endraw %}/g' \
-e '1 s/"/\&quot;/g' \
-e '1 s/</\&lt;/g' \
-e '1 s/>/\&gt;/g' \
@@ -18,9 +18,7 @@ for file in $(find docs/source/api -name "*.md"); do
-e '1 s/^# \(.*\)/---\ntitle: "\1"\nauto: true\n---/' \
$file
target=${file/\/_/\/}
if [ "$file" != "$target" ]; then
mv $file $target
fi
cat $file | ./bin/escape-nunjucks.js > $target
done
cp -r docs/source/api docs/source/zh-cn/api
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
cd docs
cp ../CHANGELOG.md source/tutorials/changelog.md
sed -i \
-e 's/{%/{% raw %}{%{% endraw %}/g' \
-e 's/{{/{% raw %}{{{% endraw %}/g' \
-e '1 s/"/\&quot;/g' \
-e '1 s/</\&lt;/g' \
-e '1 s/>/\&gt;/g' \
source/tutorials/changelog.md
cp source/tutorials/changelog.md source/zh-cn/tutorials/changelog.md
sed -i '1i ---\ntitle: Changelog\nauto: true\n---\n' source/tutorials/changelog.md
sed -i '1i ---\ntitle: 更新日志\nauto: true\n---\n' source/zh-cn/tutorials/changelog.md
+3 -13
View File
@@ -1,26 +1,16 @@
#!/usr/bin/env bash
set -ex
./bin/build-contributors.sh
./bin/build-apidoc.sh
./bin/build-changelog.sh
cd docs
npm ci
npm run build
cp CNAME public/
cp ../CHANGELOG.md source/tutorials/changelog.md
sed -i \
-e 's/{%/{% raw %}{%{% endraw %}/g' \
-e 's/{{/{% raw %}{{{% endraw %}/g' \
-e '1 s/"/\&quot;/g' \
-e '1 s/</\&lt;/g' \
-e '1 s/>/\&gt;/g' \
source/tutorials/changelog.md
cp source/tutorials/changelog.md source/zh-cn/tutorials/changelog.md
sed -i '1i ---\ntitle: Changelog\nauto: true\n---\n' source/tutorials/changelog.md
sed -i '1i ---\ntitle: 更新日志\nauto: true\n---\n' source/zh-cn/tutorials/changelog.md
if [ "$HEXO_ALGOLIA_INDEXING_KEY" != "" ]; then
npm run index
fi
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env node
// In Hexo, content inside markdown code/code fences,
// will not go through nunjucks.
// So we're escaping special chars outside code only.
let backTick = 0
process.stdin.on('data', (buffer) => {
for (const c of buffer.toString()) {
if (c === '`') {
backTick++
}
const shouldEscape = '{%%}'.includes(c) && backTick % 2 === 0
if (shouldEscape) {
const code = c.charCodeAt(0).toString(16)
process.stdout.write(`&#x${code};`)
} else process.stdout.write(c)
}
})
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
VERSION_LATEST=$(cat package.json | grep '"version":' | awk -F'"' '{print $4}')
FILE_LOCAL=dist/liquid.node.cjs.js
FILE_LATEST=dist/liquid.node.cjs.$VERSION_LATEST.js
URL_LATEST=https://unpkg.com/liquidjs@$VERSION_LATEST/dist/liquid.node.cjs.js
if [ ! -f $FILE_LATEST ]; then
curl $URL_LATEST > $FILE_LATEST
fi
# if [ ! -f $FILE_LOCAL ]; then
BUNDLES=cjs npm run build:dist
# fi
exec node benchmark/diff.js $FILE_LOCAL $FILE_LATEST
+9
View File
@@ -0,0 +1,9 @@
# LiquidJS for Node.js
## Get Started
```bash
cd demo/nodejs
npm install
npm start
```
+30
View File
@@ -0,0 +1,30 @@
import { Liquid } from 'liquidjs'
const engine = new Liquid({
extname: '.liquid',
globals: { title: 'LiquidJS Demo' },
// root files for `.render()` and `.parse()`
root: process.cwd(),
// layout files for `{% layout %}`
layouts: process.cwd() + '/layouts',
// partial files for `{% include %}` and `{% render %}`
partials: process.cwd() + '/partials'
})
const ctx = {
todos: ['fork and clone', 'make it better', 'make a pull request']
}
async function main () {
console.log('==========renderFile===========')
const html = await engine.renderFile('todolist', ctx)
console.log(html)
console.log('===========Streamed===========')
const tpls = await engine.parseFile('todolist')
engine.renderToNodeStream(tpls, ctx)
.on('data', data => process.stdout.write(data))
.on('end', () => console.log(''))
}
main()
+13
View File
@@ -0,0 +1,13 @@
{
"name": "liquidjs-demo-nodejs",
"description": "Node.js demo for liquidjs",
"private": true,
"main": "index.mjs",
"scripts": {
"start": "node index.mjs"
},
"dependencies": {
"hello-liquid": "^1.0.0",
"liquidjs": "^9.28.3"
}
}
+1
View File
@@ -0,0 +1 @@
<li>{{index}} - {{todo}}</li>
+7
View File
@@ -0,0 +1,7 @@
{% layout 'html.liquid' %}
<h1>{% include "hello-liquid" %}</h1>
<ul>
{% for todo in todos %}
{% render 'todo.liquid' with todo, index: forloop.index%}
{% endfor %}
</ul>
+20 -5
View File
@@ -1,9 +1,14 @@
const { Liquid } = require('liquidjs')
const engine = new Liquid({
root: __dirname,
extname: '.liquid',
globals: {title: 'LiquidJS Demo'}
globals: { title: 'LiquidJS Demo' },
// root files for `.render()` and `.parse()`
root: __dirname,
// layout files for `{% layout %}`
layouts: './layouts',
// partial files for `{% include %}` and `{% render %}`
partials: './partials'
})
engine.registerTag('header', {
@@ -21,6 +26,16 @@ const ctx = {
todos: ['fork and clone', 'make it better', 'make a pull request']
}
engine.renderFile('todolist', ctx)
.then(console.log)
.catch(err => console.error(err.stack))
async function main () {
console.log('==========renderFile===========')
const html = await engine.renderFile('todolist', ctx)
console.log(html)
console.log('===========Streamed===========')
const tpls = await engine.parseFile('todolist')
engine.renderToNodeStream(tpls, ctx)
.on('data', data => process.stdout.write(data))
.on('end', () => console.log(''))
}
main()
+7
View File
@@ -0,0 +1,7 @@
<html>
<head><meta name="title" content="{{title}}"></head>
<body>
{% block %}{% endblock %}
{% render "footer.liquid" %}
</body>
</html>
+1 -1
View File
@@ -7,6 +7,6 @@
"start": "node index.js"
},
"dependencies": {
"liquidjs": "*"
"liquidjs": "^9.28.3"
}
}
+1
View File
@@ -0,0 +1 @@
<small>{{title}}</small>
+1
View File
@@ -0,0 +1 @@
<li>{{index}} - {{todo}}</li>
+1 -1
View File
@@ -2,6 +2,6 @@
{%header content: title | capitalize%}
<ul>
{% for todo in todos %}
<li>{{forloop.index}} - {{todo}}</li>
{% render 'todo.liquid' with todo, index: forloop.index%}
{% endfor %}
</ul>
-1
View File
@@ -21,5 +21,4 @@ const ctx = {
title: 'Welcome to liquidjs!'
}
// console.log('isTruthy:', isTruthy('a string here'));
engine.renderFile('todolist', ctx).then(console.log)
+9 -3
View File
@@ -1,8 +1,10 @@
title: LiquidJS
subtitle: "A simple, expressive and safe template engine."
description: "LiquidJS is a simple, expressive and safe template engine."
description: "LiquidJS is a simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript."
author: Harttle
language: en
language:
- en
- zh-cn
timezone: UTC
url: https://liquidjs.com
@@ -19,8 +21,12 @@ pretty_urls:
theme: navy
highlight:
enable: false
prismjs:
enable: true
line_number: false
preprocess: true
line_number: true
tab_replace: ''
algolia:
applicationID: 0X19J927JZ
+5687 -578
View File
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"hexo": {
"version": "4.2.0"
"version": "5.4.0"
},
"scripts": {
"build": "hexo generate",
@@ -13,7 +13,7 @@
},
"dependencies": {
"cheerio": "^0.22.0",
"hexo": "^4.2.0",
"hexo": "^5.4.0",
"hexo-algolia": "^1.3.1",
"hexo-clean-css": "^1.0.0",
"hexo-filter-nofollow": "^2.0.2",
@@ -21,15 +21,16 @@
"hexo-generator-feed": "^2.0.0",
"hexo-generator-sitemap": "^2.0.0",
"hexo-renderer-marked": "^2.0.0",
"hexo-renderer-pug": "^1.0.0",
"hexo-renderer-pug": "^2.0.0",
"hexo-renderer-stylus": "^1.0.0",
"hexo-renderer-swig": "^1.1.0",
"hexo-server": "^1.0.0",
"hexo-uglify": "^1.0.0"
},
"devDependencies": {
"all-contributors-cli": "^6.8.1",
"eslint": "^6.0.1",
"eslint-config-hexo": "^4.0.0",
"all-contributors-cli": "^6.8.1"
"eslint-config-hexo": "^4.0.0"
},
"engines": {
"node": ">=8.10.0"
+6 -1
View File
@@ -37,7 +37,12 @@ hexo.extend.helper.register('page_nav', function () {
})
hexo.extend.helper.register('raw', function (filepath) {
const content = readFileSync(resolve(this.view_dir, filepath))
const content = readFileSync(resolve(this.view_dir, filepath), 'utf8')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
return content
})
+1 -1
View File
@@ -19,5 +19,5 @@ hexo.extend.tag.register('note', (args, text) => {
}, true)
hexo.extend.tag.register('since', (args, text) => {
return `<p class="since">Added in: ${text.trim()}</p>`
return `<p class="since">${text.trim()}</p>`
}, true)
+1 -1
View File
@@ -1,4 +1,4 @@
tutorials: /tutorials/setup.html
tutorials: /tutorials/intro-to-liquid.html
tags: /tags/overview.html
filters: /filters/overview.html
playground: /playground.html
+6 -6
View File
@@ -1,9 +1,3 @@
-
url: https://github.com/harttle/liquidjs/pull/5
date: '2016-09-12'
title:
zh-cn: '异步化:重写了解析器和渲染器,使 LiquidJS 可以提供 Promise API 并支持异步的自定义 Tag 实现。'
en: 'Async spike: rewrite the parser and render to support Promise, which enables async tags.'
-
url: https://opencollective.com/liquidjs/#section-contribute
date: '2020-02-26'
@@ -22,3 +16,9 @@
title:
zh-cn: '性能提升:引入 AST 并重新设计 Token 类型系统,使渲染性能平均提升 100.3%。'
en: 'Performance Boost: a simple AST to improve render performance by 100.3%.'
-
url: https://github.com/harttle/liquidjs/milestone/3?closed=1
date: '2021-09-30'
title:
zh-cn: '流式渲染:4 倍渲染速度,并增加了对流式渲染的支持。'
en: 'Streamed Rendering: now render is 4x faster and support streamed rendering.'
+11
View File
@@ -9,6 +9,10 @@ tutorials:
advanced:
caching: caching.html
registeration: register-filters-tags.html
access_scope_in_filters: access-scope-in-filters.html
parse_parameters: parse-parameters.html
render_tag_content: render-tag-content.html
sync_and_async: sync-and-async.html
whitespace: whitespace-control.html
plugins: plugins.html
operators: operators.html
@@ -28,6 +32,7 @@ filters:
capitalize: capitalize.html
ceil: ceil.html
compact: compact.html
concat: concat.html
date: date.html
default: default.html
divided_by: divided_by.html
@@ -46,6 +51,7 @@ filters:
newline_to_br: newline_to_br.html
plus: plus.html
prepend: prepend.html
raw: raw.html
remove: remove.html
remove_first: remove_first.html
replace: replace.html
@@ -78,15 +84,20 @@ tags:
comment: comment.html
cycle: cycle.html
decrement: decrement.html
echo: echo.html
else: if.html
elsif: if.html
for: for.html
if: if.html
include: include.html
increment: increment.html
layout: layout.html
liquid: liquid.html
raw: raw.html
render: render.html
tablerow: tablerow.html
unless: unless.html
when: case.html
api:
quick_entry:
+2
View File
@@ -2,6 +2,8 @@
title: concat
---
{% since %}v2.0.0{% endsince %}
Concatenates (joins together) multiple arrays. The resulting array contains all the items from the input arrays.
Input
+8
View File
@@ -16,6 +16,10 @@ Output
Fri, Jul 17, 15
```
{% note info TimeZone %}
Date will be converted to local time before output. To avoid that, you can set `timezoneOffset` LiquidJS option to `0`, its default value is your local timezone offset which can be obtained by `new Date().getTimezoneOffset()`.
{% endnote %}
Input
```liquid
{{ article.published_at | date: "%Y" }}
@@ -38,6 +42,10 @@ Output
Mar 14, 16
```
{% note info Timestamp Strings %}
Note that LiquidJS is using JavaScript [Date][newDate] to parse the input string, that means [IETF-compliant RFC 2822 timestamps](https://datatracker.ietf.org/doc/html/rfc2822#page-14) and strings in [a version of ISO8601](https://www.ecma-international.org/ecma-262/11.0/#sec-date.parse) are supported.
{% endnote %}
To get the current time, pass the special word `"now"` (or `"today"`) to `date`:
Input
+19
View File
@@ -44,4 +44,23 @@ Output
2.99
```
## Allowing `false`
{% since %}v9.32.0{% endsince %}
To allow variables to return `false` instead of the default value, you can use the `allow_false` parameter.
Input
```liquid
{% assign display_price = false %}
{{ display_price | default: true, allow_false: true }}
```
Output
```text
false
```
[falsy]: ../tutorials/truthy-and-falsy.html
+18 -1
View File
@@ -26,6 +26,23 @@ Output
1.6666666666666667
```
{% note info Integer Arithmetic %}Since JavaScript doesn't differentiate integers and floats, LiquidJS is not capable of integer arithmetic and the return type is always `number`, the string representation of which depends on its value.{% endnote %}
In JavaScript, float and integer shares the same type `number` and we cannot tell the difference. For example:
```javascript
// always true
5.0 === 5
```
You'll need to pass another `integerArithmetic` argument to enforce integer divide:
Input
```liquid
{{ 5 | divided_by: 3, true }}
```
Output
```text
1
```
[floor]: ./floor.html
+4 -2
View File
@@ -1,5 +1,6 @@
---
title: Filters
description: Description and demo for each Liquid filter
---
LiquidJS implements business-logic independent filters that are typically implemented in [shopify/liquid][shopify/liquid]. This section contains the specification and demoes for all the filters implemented by LiquidJS.
@@ -8,10 +9,11 @@ There's 40+ filters supported by LiquidJS. These filters can be categorized into
Categories | Filters
--- | ---
Math | plus, minus, modulo, times, floor, ceil, round, divided_by, abs
Math | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most
String | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, remove, remove_first, truncate, truncatewords
HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br
Array | slice, map, sort, sort_natural, uniq, where, first, last, join, reverse
Array | slice, map, sort, sort_natural, uniq, where, first, last, join, reverse, concat, compact, size
Date | date
Misc | default, json, raw
[shopify/liquid]: https://github.com/Shopify/liquid
+51
View File
@@ -0,0 +1,51 @@
---
title: raw
---
{% since %}v9.37.0{% endsince %}
Liquid filter that directly returns the value of the variable. Useful when [outputEscape](/api/interfaces/liquid_options_.liquidoptions.html#Optional-outputEscape) is set.
{% note info Auto escape %}
By default `outputEscape` is not set. That means LiquidJS output is not escaped by default, thus `raw` filter is not useful until `outputEscape` is set.
{% endnote %}
Input (`outputEscape` not set)
```liquid
{{ "<" }}
```
Output
```text
<
```
Input (`outputEscape="escape"`)
```liquid
{{ "<" }}
```
Output
```text
&lt;
```
Input (`outputEscape="json"`)
```liquid
{{ "<" }}
```
Output
```text
"<"
```
Input (`outputEscape="escape"`)
```liquid
{{ "<" | raw }}
```
Output
```text
<
```
+2 -2
View File
@@ -14,5 +14,5 @@ Input
Output
```text
ants, bugs, bees```
ants, bugs, bees
```
+1 -1
View File
@@ -1,5 +1,5 @@
layout: index
description: LiquidJS is a simple, expressive and safe template engine.
description: LiquidJS is a simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript.
subtitle: A simple, expressive and safe template engine.
---
ul#intro-feature-list
+28
View File
@@ -1,6 +1,7 @@
{
"short_name": "LiquidJS",
"name": "LiquidJS",
"description": "A simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript.",
"icons": [
{
"src": "/icon/apple-touch-icon-57x57.png",
@@ -23,6 +24,33 @@
"sizes": "512x512"
}
],
"shortcuts" : [
{
"name": "Tutorials",
"url": "/tutorials/intro-to-liquid.html",
"description": "A set of articles describing how to use LiquidJS"
},
{
"name": "Tags",
"url": "/tags/overview.html",
"description": "Description and demo for each Liquid tag"
},
{
"name": "Filters",
"url": "/filters/overview.html",
"description": "Description and demo for each Liquid filter"
},
{
"name": "Playground",
"url": "/playground.html",
"description": "An online code editor to try out and share Liquid templates"
},
{
"name": "API",
"url": "/api/classes/liquid_.liquid.html",
"description": "TypeScript doc for LiquidJS classes and interfaces"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#0f83ce",
+2
View File
@@ -1,3 +1,5 @@
---
layout: playground
title: Playground
description: An online code editor to try out and share Liquid templates
---
+9 -2
View File
@@ -9,6 +9,7 @@ const urlsToCache = [
'/fonts/icomoon.ttf?e8nnma'
]
const blackList = [
/chrome-extension:/,
/google-analytics.com.*collect/
]
@@ -29,8 +30,14 @@ self.addEventListener('fetch', event => {
if (
event.request.method !== 'GET' || blackList.some(regex => regex.exec(event.request.url))
) return network(event.request)
const pn = networkAndSave(event.request)
event.respondWith(cache(event.request).then(res => res || pn).catch(() => pn))
if (event.request.url.match(/\.githubusercontent\.com/)) {
// cache first
const pn = networkAndSave(event.request)
event.respondWith(cache(event.request).then(res => res || pn).catch(() => pn))
} else {
// network first
event.respondWith(networkAndSave(event.request).catch(() => cache(event.request)))
}
})
function cache (req) {
+1 -1
View File
@@ -12,7 +12,7 @@ Input
{% case handle %}
{% when "cake" %}
This is a cake
{% when "cookie" %}
{% when "cookie", "biscuit" %}
This is a cookie
{% else %}
This is not a cake nor a cookie
+20
View File
@@ -0,0 +1,20 @@
---
title: Echo
---
{% since %}v9.31.0{% endsince %}
Outputs an expression in the rendered HTML. This is identical to wrapping an expression in `{{` and `}}`, but works inside liquid tags and supports filters.
## echo
Input
```liquid
{% assign username = 'Bob' %}
{% echo username | append: ", welcome to LiquidJS!" | capitalize %}
```
Output
```text
Bob, welcome to LiquidJS!
```
+90 -22
View File
@@ -66,17 +66,17 @@ Causes the loop to stop iterating when it encounters the `break` tag.
Input
```liquid
{% for i in (1..5) %}
{% if i == 4 %}
{%- if i == 4 -%}
{% break %}
{% else %}
{%- else -%}
{{ i }}
{% endif %}
{%- endif -%}
{% endfor %}
```
Output
```text
1 2 3
123
```
### continue
@@ -86,17 +86,17 @@ Causes the loop to skip the current iteration when it encounters the `continue`
Input
```liquid
{% for i in (1..5) %}
{% if i == 4 %}
{% continue %}
{% else %}
{%- if i == 4 -%}
{%- continue -%}
{%- else -%}
{{ i }}
{% endif %}
{%- endif -%}
{% endfor %}
```
Output
```text
1 2 3 5
1235
```
### forloop
@@ -106,7 +106,7 @@ There's a `forloop` object available inside `for` loops. It's used to indicate t
The `forloop.first`, `forloop.last` and `forloop.length` property:
Input
```
```liquid
{% for i in (1..5) %}
{%- if forloop.first == true -%} First
{%- elsif forloop.last == true -%} Last
@@ -116,7 +116,7 @@ Input
```
Output
```
```text
First
5
5
@@ -152,15 +152,15 @@ Limits the loop to the specified number of iterations.
Input
```liquid
<!-- if array = [1,2,3,4,5,6] -->
<!-- for array = [1,2,3,4,5,6] -->
{% for item in array limit:2 %}
{{ item }}
{{- item -}}
{% endfor %}
```
Output
```text
1 2
12
```
### offset
@@ -169,15 +169,57 @@ Begins the loop at the specified index.
Input
```liquid
<!-- if array = [1,2,3,4,5,6] -->
<!-- for array = [1,2,3,4,5,6] -->
{% for item in array offset:2 %}
{{ item }}
{{- item -}}
{% endfor %}
```
Output
```text
3 4 5 6
3456
```
#### offset:continue
{% since %}v9.33.0{% endsince %}
Offset value can be `continue` to continue previous loop. For example:
Input
```liquid
<!-- for array = [1,2,3,4,5,6] -->
{% for item in array limit:2 %}
{{- item -}}
{% endfor%}
{% for item in array offset:continue %}
{{- item -}}
{% endfor%}
```
Output
```text
12
3456
```
For the same variable name (`"item"` in this case) and same collection (`"array"` in this case), there's one position record. That means you can start a new loop with a different variable name:
Input
```liquid
<!-- for array = [1,2,3,4,5,6] -->
{% for item in array limit:2 %}
{{- item -}}
{% endfor%}
{% for item2 in array offset:continue %}
{{- item2 -}}
{% endfor%}
```
Output
```text
12
123456
```
### range
@@ -187,19 +229,19 @@ Defines a range of numbers to loop through. The range can be defined by both lit
Input
```liquid
{% for i in (3..5) %}
{{ i }}
{% endfor %}
{{- i -}}
{% endfor-%}
{% assign num = 4 %}
{% for i in (1..num) %}
{{ i }}
{{- i -}}
{% endfor %}
```
Output
```text
3 4 5
1 2 3 4
345
1234
```
### reversed
@@ -218,3 +260,29 @@ Output
```text
6 5 4 3 2 1
```
When used with additional parameters, order is important. Leading with `reversed` reverses the order of the loop before executing the other parameters.
Input
```liquid
{% for i in (1..8) reversed limit: 4 %}
{{ i }}
{% endfor %}
```
Output
```text
8 7 6 5
```
Input
```liquid
{% for i in (1..8) limit: 4 reversed %}
{{ i }}
{% endfor %}
```
Output
```text
4 3 2 1
```
+64 -2
View File
@@ -5,7 +5,7 @@ title: Include
{% since %}v1.9.1{% endsince %}
{% note warn Deprecated %}
This tag is deprecated, use <a href="./render.html">render</a> tag instead for better encapsulation.
This tag is deprecated, use <a href="./render.html">render</a> tag instead, which contains all the features of `include` and provides better encapsulation.
{% endnote %}
## Include a Template
@@ -16,7 +16,7 @@ Renders a partial template from the template [roots][root].
{% include 'footer.liquid' %}
```
When the [extname][extname] option is set, the above `.liquid` extension can be omitted and writes:
If [extname][extname] option is set, the above `.liquid` extension becomes optional:
```liquid
{% include 'footer' %}
@@ -44,5 +44,67 @@ A single object can be passed to a snippet by using the `with...as` syntax:
In the example above, the `product` variable in the partial template will hold the value of `featured_product` in the parent template.
## Outputs & Filters
When filename is specified as literal string, it supports Liquid output and filter syntax. Useful when concatenating strings for a complex filename.
```liquid
{% include "prefix/{{name | append: \".html\"}}" %}
```
{% note info Escaping %}
In LiquidJS, `"` within quoted string literals need to be escaped by adding a slash before the quote, e.g. `\"`. Using Jekyll-like filenames can make this easier, see below.
{% endnote %}
## Jekyll-like filenames
Setting [dynamicPartials][dynamicPartials] to `false` will enable Jekyll-like filenames, where file names are specified as literal string without surrounding quotes. Liquid outputs and filters are also supported within that, for example:
```liquid
{% include prefix/{{ page.my_variable }}/suffix %}
```
This way, you don't need to escape `"` in the filename expression.
```liquid
{% include prefix/{{name | append: ".html"}} %}
```
## Jekyll include
{% since %}v9.33.0{% endsince %}
[jekyllInclude][jekyllInclude] is used to enable Jekyll-like include syntax. Defaults to `false`, when set to `true`:
- Filename will be static: `dynamicPartials` now defaults to `false` (instead of `true`). And you can set `dynamicPartials` back to `true`.
- Use `=` instead of `:` to separate parameter key-values.
- Parameters are under `include` variable instead of current scope.
For example, the following template:
```liquid
{% include article.html header="HEADER" content="CONTENT" %}
```
`article.html` with following content:
```liquid
<article>
<header>{{include.header}}</header>
{{include.content}}
</article>
```
Note that we're referencing the first parameter by `include.header` instead of `header`. Will output following:
```html
<article>
<header>HEADER</header>
CONTENT
</article>
```
[extname]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-extname
[root]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-root
[dynamicPartials]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-dynamicPartials
[jekyllInclude]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-jekyllInclude
+74 -33
View File
@@ -4,21 +4,67 @@ title: Layout
{% since %}v1.9.1{% endsince %}
## Using a Layout Template
## Using a Layout
Renders current template inside a layout template from the template [roots][root].
Introduce a layout template for the current template to render in. The directory for layout files are defined by [layouts][layouts] or [root][root].
```liquid
{% layout 'footer.liquid' %}
// default-layout.liquid
Header
{% block %}{% endblock %}
Footer
// page.liquid
{% layout "default-layout.liquid" %}
{% block %}My page content{% endblock %}
// result
Header
My page content
Footer
```
Whe the [extname][extname] option is set, the above `.liquid` extension can be omitted and writes:
If [extname][extname] option is set, the `.liquid` extension becomes optional:
```liquid
{% layout 'footer' %}
{% layout 'default-layout' %}
```
When a partial template is rendered by `layout`, the code inside it can access its caller's variables but its parent cannot access variables defined inside a included template.
{% note info Scoping %}
When a partial template is rendered by <code>layout</code>, its template have access for its caller's variables but not vice versa. Variables defined in layout will be popped out before control returning to its caller.
{% endnote %}
## Multiple Blocks
The layout file can contain multiple blocks, each with a specified name. The following snippets yield same result as in the above example.
```liquid
// default-layout.liquid
{% block header %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock %}
// page.liquid
{% layout "default-layout.liquid" %}
{% block header %}Header{% endblock %}
{% block content %}My page content{% endblock %}
{% block footer %}Footer{% endblock %}
```
## Default Block Contents
In the above layout files, blocks has empty contents. But it's not necessarily be empty, in which case, the block contents in layout files will be used as default templates. The following snippets are also equivalent to the above examples:
```liquid
// default-layout.liquid
{% block header %}Header{% endblock %}
{% block content %}{% endblock %}
{% block footer %}Footer{% endblock %}
// page.liquid
{% layout "default-layout.liquid" %}
{% block content %}My page content{% endblock %}
```
## Passing Variables
@@ -29,38 +75,33 @@ Variables defined in current template can be passed to a the layout template by
{% layout 'name', my_variable: my_variable, my_other_variable: 'oranges' %}
```
## Blocks
## Outputs & Filters
The layout file can contain multiple `block`s which will be populated by the child template (the caller). For example we have a `default-layout.liquid` file with the following contents:
When filename is specified as literal string, it supports Liquid output and filter syntax. Useful when concatenating strings for a complex filename.
```
Header
{% block content %}My default content{% endblock %}
Footer
```liquid
{% layout "prefix/{{name | append: \".html\"}}" %}
```
And it's called by a `page.liquid` file with `layout` tag:
```
{% layout "default-layout" %}
{% block content %}My page content{% endblock %}
```
The render result of `page.liquid` will be :
```
Header
My page content
Footer
```
{% note tip Block %}
<ul>
<li>Multiple blocks can be defined within a layout template;</li>
<li>The block name is optional when there's only one block.</li>
<li>The block contents will fallback to parent's corresponding block if not provided by child template.</li>
</ul>
{% note info Escaping %}
In LiquidJS, `"` within quoted string literals need to be escaped. Adding a slash before the quote, e.g. `\"`. Using Jekyll-like filenames can make this easier, see below.
{% endnote %}
## Jekyll-like Filenames
Setting [dynamicPartials][dynamicPartials] to `false` will enable Jekyll-like filenames, file names are specified as literal string. And it also supports Liquid outputs and filters.
```liquid
{% layout prefix/{{ page.my_variable }}/suffix %}
```
This way, you don't need to escape `"` in the filename expression.
```liquid
{% layout prefix/{{name | append: ".html"}} %}
```
[extname]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-extname
[root]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-root
[layouts]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-layouts
[dynamicPartials]: ../api/interfaces/liquid_options_.liquidoptions.html#dynamicPartials
+28
View File
@@ -0,0 +1,28 @@
---
title: Liquid
---
{% since %}v9.31.0{% endsince %}
Encloses multiple tags within one set of delimiters, to allow writing Liquid logic more concisely.
## liquid
Input
```liquid
{% liquid
assign names = 'Bob, Sally' | split: ', '
for name in names
echo 'Hello, ' | append: name
unless forloop.last
echo ', '
endunless
endfor
%}
```
Output
```text
Hello, Bob, Hello Sally
```
+3 -2
View File
@@ -1,5 +1,6 @@
---
title: Tags
description: Description and demo for each Liquid tag
---
LiquidJS implements business-logic independent tags that are typically implemented in [shopify/liquid][shopify/liquid]. This section contains the specification and demoes for all the tags implemented by LiquidJS.
@@ -10,8 +11,8 @@ Category | Purpose | Tags
--- | --- | ---
Iteration | iterate over a collection | for, cycle, tablerow
Control Flow | control the execution branch of template rendering | if, unless, elsif, else, case, when
Variable | define and alter variables | assign, increment, decrement
Variable | define and alter variables | assign, increment, decrement, capture, echo
File | include another template or extend a layout template | render, include, layout
Language | temporarily disable LiquidJS syntax | raw, comment
Language | temporarily disable LiquidJS syntax | raw, comment, liquid
[shopify/liquid]: https://github.com/Shopify/liquid
+42 -7
View File
@@ -4,26 +4,33 @@ title: Render
{% since %}v9.2.0{% endsince %}
## Basic Usage
## Render a Template
### Render a Template
Renders a partial template from the template [root][root]s.
Render a partial template from partials directory specified by [partials][partials] or [root][root].
```liquid
// index.liquid
Contents
{% render 'footer.liquid' %}
// footer.liquid
Footer
// result
Contents
Footer
```
When the [extname][extname] option is set, the above `.liquid` extension can be omitted and writes:
If [extname][extname] option is set, the above `.liquid` extension becomes optional:
```liquid
{% render 'footer' %}
```
{% note info Variable Scope %}
When a partial template is rendered, the code inside it can't access its parent's variables and its variables won't be accessible by its parent. This encapsulation helps make theme code easier to understand and maintain.{% endnote %}
When a partial template is rendered, the code inside it can't access its parent's variables and its variables won't be accessible by its parent. This encapsulation makes partials easier to understand and maintain.{% endnote %}
### Passing Variables
## Passing Variables
Variables defined in parent's scope can be passed to a the partial template by listing them as parameters on the render tag:
@@ -34,6 +41,32 @@ Variables defined in parent's scope can be passed to a the partial template by l
[globals][globals] don't need to be passed down. They are accessible from all files.
## Outputs & Filters
When filename is specified as literal string, it supports Liquid output and filter syntax. Useful when concatenating strings for a complex filename.
```liquid
{% render "prefix/{{name | append: \".html\"}}" %}
```
{% note info Escaping %}
In LiquidJS, `"` within quoted string literals need to be escaped. Adding a slash before the quote, e.g. `\"`. Using Jekyll-like filenames can make this easier, see below.
{% endnote %}
## Jekyll-like Filenames
Setting [dynamicPartials][dynamicPartials] to `false` will enable Jekyll-like filenames, file names are specified as literal string. And it also supports Liquid outputs and filters.
```liquid
{% render prefix/{{ page.my_variable }}/suffix %}
```
This way, you don't need to escape `"` in the filename expression.
```liquid
{% render prefix/{{name | append: ".html"}} %}
```
## Parameters
### The `with` Parameter
@@ -63,4 +96,6 @@ In the example above, the partial template will be rendered once for each `varia
[forloop]: ./for.html
[extname]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-extname
[root]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-root
[partials]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-partials
[globals]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-globals
[dynamicPartials]: ../api/interfaces/liquid_options_.liquidoptions.html#dynamicPartials
@@ -0,0 +1,32 @@
---
title: Access Scope in Filters
---
As covered in [Register Filters/Tags][register-filters], we can access filter arguments directly in filter function like:
```javascript
// Usage: {{ 1 | add: 2, 3 }}
// Output: 6
engine.registerFilter('add', (initial, arg1, arg2) => initial + arg1 + arg2)
```
When it comes to stateful filters, for example transform a URL path to full URL, we'll need to access a `origin` in current scope:
```javascript
// Usage: {{ '/index.html' | fullURL }}
// Scope: { origin: "https://liquidjs.com" }
// Output: https://liquidjs.com/index.html
engine.registerFilter('fullURL', function (path) {
const origin = this.context.get(['origin'])
return new URL(path, origin).toString()
})
```
See this JSFiddle: <http://jsfiddle.net/ctj364up/1/>
{% note warn Arrow Functions %}
<code>this</code> in arrow functions is bound to current JavaScript context, you'll need to use <code>function(){}</code> instead of <code>()=>{}</code> syntax to access <code>this.context</code> correctly.
{% endnote %}
[register-filters]: /tutorials/register-filters-tags.html
@@ -2,6 +2,10 @@
title: Contribution Guideline
---
## 👉👉👉 Star LiquidJS [![harttle/liquidjs](https://img.shields.io/github/stars/harttle/liquidjs?style=flat-square)][liquidjs]
Starring LiquidJS is the most important and easiest way to support us: boost its rank and expose it to more people, which in turn makes it better.
## Show Me Your Code
**Code Style**: LiquidJS applies [standard](https://github.com/standard/eslint-config-standard) and [@typescript-eslint/recommended](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json) rules, make sure it's still valid before commit:
@@ -18,19 +22,23 @@ npm test
**Commit Message**: Please align to [the Angular Commit Message Guidelines](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits), especially note the [type identifier](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type), on which semantic-release bot depends.
## Star on Github 👉 [![harttle/liquidjs](https://img.shields.io/github/stars/harttle/liquidjs?style=flat-square)][liquidjs]
This is the easiest way to support us: boost its rank and expose it to more people, which in turn makes it better.
**Backward-Compatibility**: please be backward-compatible. LiquidJS is used by multiple layers of softwares, including underlying libraries, compilers, site generators and Web servers. It's not easy to do a major upgrade for most of them.
## Financial Support
LiquidJS is Open Source and Free and **without** capitalists support and **without** any ADs. To help it live and thrive, consider contribute on [Open Collective][oc] or [Patreon][pt]. To acknowledge your contribution, your name and avatar will be listed here and on [Github README][liquidjs].
LiquidJS is Open Source and Free. To help it live and thrive, please consider contribute on [Open Collective][oc] or [Patreon][pt]. To acknowledge your contribution, your name and avatar will be listed here, on LiquidJS [homepage](https://liquidjs.com/) and on [Github README][liquidjs].
<object type="image/svg+xml" data="https://opencollective.com/liquidjs/tiers/backer.svg?avatarHeight=72"></object>
### Backers
If you personally like LiquidJS and find it's useful to you, you can become a backer!
[![Become a Patron!](../icon/[email protected])](https://www.patreon.com/bePatron?u=32321060)
<object type="image/svg+xml" data="https://opencollective.com/liquidjs/backers.svg?avatarHeight=72"></object>
[oc]: https://opencollective.com/liquidjs/
### Sponsors
If LiquidJS is benefiting your business/company, please sponsor us to make it better!
<object type="image/svg+xml" data="https://opencollective.com/liquidjs/sponsors.svg?avatarHeight=72"></object>
[oc]: https://opencollective.com/liquidjs/contribute/backer-ii-10666/checkout
[pt]: https://www.patreon.com/harttle
[shopify/liquid]: https://shopify.github.io/liquid/
[caniuse-promises]: http://caniuse.com/#feat=promises
+28 -1
View File
@@ -2,7 +2,25 @@
title: Differences with Shopify/liquid
---
All filters and tags in [shopify/liquid](https://github.com/Shopify/liquid) are supposed to be built in LiquidJS, but not those business-logic specific tags/filters which are typically from Shopify themes (see [Plugins List][plugins] in case you're looking for them and feel free to add yours to the list). Though being compatible the Ruby version is one of our priorities, there are still some differences:
## Compatibility
Being compatible the Ruby version is one of our priorities. Liquid language is originally [implemented in Ruby][ruby-liquid] and used by Shopify, Jekyll and thus Github Pages, as you can see it's one of the most popular template engines in Ruby. There're lots of people using LiquidJS to serve their templates originally written for Shopify themes and Jekyll sites.
So "being compatible" means serve developers from Shopify and Jekyll well:
- **Well-formed Liquid template should work just fine in LiquidJS**. For example, `forloop.index` should be 1-indexed, `nil` should be rendered as empty string rather than `undefined`, etc. Although some features (e.g. [#236][#236]) are not feasible in JavaScript, at least we're trying to implement all the semantics of Liquid language.
- **All filters and tags in [shopify/liquid][ruby-liquid] are supposed to be built in LiquidJS**. But not those business-logic specific tags/filters typically defined by Shopify platform. Those features should be maintained as [plugins][plugins]. For filters/tags that are not business-logic specific, like `{% layout %}`, and extremely useful, feel free to file an issue.
In the meantime, it's now implemented in JavaScript, that means it has to be more powerful:
* **Async as first-class citizen**. Filters and tags can be implemented asynchronously by return a `Promise`.
* **Also can be sync**. For scenarios that are not I/O intensive, render synchronously can be much faster. You can call synchronous APIs like `.renderSync()` as long as all the filters and tags in template support to be rendered synchronously. All builtin filters/tags support both sync and async render.
* **[Abstract file system][afs]**. Along with async feature, LiquidJS can be used to serve templates stored in Databases [#414][#414], on remote HTTP server [#485][#485], and so on.
* **Additional tags and filters** like `layout` and `json`.
## Differences
Though we're trying to be compatible with the Ruby version, there are still some differences:
* Truthy and Falsy. All values except `undefined`, `null`, `false` are truthy, whereas in Ruby Liquid all except `nil` and `false` are truthy. See [#26][#26].
* Number. In JavaScript we cannot distinguish or convert between `float` and `integer`, see [#59][#59]. And when applied `size` filter, numbers always return 0, which is 8 for integer in ruby, cause they do not have a `length` property.
@@ -11,11 +29,20 @@ All filters and tags in [shopify/liquid](https://github.com/Shopify/liquid) are
* Iteration order for objects. The iteration order of JavaScript objects, and thus LiquidJS objects, is a combination of the insertion order for string keys, and ascending order for number-like keys, while the iteration order of Ruby Hash is simply the insertion order.
* Sort stability. The [sort][sort] stability is also not defined in both shopify/liquid and LiquidJS, but it's [considered stable][stable-sort] for LiquidJS in Node.js 12+ and Google Chrome 70+.
* Trailing unmatched characters inside filters are allowed in shopify/liquid but not in LiquidJS. It means filter arguments without a colon like `{%raw%}{{ "a b" | split " "}}{%endraw%}` will throw an error in LiquidJS. This is intended to improve Liquid usability, see [#208][#208] and [#212][#212].
* LiquidJS has additional tags: [layout][layout] and corresponding `block` tag.
* LiquidJS has additional filters: [json][json].
[layout]: https://liquidjs.com/tags/layout.html
[json]: https://liquidjs.com/filters/json.html
[#26]: https://github.com/harttle/liquidjs/pull/26
[#59]: https://github.com/harttle/liquidjs/issues/59
[#208]: https://github.com/harttle/liquidjs/issues/208
[#212]: https://github.com/harttle/liquidjs/issues/212
[#236]: https://github.com/harttle/liquidjs/issues/236
[#414]: https://github.com/harttle/liquidjs/discussions/414
[#485]: https://github.com/harttle/liquidjs/discussions/485
[sort]: https://liquidjs.com/filters/sort.html
[stable-sort]: https://v8.dev/features/stable-sort
[plugins]: ./plugins.html#Plugin-List
[ruby-liquid]: https://github.com/Shopify/liquid
[afs]: https://liquidjs.com/tutorials/render-file.html#Abstract-File-System
+7 -2
View File
@@ -1,14 +1,19 @@
---
title: Introduction to Liquid Template Language
title: The Liquid Template Language
describe: A short introduction to the Liquid template language and some simple demos.
---
LiquidJS is a simple, expressive, safe and shopify compatible template engine in pure JavaScript. The purpose of this repo is to provide a standard Liquid implementation for the JavaScript community. Liquid is originally implemented in Ruby and used by Github Pages, Jekyll and Shopify, see [Differences with Shopify/liquid][diff].
LiquidJS is a simple, expressive and safe [Shopify][shopify/liquid] / Github Pages compatible template engine in pure JavaScript. The purpose of this repo is to provide a standard Liquid implementation for the JavaScript community. Liquid is originally implemented in Ruby and used by Github Pages, Jekyll and Shopify, see [Differences with Shopify/liquid][diff].
LiquidJS syntax is relatively simple. There're 2 types of markups in LiquidJS:
- **Tags**. A tag consists of a tag name and optional arguments wrapped between `{%raw%}{%{%endraw%}` and `%}`.
- **Outputs**. An output consists of a value and a list of filters, which is optional, wrapped between `{%raw%}{{{%endraw%}` and `}}`.
{% note info Live Demo %}
Before going into the details, here's a live demo to play around: <https://liquidjs.com/playground.html>.
{% endnote %}
## Outputs
**Outputs** are used to output variables, which can be transformed by filters, into HTML. The following template will insert the value of `username` into the input's value:
+52 -8
View File
@@ -2,7 +2,7 @@
title: Options
---
The [Liquid][liquid] constructor accepts a plain object as options to define the behaviour of LiquidJS. All of these options are optional thus we can specify any of them, for example the `cache` option:
The [Liquid][liquid] constructor accepts a plain object as options to define the behavior of LiquidJS. All of these options are optional thus we can specify any of them, for example the `cache` option:
```javascript
const { Liquid } = require('liquidjs')
@@ -23,8 +23,20 @@ It's default to `false`. When setting to `true` a default LRU cache of size 1024
Additionally, it can also be a custom cache implementation. See [Caching][caching] for details.
## Partials/Layouts
**root** is used to specify template directories for LiquidJS to lookup and read template files. Can be a single string and an array of strings. See [Render Files][render-file] for details.
**layouts** is used to specify template directories for LiquidJS to lookup files for `{% layout %}`. Same format as `root` and will default to `root` if not specified.
**partials** is used to specify template directories for LiquidJS to lookup files for `{% render %}` and `{% include %}`. Same format as `root` and will default to `root` if not specified.
**relativeReference** is set to `true` by default to allow relative filenames. Note that relatively referenced files are also need to be within corresponding root. For example you can reference another file like `{% render ../foo/bar %}` as long as `../foo/bar` is also within `partials` directory.
## dynamicPartials
> Note: for historical reasons, it's named dynamicPartials but it also works for layouts.
**dynamicPartials** indicates whether or not to treat filename arguments in [include][include], [render][render], [layout][layout] tags as a variable. Defaults to `true`. For example, render the following snippet with scope `{ file: 'foo.html' }` will include the `foo.html`:
```liquid
@@ -40,9 +52,32 @@ Setting `dynamicPartials: false`, LiquidJS will try to include the file named `f
{% note warn Common Pitfall %}
LiquidJS defaults this option to <code>true</code> to be compatible with shopify/liquid, but if you're from <a href="https://github.com/11ty/eleventy" target="_blank">eleventy</a> it's set to <code>false</code> by default (see <a href="https://www.11ty.dev/docs/languages/liquid/#quoted-include-paths" target="_blank">Quoted Include Paths</a>) which I believe is trying to be compatible with Jekyll.{% endnote %}
## Jekyll include
{% since %}v9.33.0{% endsince %}
[jekyllInclude][jekyllInclude] is used to enable Jekyll-like include syntax. Defaults to `false`, when set to `true`:
- Filename will be static: `dynamicPartials` now defaults to `false` (instead of `true`). And you can set `dynamicPartials` back to `true`.
- Use `=` instead of `:` to separate parameter key-values.
- Parameters are under `include` variable instead of current scope.
For example in the following template, `name.html` is not quoted, `header` and `"HEADER"` are separated by `=`, and the `header` parameter is referenced by `include.header`. More details please check out [include][include].
```liquid
// entry template
{% include article.html header="HEADER" content="CONTENT" %}
// article.html
<article>
<header>{{include.header}}</header>
{{include.content}}
</article>
```
## extname
**extname** defines the default extname to be appended into filenames if the filename has no extname. Defaults to `''` which means it's disabled by default. By setting it to `.liquid`:
**extname** defines the default extension name to be appended into filenames if the filename has no extension name. Defaults to `''` which means it's disabled by default. By setting it to `.liquid`:
```liquid
{% render "foo" %} there's no extname, adds `.liquid` and loads foo.liquid
@@ -53,10 +88,6 @@ LiquidJS defaults this option to <code>true</code> to be compatible with shopify
Before 2.0.1, <code>extname</code> is set to `.liquid` by default. To change that you need to set <code>extname: ''</code> explicitly. See <a href="https://github.com/harttle/liquidjs/issues/41" target="_blank">#41</a> for details.
{% endnote %}
## root
**root** is used to specify template directories for LiquidJS to lookup and read template files. Can be a single string and an array of strings. See [Render Files][render-file] for details.
## fs
**fs** is used to define a custom file system implementation which will be used by LiquidJS to lookup and read template files. See [Abstract File System][abstract-fs] for details.
@@ -71,9 +102,15 @@ Before 2.0.1, <code>extname</code> is set to `.liquid` by default. To change tha
it defaults to false. For example, when set to true, a blank string would evaluate to false with jsTruthy. With Shopify's truthiness, a blank string is true.
## Date
**timezoneOffset** is used to specify a different timezone to output dates, your local timezone will be used if not specified. For example, set `timezoneOffset: 0` to output all dates in UTC/GMT 00:00.
**preserveTimezones** is a boolean effects only literal timestamps. When set to `true`, all literal timestamps will remain the same when output. This is a parser option, so Date objects passed to LiquidJS as data will not be affected. Note that `preserveTimezones` has a higher priority than `timezoneOffset`.
## Trimming
**greedy**, **trimOutputLeft**, **trimOutputRight**, **trimTagLeft**, **trimTagRight** options are used to eliminate extra newlines and indents in templates arround Liquid Constructs. See [Whitespace Control][wc] for details.
**greedy**, **trimOutputLeft**, **trimOutputRight**, **trimTagLeft**, **trimTagRight** options are used to eliminate extra newlines and indents in templates around Liquid Constructs. See [Whitespace Control][wc] for details.
## Delimiter
@@ -91,10 +128,16 @@ it defaults to false. For example, when set to true, a blank string would evalu
**lenientIf** modifies the behavior of `strictVariables` to allow handling optional variables. If set to `true`, an undefined variable will *not* cause an exception in the following two situations: a) it is the condition to an `if`, `elsif`, or `unless` tag; b) it occurs right before a `default` filter. Irrelevant if `strictVariables` is not set. Defaults to `false`.
**ownPropertyOnly** hides scope variables from prototypes, useful when you're passing a not sanitized object into LiquidJS or need to hide prototypes from templates. Defaults to `false`.
{% note info Non-existent Tags %}
Non-existent tags always throw errors during pasrsing and this behaviour can not be customized.
Non-existent tags always throw errors during parsing and this behavior can not be customized.
{% endnote %}
## Parameter Order
Parameter orders are ignored by default, for ea `{% for i in (1..8) reversed limit:3 %}` will always perform `limit` before `reversed`, even if `reversed` occurs before `limit`. To make parameter order respected, set **orderedFilterParameters** to `true`. Its default value is `false`.
[liquid]: ../api/classes/liquid_.liquid.html
[caching]: ./caching.html
[abstract-fs]: ./render-file.html#Abstract-File-System
@@ -105,3 +148,4 @@ Non-existent tags always throw errors during pasrsing and this behaviour can not
[layout]: ../tags/layout.html
[wc]: ./whitespace-control.html
[intro]: ./intro-to-liquid.html
[jekyllInclude]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-jekyllInclude
+100
View File
@@ -0,0 +1,100 @@
---
title: Parse Parameters
---
## Access Raw Parameters
As covered in [Register Filters/Tags][register-tags], tag parameters is available on `tagToken.args` as a raw string. For example:
```javascript
// Usage: {% random foo bar coo %}
// Output: "foo", "bar" or "coo"
engine.registerTag('random', {
parse(tagToken) {
// tagToken.args === "foo bar coo"
this.items = tagToken.args.split(' ')
},
render(context, emitter) {
// get a random index
const index = Math.floor(this.items.length * Math.random())
// output that item
emitter.write(this.items[index])
}
})
```
Here's a JSFiddle version: <http://jsfiddle.net/ctj364up/2/>
## Parse Parameters as Values
Sometimes we need more dynamic tags and want to pass values to the custom tag instead of static strings. Variables in LiquidJS can be literal (string, number, etc.) or a variable from current context scope.
The following modified template also contains 3 values to random from, but they're values instead of static strings. The first one is string literal, second one is an identifier, third one is a property access sequence containing two identifiers.
```liquid
{% random "foo" bar obj.coo %}
```
It can be tricky to parse all these cases manually, but there's a [Tokenizer][Tokenizer] class in LiquidJS you can make use of.
```javascript
const { Liquid, Tokenizer, evalToken } = require('liquidjs')
engine.registerTag('random', {
parse(tagToken) {
const tokenizer = new Tokenizer(tagToken.args)
this.items = []
while (!tokenizer.end()) {
// here readValue() returns a LiteralToken or PropertyAccessToken
this.items.push(tokenizer.readValue())
}
},
* render(context, emitter) {
const index = Math.floor(this.items.length * Math.random())
const token = this.items[index]
// in LiquidJS, we use yield to wait for async call
const value = yield evalToken(token, context)
emitter.write(value)
}
})
```
Calling this tag in scope `{ bar: "bar", obj: { coo: "coo" } }` yields exactly the same result as the first example. See this JSFiddle: <http://jsfiddle.net/ctj364up/3/>
{% note info Async ans Promises %}
Async calls in LiquidJS are implemented by generators directly, for we can call generators in synchronous manner so this tag implementation is also valid for `renderSync()`, `parseAndRenderSync()`, `renderFileSync()`. If you need to await a promise in tag implementation, simply replace `await somePromise` with `yield somePromise` and keep `* render()` instead of `async render()` will do the trick. See <a href="/tutorials/sync-and-async.html">Sync and Async</a> for more details.
{% endnote %}
## Parse Key-Value Pairs as Named Parameters
Named parameters become very handy when there're optional parameters or lots of parameters, in which case the order of parameters is not important. This is exactly what [Hash][Hash] class is invented for.
```liquid
{% random from:2, to:max %}
```
In the above example, we're trying to generate a random number in the range [2, max]. We'll use `Hash` to parse `from` and `to` parameters.
```javascript
const { Liquid, Hash } = require('liquidjs')
engine.registerTag('random', {
parse(tagToken) {
// parse the parameters structure into `this.args`
this.args = new Hash(tagToken.args)
},
* render(context, emitter) {
// evaluate the parameters in `context`
const {from, to} = yield this.args.render(context)
const length = to - from + 1
const value = from + Math.floor(length * Math.random())
emitter.write(value)
}
})
```
Rendering `{% random from:2, to:max %}` in scope `{ max: 10 }` will generate a random number in the range [2, 10]. See this JSFiddle: <http://jsfiddle.net/ctj364up/4/>
[register-tags]: /tutorials/register-filters-tags.html
[Tokenizer]: /api/classes/parser_tokenizer_.tokenizer.html
[Hash]: /api/classes/template_tag_hash_.hash.html
@@ -28,7 +28,7 @@ color: 'yellow' shape: 'square'
More details please refer to the [render](../tags/render.html) tag.
{% note tip The &quot;.liquid&quot; Extension %}
The ".liquid" extension in <code>layout</code>, <code>render</code> and <code>include</code> an be omitted if Liquid instance is created using `extname: ".liquid"` option. See <a href="./options.html#extname">the extname option</a> for details.
The ".liquid" extension in <code>layout</code>, <code>render</code> and <code>include</code> can be omitted if Liquid instance is created using `extname: ".liquid"` option. See <a href="./options.html#extname">the extname option</a> for details.
{% endnote %}
## Layout Templates (Extends)
@@ -61,4 +61,4 @@ function disabledFilter(name) {
}
}
engine.registerFilter('plus', disabledFilter('plus'));
```
```
+9 -4
View File
@@ -68,7 +68,7 @@ Here's a demo for browsers: [demo/browser](https://github.com/harttle/liquidjs/t
## Abstract File System
LiquidJS defines an abstract file system interface in [src/fs/ifs.ts][ifs] and the default implementation is [src/fs/node.ts][fs-node] for Node.js and [src/fs/browser.ts][fs-browser] for the browser bundle.
LiquidJS defines an abstract file system interface in [src/fs/fs.ts][ifs] and the default implementation is [src/fs/node.ts][fs-node] for Node.js and [src/fs/browser.ts][fs-browser] for the browser bundle.
The `Liquid` constructor provides a [fs][fs] option to specify the file system implementation. It's supposed to be used to define customized template fetching logic, i.e. fetch template from a database table, like:
@@ -78,14 +78,17 @@ var engine = new Liquid({
readFileSync (file) {
return db.model('Template').findByIdSync(file).text
},
await readFile (file) {
async readFile (file) {
const template = await db.model('Template').findById(file)
return template.text
},
existsSync () {
return true
},
await exists () {
exists () {
return true
},
contains () {
return true
},
resolve(root, file, ext) {
@@ -95,8 +98,10 @@ var engine = new Liquid({
});
```
{% note warn Path Traversal Vulnerability %}The default value of <code>contains()</code> always returns true. That means when specifying an abstract file system, you'll need to provide a proper <code>contains()</code> to avoid expose such vulnerabilities.{% endnote %}
[fs]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-fs
[ifs]: https://github.com/harttle/liquidjs/blob/master/src/fs/ifs.ts
[ifs]: https://github.com/harttle/liquidjs/blob/master/src/fs/fs.ts
[fs-node]: https://github.com/harttle/liquidjs/blob/master/src/fs/node.ts
[fs-browser]: https://github.com/harttle/liquidjs/blob/master/src/fs/browser.ts
[layout]: https://help.shopify.com/en/themes/liquid/tags/theme-tags#layout
+137
View File
@@ -0,0 +1,137 @@
---
title: Render Tag Content
---
Custom tags can have content template and can be nested. This article describes how to implement custom tags that consists of a *begin tag*, an *end tag*, and template content between them.
## Render Tag Content
We'll start with a simple tag `wrap` which wraps its content into a `<div class="wrapper"></div>` element:
```liquid
{% wrap %}
{{ "hello world!" | capitalize }}
{% endwrap %}
```
Expected output:
```html
<div class='wrapper'>
Hello world!
</div>
```
Firstly, [register][register-tags] a tag with name `wrap` and parse the content into `this.tpls`. Here in `parse(tagToken, remainTokens)`,
- `tagToken` is current token `{% wrap %}`, and
- `remainTokens` is an array of all tokens following `{% wrap %}` until the end of this template file.
Basically, what we need to do is take/`.shift()` enough tags from `remainTokens` until we got a `endwrap` token (the name can be arbitrary, but in convention, we need it to be `endwrap`). And if there's no `endwrap` until the end of template file, we need to throw an tag-not-closed `Error`.
```javascript
engine.registerTag('wrap', {
parse(tagToken, remainTokens) {
this.tpls = []
let closed = false
while(remainTokens.length) {
let token = remainTokens.shift()
// we got the end tag! stop taking tokens
if (token.name === 'endwrap') {
closed = true
break
}
// parse token into template
// parseToken() may consume more than 1 tokens
// e.g. {% if %}...{% endif %}
let tpl = this.liquid.parser.parseToken(token, remainTokens)
this.tpls.push(tpl)
}
if (!closed) throw new Error(`tag ${tagToken.getText()} not closed`)
},
* render(context, emitter) {
emitter.write("<div class='wrapper'>")
yield this.liquid.renderer.renderTemplates(this.tpls, context, emitter)
emitter.write("</div>")
}
})
```
`.renderTemplates()` can be async, we need `yield` to wait it complete. More details on async in LiquidJS, please refer to [Sync and Async][async]. Other parts of `render()` method is quite straightforward. Here's a JSFiddle version: <http://jsfiddle.net/por0zcn1/3/>
## Using ParseStream
When it comes to complex tags like [for][for] and [if][if], the `parse()` can be very complicated. There's a [ParseStream][ParseStream] utility to organize the `parse()` in event-based style. Following is a re-written `parse()` using `ParseStream` and does exactly the same as above example.
```javascript
parse(tagToken, remainTokens) {
this.tpls = []
this.liquid.parser.parseStream(remainTokens)
.on('template', tpl => this.tpls.push(tpl))
// note that we cannot use arrow function because we need `this`
.on('tag:endwrap', function () { this.stop() })
.on('end', () => { throw new Error(`tag ${tagToken.getText()} not closed`) })
.start()
}
```
Here's a JSFiddle version: <http://jsfiddle.net/por0zcn1/4/>. For simplicity, the following examples are implemented using `ParseStream`.
## Manipulate the Context
The `wrap` tag above doesn't seem to be very useful, without using that tag we can render the content anyway. Now we're going to implement a `repeat` tag to render the content 2 times (we can also add a [parameter][parameter] to render arbitrary times).
```liquid
{% repeat %}
{{ repeat.i }}. {{ "hello world!" | capitalize }}
{% endrepeat %}`
```
Expected outputs:
```html
1. Hello world!
2. Hello world!
```
As you've noticed, there's an additional `repeat.i` in the context of `repeat`. That is implemented by manipulating the *Context*.
{% note info Context %}
<em>Context</em> defines the value of each variable in Liquid template. In LiquidJS, a `Context` consists of a stack of `Scope`s. A *Scope* is a plain object like the one specified in `engine.render(tpl, scope)`.
{% endnote %}
Each time we enter a new *Context*, we need to push a new *Scope*. And when we finish rendering and exit the *Context*, we pop the *Scope* from the *Context*. As you can see in the following implementation:
```javascript
engine.registerTag('repeat', {
parse(tagToken, remainTokens) {
this.tpls = []
this.liquid.parser.parseStream(remainTokens)
.on('template', tpl => this.tpls.push(tpl))
.on('tag:endrepeat', function () { this.stop() })
.on('end', () => { throw new Error(`tag ${tagToken.getText()} not closed`) })
.start()
},
* render(context, emitter) {
const repeat = { i: 1 }
context.push({ repeat })
yield this.liquid.renderer.renderTemplates(this.tpls, context, emitter)
repeat.i++
yield this.liquid.renderer.renderTemplates(this.tpls, context, emitter)
context.pop()
}
})
```
The `parse()` is exactly the same as `wrap` tag, we repeat the content simply by calling `.renderTemplates(this.tpls)` twice during `render()`. Here's the JSFiddle: <http://jsfiddle.net/por0zcn1/2/>
{% note warn Use Push & Pop in Pairs %}
`context.push()` and `context.pop()` have to be used in pairs. Failing to `pop()` the *Scope* you pushed will leak the *Scope* to latter templates and may corrupt the *Context* stack.
{% endnote %}
[register-tags]: ./register-filters-tags.html
[async]: ./sync-and-async.html
[for]: ../tags/for.html
[if]: ../tags/if.html
[ParseStream]: ../api/classes/parser_parse_stream_.parsestream.html
[parameter]: ./parse-parameters.html
+90
View File
@@ -0,0 +1,90 @@
---
title: Sync and Async
---
LiquidJS supports both sync and async evaluate, and can be used with Promises. To reuse the same set of tag/filter implementations in both sync and async, LiquidJS tags are implemented as generators.
## Sync and Async API
All major methods on [Liquid][Liquid] supports both sync and async. These methods return Promises:
- `render()`
- `renderFile()`
- `parseFile()`
- `parseAndRender()`
- `evalValue()`
The synchronous version of methods contains a `Sync` suffix:
- `renderSync()`
- `renderFileSync()`
- `parseFileSync()`
- `parseAndRenderSync()`
- `evalValueSync()`
## Implement Sync-Compatible Tags
### Requirements
All builtin tags are *sync-compatible* and safe to use for both sync and async APIs. To make your custom tag *sync-compatible*, you'll need to avoid return a `Promise`. That means the `render(context, emitter)`:
- Should not directly `return <Promise>`, and
- Should not be declared as `async`.
{% note info Non Sync-Compatible Tags %}
Non <em>sync-compatible</em> tags are also valid tags, will work just fine for asynchronous API calls. When called synchronously, tags that return a <code>Promise</code> will be rendered as <code>[object Promise]</code>.
{% endnote %}
### Await Promises
But LiquidJS is Promise-friendly, right? You can still call Promise-based functions and wait for that Promise within tag implementations. Just replace `await` with `yield` and keep `* render()` instead of `async render()`. e.g.
```typescript
import { TagToken, Context, Emitter, TopLevelToken } from 'liquidjs'
// Usage: {% upper "alice" %}
// Output: ALICE
engine.registerTag('upper', {
parse: function(tagToken: TagToken, remainTokens: TopLevelToken[]) {
this.str = tagToken.args
},
* render: function(ctx: Context) {
// _evalValue will behave synchronously when called by synchronous API
// in which case `ctx.sync == true`
var str = yield this.liquid._evalValue(this.str, ctx)
return str.toUpperCase()
}
})
```
See this JSFiddle: <http://jsfiddle.net/ctj364up/6/>.
## Async-only Tags
For tags that intended to be used only by async API, or those cannot be implemented synchronously, there's no difference between using generator-base syntax or async syntax. I'll call them *async-only tags*.
For example, if the above `this.liquid._evalValue()` doesn't respect `ctx.sync` and always returns a Promise, even if the tag is implemented using `* render()` and `yield this.liquid._evalValue()`, it will be rendered as `<object Promise>` anyway.
For *async-only tags*, you can use async syntax at will. Be careful some APIs in LiquidJS return Promises and others return Generators. You'll need [toPromise][toPromise] API to convert a Generator to a Promise, for example:
```typescript
import { TagToken, Context, Emitter, TopLevelToken, toPromise } from 'liquidjs'
// Usage: {% upper "alice" %}
// Output: ALICE
engine.registerTag('upper', {
parse: function(tagToken: TagToken, remainTokens: TopLevelToken[]) {
this.str = tagToken.args; // name
},
render: async function(ctx: Context) {
var str = await toPromise(this.liquid._evalValue(this.str, ctx));
// Or use the alternate API that returns a Promise
// var str = await this.liquid.evalValue(this.str, ctx);
return str.toUpperCase()
}
});
```
See this JSFiddle: <http://jsfiddle.net/ctj364up/5/>.
[Liquid]: /api/classes/liquid_.liquid.html
[toPromise]: /api/modules/liquid_.html#toPromise
+2 -2
View File
@@ -41,7 +41,7 @@ Alternatively, LiquidJS provides these per engine options to enable whitespace c
* `trimTagLeft`
* `trimTagRight`
* `trimValueRight`
* `trimValueLeft`
* `trimValueRight`
[LiquidJS][liquidjs] will **NOT** trim any whitespace by default, aka. above options all default to `false`. For details of these options, see the [options][options].
@@ -53,4 +53,4 @@ In greedy mode (enabled by the [greedy option][greedy]), all consecutive whitesp
[shopify/liquid]: https://github.com/Shopify/liquid
[liquidjs]: https://github.com/harttle/liquidjs
[options]: ../api/interfaces/liquid_options_.liquidoptions.html
[greedy]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-greedy
[greedy]: ../api/interfaces/liquid_options_.liquidoptions.html#Optional-greedy
+4 -2
View File
@@ -2,7 +2,9 @@
title: concat
---
Concatenates (joins together) multiple arrays. The resulting array contains all the items from the input arrays.
{% since %}v2.0.0{% endsince %}
连接多个数组,返回的数组包含所有传入数组的元素。
输入
```liquid
@@ -26,7 +28,7 @@ Concatenates (joins together) multiple arrays. The resulting array contains all
- potatoes
```
You can string together `concat` filters to join more than two arrays:
可以链式地使用 `concat` 过滤器来连接多个数组:
输入
```liquid
+8
View File
@@ -16,6 +16,10 @@ title: date
Fri, Jul 17, 15
```
{% note info 时区 %}
日期在输出时会转换为当地时区,设置 `timezoneOffset` LiquidJS 参数可以指定一个不同的时区。或者设置 `preserveTimezones``true` 来保持字面量时间戳的时区,数据中的日期对象不受此参数的影响。
{% endnote %}
输入
```liquid
{{ article.published_at | date: "%Y" }}
@@ -38,6 +42,10 @@ Fri, Jul 17, 15
Mar 14, 16
```
{% note info 时间戳字符串 %}
LiquidJS 使用 JavaScript [Date][newDate] 来解析输入字符串,意味着支持 [IETF-compliant RFC 2822 时间戳](https://datatracker.ietf.org/doc/html/rfc2822#page-14) 和 [特定版本的 ISO8601](https://www.ecma-international.org/ecma-262/11.0/#sec-date.parse)。
{% endnote %}
可以用特殊值 `"now"`(或`"today"`)来获取当前时间:
输入
+19
View File
@@ -42,4 +42,23 @@ title: default
2.99
```
## 允许 `false`
{% since %}v9.32.0{% endsince %}
为了允许让 `false` 直接输出而不是用默认值,可以用 `allow_false` 参数。
输入
```liquid
{% assign display_price = false %}
{{ display_price | default: true, allow_false: true }}
```
输出
```text
false
```
[falsy]: ../tutorials/truthy-and-falsy.html
+18 -1
View File
@@ -26,6 +26,23 @@ title: divided_by
1.6666666666666667
```
{% note info Integer Arithmetic %}Since JavaScript doesn't differentiate integers and floats, LiquidJS is not capable of integer arithmetic and the return type is always `number`, the string representation of which depends on its value.{% endnote %}
在 JavaScript 里数字没有浮点和整数的区分,它们的类型都是 `number`
```javascript
// always true
5.0 === 5
```
因此如果需要做整数运算,需要传入额外的 `integerArithmetic` 参数:
Input
```liquid
{{ 5 | divided_by: 3, true }}
```
Output
```text
1
```
[floor]: ./floor.html
+4 -2
View File
@@ -1,5 +1,6 @@
---
title: 过滤器
description: 每个 Liquid 过滤器的描述和示例
---
LiquidJS 支持 Liquid 语法中具体业务无关的过滤器,基本上 [shopify/liquid 核心][shopify/liquid] 支持的 LiquidJS 都支持。这部分包含了所有 LiquidJS 支持的过滤器的文档和使用示例。
@@ -8,10 +9,11 @@ LiquidJS 共支持 40+ 个过滤器,可以分为如下几类:
类别 | 过滤器
--- | ---
数学 | plus, minus, modulo, times, floor, ceil, round, divided_by, abs
数学 | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most
字符串 | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, remove, remove_first, truncate, truncatewords
HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br
数组 | slice, map, sort, sort_natural, uniq, wheres, first, last, join, reverse
数组 | slice, map, sort, sort_natural, uniq, wheres, first, last, join, reverse, concat, compact, size
日期 | date
其他 | default, json
[shopify/liquid]: https://github.com/Shopify/liquid
+52
View File
@@ -0,0 +1,52 @@
---
title: raw
---
{% since %}v9.37.0{% endsince %}
直接返回变量的值。配合 [outputEscape](/api/interfaces/liquid_options_.liquidoptions.html#Optional-outputEscape) 参数使用。
{% note info 自动转义 %}
默认情况下 `outputEscape``undefined`,这意味着 LiquidJS 输出不会默认转义,因此这时使用 `raw` 没有意义。
{% endnote %}
输入(未设置 `outputEscape`
```liquid
{{ "<" }}
```
输出
```text
<
```
输入(`outputEscape="escape"`
```liquid
{{ "<" }}
```
输出
```text
&lt;
```
输入(`outputEscape="json"`
```liquid
{{ "<" }}
```
输出
```text
"<"
```
输入(`outputEscape="escape"`
```liquid
{{ "<" | raw }}
```
输出
```text
<
```
+1 -1
View File
@@ -4,7 +4,7 @@ title: upcase
{% since %}v1.9.1{% endsince %}
字符串中每个字符都转为大写,对已经是写的字符没有影响。
字符串中每个字符都转为大写,对已经是写的字符没有影响。
输入
```liquid
+1 -1
View File
@@ -1,5 +1,5 @@
layout: index
description: LiquidJS is a simple, expressive and safe template engine.
description: LiquidJS 是一个纯 JavaScript 实现的,简洁的、安全的模板引擎,兼容 Shopify / Github Pages。
subtitle: 简单安全的 Liquid 模板引擎
---
ul#intro-feature-list
+58
View File
@@ -0,0 +1,58 @@
{
"short_name": "LiquidJS",
"name": "LiquidJS",
"description": "LiquidJS 是一个简单的、安全的、兼容 Shopify 的、纯 JavaScript 编写的模板引擎。",
"icons": [
{
"src": "/icon/apple-touch-icon-57x57.png",
"type": "image/png",
"sizes": "57x57"
},
{
"src": "/icon/favicon-96x96.png",
"type": "image/png",
"sizes": "96x96"
},
{
"src": "/icon/favicon-196x196.png",
"type": "image/png",
"sizes": "196x196"
},
{
"src": "/icon/apple-touch-icon.png",
"type": "image/png",
"sizes": "512x512"
}
],
"shortcuts" : [
{
"name": "教程",
"url": "/zh-cn/tutorials/intro-to-liquid.html",
"description": "一系列描述如何使用 LiquidJS 的文章"
},
{
"name": "标签",
"url": "/zh-cn/tags/overview.html",
"description": "每个 Liquid 标签的描述和示例"
},
{
"name": "过滤器",
"url": "/zh-cn/filters/overview.html",
"description": "每个 Liquid 过滤器的描述和示例"
},
{
"name": "演示",
"url": "/zh-cn/playground.html",
"description": "一个用来尝试和分享 Liquid 模板的在线编辑器"
},
{
"name": "API",
"url": "/zh-cn/api/classes/liquid_.liquid.html",
"description": "LiquidJS 类和接口的 TypeScript 文档"
}
],
"start_url": "/zh-cn",
"display": "standalone",
"theme_color": "#0f83ce",
"background_color": "#0f83ce"
}
+2
View File
@@ -1,3 +1,5 @@
---
layout: playground
title: 演示
description: 一个用来尝试和分享 Liquid 模板的在线编辑器
---

Some files were not shown because too many files have changed in this diff Show More