Compare commits

...
106 Commits
Author SHA1 Message Date
Yang Jun 292a93b738 docs: fix liquid snippet lighlight 2024-08-20 09:23:52 +08:00
Yang Jun 5b1658c823 docs: fix styles and escape 2024-08-20 03:35:37 +08:00
Yang Jun b1f0260dcb docs: Add WISMOlabs use case into README 2024-08-18 13:44:20 +08:00
semantic-release-bot 4fdbce2459 chore(release): 10.16.3 [skip ci]
## [10.16.3](https://github.com/harttle/liquidjs/compare/v10.16.2...v10.16.3) (2024-08-16)

### Bug Fixes

* support for NodeJS 15, fixes [#732](https://github.com/harttle/liquidjs/issues/732) ([4548c11](https://github.com/harttle/liquidjs/commit/4548c1140629bf270d163a403c2994d785c7f710))
2024-08-16 16:56:46 +00:00
Jun YangandGitHub e941378535 docs: add internal types in apidoc (#734)
* docs: add internal types in apidoc

* chore: downgrade package-lock version for NodeJS 14

* test: test case when performance uses Date.now
2024-08-17 00:55:24 +08:00
Yang Jun 4548c11406 fix: support for NodeJS 15, fixes #732 2024-08-16 23:40:48 +08:00
semantic-release-bot 22ba21d63f chore(release): 10.16.2 [skip ci]
## [10.16.2](https://github.com/harttle/liquidjs/compare/v10.16.1...v10.16.2) (2024-08-15)

### Bug Fixes

* support for NodeJS 14 ([85bd0d3](https://github.com/harttle/liquidjs/commit/85bd0d35a6d949a02db49ba546407fe5be17db5e))
2024-08-15 17:39:09 +00:00
Yang Jun 85bd0d35a6 fix: support for NodeJS 14 2024-08-16 01:36:42 +08:00
Yang Jun f8bb63a1bb chore: check node 14 on pipeline 2024-08-16 01:36:33 +08:00
Jun YangandGitHub c6a6ef1a1f chore: check node@14 on pipeline, #728 (#731) 2024-08-16 00:55:14 +08:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
6fb707f9c4 docs: add vrugtehagel as a contributor for code (#730)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-08-15 22:40:05 +08:00
KoenandGitHub f03247d420 Import performance object from perf_hooks (#729) 2024-08-15 22:37:46 +08:00
semantic-release-bot ebc8daeec9 chore(release): 10.16.1 [skip ci]
## [10.16.1](https://github.com/harttle/liquidjs/compare/v10.16.0...v10.16.1) (2024-07-25)

### Bug Fixes

* parser throws on non-string input, [#726](https://github.com/harttle/liquidjs/issues/726) ([21a8223](https://github.com/harttle/liquidjs/commit/21a822348f3c315dae56fba2674ad3db0cf2f80d))
2024-07-25 12:07:55 +00:00
Yang Jun 21a822348f fix: parser throws on non-string input, #726 2024-07-25 20:06:12 +08:00
semantic-release-bot fce2899e88 chore(release): 10.16.0 [skip ci]
# [10.16.0](https://github.com/harttle/liquidjs/compare/v10.15.0...v10.16.0) (2024-07-21)

### Features

* locale support for date filter, [#567](https://github.com/harttle/liquidjs/issues/567) ([#723](https://github.com/harttle/liquidjs/issues/723)) ([e4aeb02](https://github.com/harttle/liquidjs/commit/e4aeb023fddf5ead90db209599cfd99450274658))
2024-07-21 16:41:22 +00:00
Jun YangandGitHub e4aeb023fd feat: locale support for date filter, #567 (#723) 2024-07-22 00:39:44 +08:00
semantic-release-bot 542a75fd44 chore(release): 10.15.0 [skip ci]
# [10.15.0](https://github.com/harttle/liquidjs/compare/v10.14.0...v10.15.0) (2024-07-09)

### Bug Fixes

* report error for malformed else/elsif/endif/endfor, [#713](https://github.com/harttle/liquidjs/issues/713) ([22b5a12](https://github.com/harttle/liquidjs/commit/22b5a123333a066aaf7dff580df061e7cd6aa7b2))

### Features

* DoS prevention, [#250](https://github.com/harttle/liquidjs/issues/250) ([e443068](https://github.com/harttle/liquidjs/commit/e443068cb9281883ff0fe9f755a15f52ada4e7e2))
* support in-memory template mapping, inspired by [@jg-rp](https://github.com/jg-rp) [#714](https://github.com/harttle/liquidjs/issues/714) ([df27ac6](https://github.com/harttle/liquidjs/commit/df27ac694739496982012432077fe28b1476662a))
2024-07-09 14:52:55 +00:00
Yang Jun e443068cb9 feat: DoS prevention, #250 2024-07-09 22:51:11 +08:00
Yang Jun fad00aa14e test: edge cases for map fs 2024-07-09 22:51:11 +08:00
Harttle df27ac6947 feat: support in-memory template mapping, inspired by @jg-rp #714 2024-07-08 02:25:25 +08:00
Harttle 834328b9cb docs: add @15fathoms as financial contributor 2024-07-08 02:24:58 +08:00
Harttle 22b5a12333 fix: report error for malformed else/elsif/endif/endfor, #713 2024-07-05 01:23:33 +08:00
Harttle d141c4bdd2 docs: update LiquidJS description about dependency 2024-06-25 22:59:44 +08:00
semantic-release-bot 53489641ac chore(release): 10.14.0 [skip ci]
# [10.14.0](https://github.com/harttle/liquidjs/compare/v10.13.1...v10.14.0) (2024-06-17)

### Bug Fixes

* use drop `valueOf` when evaluated as condition ([#705](https://github.com/harttle/liquidjs/issues/705)) ([a7da93f](https://github.com/harttle/liquidjs/commit/a7da93ff0f2c1c66f9c85b45ffcc1326c23254c7))

### Features

* support catching all errors, [#220](https://github.com/harttle/liquidjs/issues/220) ([#710](https://github.com/harttle/liquidjs/issues/710)) ([3b5627b](https://github.com/harttle/liquidjs/commit/3b5627b04072b1d6703ef5ba782a3a0f26fd2a60))
2024-06-17 14:52:35 +00:00
Jun YangandGitHub 3b5627b040 feat: support catching all errors, #220 (#710) 2024-06-17 22:48:57 +08:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
612da52275 docs: add jsoref as a contributor for doc (#709)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-06-17 17:20:45 +08:00
a0ea372764 docs: fix some spelling (#708)
* spelling: according

Signed-off-by: Josh Soref <[email protected]>

* spelling: asynchronously

Signed-off-by: Josh Soref <[email protected]>

* spelling: background

Signed-off-by: Josh Soref <[email protected]>

* spelling: camel

Signed-off-by: Josh Soref <[email protected]>

* spelling: cannot

Signed-off-by: Josh Soref <[email protected]>

* spelling: case-sensitive

Signed-off-by: Josh Soref <[email protected]>

* spelling: comparison

Signed-off-by: Josh Soref <[email protected]>

* spelling: demos

Signed-off-by: Josh Soref <[email protected]>

* spelling: forloop

Signed-off-by: Josh Soref <[email protected]>

* spelling: formatters

Signed-off-by: Josh Soref <[email protected]>

* spelling: github

Signed-off-by: Josh Soref <[email protected]>

* spelling: guidelines

Signed-off-by: Josh Soref <[email protected]>

* spelling: hashes

Signed-off-by: Josh Soref <[email protected]>

* spelling: https

Signed-off-by: Josh Soref <[email protected]>

* spelling: javascript

Signed-off-by: Josh Soref <[email protected]>

* spelling: keep

Signed-off-by: Josh Soref <[email protected]>

* spelling: natural

Signed-off-by: Josh Soref <[email protected]>

* spelling: neither

Signed-off-by: Josh Soref <[email protected]>

* spelling: no longer

Signed-off-by: Josh Soref <[email protected]>

* spelling: nonexistent

Signed-off-by: Josh Soref <[email protected]>

* spelling: output

Signed-off-by: Josh Soref <[email protected]>

* spelling: polymorphism

Signed-off-by: Josh Soref <[email protected]>

* spelling: precache

Signed-off-by: Josh Soref <[email protected]>

* spelling: programmatically

Signed-off-by: Josh Soref <[email protected]>

* spelling: punctuation

Signed-off-by: Josh Soref <[email protected]>

* spelling: registration

Signed-off-by: Josh Soref <[email protected]>

* spelling: rendered

Signed-off-by: Josh Soref <[email protected]>

* spelling: synchronously

Signed-off-by: Josh Soref <[email protected]>

* spelling: thrown

Signed-off-by: Josh Soref <[email protected]>

* spelling: trimmed

Signed-off-by: Josh Soref <[email protected]>

* spelling: unbalanced

Signed-off-by: Josh Soref <[email protected]>

* chore: use example.com

* chore: fix reference for sidebar.registration

---------

Signed-off-by: Josh Soref <[email protected]>
Co-authored-by: Harttle <[email protected]>
2024-06-17 17:19:46 +08:00
Adam TannerandGitHub a7da93ff0f fix: use drop valueOf when evaluated as condition (#705) 2024-06-05 08:28:21 +08:00
semantic-release-bot 513940dfa7 chore(release): 10.13.1 [skip ci]
## [10.13.1](https://github.com/harttle/liquidjs/compare/v10.13.0...v10.13.1) (2024-05-24)

### Bug Fixes

* allow liquidMethodMissing to return any supported value type ([#698](https://github.com/harttle/liquidjs/issues/698)) ([0983f2c](https://github.com/harttle/liquidjs/commit/0983f2c42012b2b97258d0cdcb07b6d43c904814))
* isComparable full interface check ([#701](https://github.com/harttle/liquidjs/issues/701)) ([55e144a](https://github.com/harttle/liquidjs/commit/55e144a0298047349d55d8483a46b2513303d940))
2024-05-24 02:39:11 +00:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
8f700ae10a docs: add GuillermoCasalCaro as a contributor for code (#702)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-05-24 10:37:16 +08:00
55e144a029 fix: isComparable full interface check (#701)
* Improve isComparable function to ensure full Comparable interface implementation

* Deleted trailing commas

---------

Co-authored-by: Guillermo Casal Caro <[email protected]>
2024-05-24 10:35:49 +08:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
6ca5376362 docs: add admtnnr as a contributor for code (#699)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-05-22 12:36:50 +08:00
0983f2c420 fix: allow liquidMethodMissing to return any supported value type (#698)
* fix: allow liquidMethodMissing to return any supported value type

* Update src/drop/drop.ts

Co-authored-by: Jun Yang <[email protected]>

---------

Co-authored-by: Jun Yang <[email protected]>
2024-05-22 12:35:46 +08:00
allcontributors[bot]andJun Yang 12001b6161 docs: update .all-contributorsrc [skip ci] 2024-05-14 18:21:36 +08:00
allcontributors[bot]andJun Yang 7591ddc161 docs: update README.md [skip ci] 2024-05-14 18:21:36 +08:00
Cosmin PopoviciandJun Yang 3b24f079ea docs: update broken link
updated broken link to shopify/liquid differences page
2024-05-14 18:20:54 +08:00
semantic-release-bot bd571d19d1 chore(release): 10.13.0 [skip ci]
# [10.13.0](https://github.com/harttle/liquidjs/compare/v10.12.0...v10.13.0) (2024-05-13)

### Features

* array_to_sentence_string and number_of_words filters from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([50253a9](https://github.com/harttle/liquidjs/commit/50253a98caf5356d3c33e148be66f34fbe75a204))
* date filters from Jekyll ([4955e75](https://github.com/harttle/liquidjs/commit/4955e75be7f38a3fd15e71f2c192cff6f0d6e2d5))
* escape filters from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([b12eb8a](https://github.com/harttle/liquidjs/commit/b12eb8ab4b58b002459725b6c0ed00159cdc15e6))
* jsonify, inspect, to_integer, normalize_whitespace filters ([842b45c](https://github.com/harttle/liquidjs/commit/842b45c96a46290a1e1ba43fc5cc7a465f4ba9de))
* slugify filter from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([47ddc11](https://github.com/harttle/liquidjs/commit/47ddc1193b84bbdeb8d48457bb5aead24d5aff77))
2024-05-13 15:56:11 +00:00
Yang Jun 47ddc1193b feat: slugify filter from Jekyll, #443 2024-05-13 23:54:07 +08:00
Yang Jun 50253a98ca feat: array_to_sentence_string and number_of_words filters from Jekyll, #443 2024-05-13 00:38:52 +08:00
Yang Jun b12eb8ab4b feat: escape filters from Jekyll, #443 2024-05-12 15:05:36 +08:00
Yang Jun 4955e75be7 feat: date filters from Jekyll 2024-05-09 23:37:27 +08:00
Yang Jun 842b45c96a feat: jsonify, inspect, to_integer, normalize_whitespace filters 2024-05-06 21:10:27 +08:00
semantic-release-bot ea0eab93d1 chore(release): 10.12.0 [skip ci]
# [10.12.0](https://github.com/harttle/liquidjs/compare/v10.11.1...v10.12.0) (2024-04-28)

### Bug Fixes

* case/when array equality, [#673](https://github.com/harttle/liquidjs/issues/673) ([2b63035](https://github.com/harttle/liquidjs/commit/2b630353c478368cb36dbfcb38961b25bf48249e))

### Features

* introduce where_exp filter from Jekyll ([8c7cef9](https://github.com/harttle/liquidjs/commit/8c7cef9f95cda765164ada8d58af7d402b3d3143))
2024-04-28 15:18:37 +00:00
Yang JunandJun Yang 76a7fb738e chore: use Node@20 to build 2024-04-28 23:17:01 +08:00
Yang JunandJun Yang 2b630353c4 fix: case/when array equality, #673 2024-04-28 23:17:01 +08:00
Yang JunandJun Yang 8c7cef9f95 feat: introduce where_exp filter from Jekyll 2024-04-28 23:17:01 +08:00
Yang JunandJun Yang 303a0d44b5 docs: add customerio as contributor 2024-04-28 23:17:01 +08:00
semantic-release-bot 28ebe11d26 chore(release): 10.11.1 [skip ci]
## [10.11.1](https://github.com/harttle/liquidjs/compare/v10.11.0...v10.11.1) (2024-04-21)

### Bug Fixes

* allow %Z for TimezoneDate, update docs accordingly [#684](https://github.com/harttle/liquidjs/issues/684) ([e09657c](https://github.com/harttle/liquidjs/commit/e09657c52b5e9920256d73f99455e2e81cadf065))
* Allow `lenientIf` for multiple operands (issue [#682](https://github.com/harttle/liquidjs/issues/682)) ([#683](https://github.com/harttle/liquidjs/issues/683)) ([490ff43](https://github.com/harttle/liquidjs/commit/490ff4309cc231a25be23df5374a5d032aac144e))
2024-04-21 08:09:13 +00:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
fdec831e5c docs: add amedve as a contributor for code (#686)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-04-21 16:07:34 +08:00
Max MedveandGitHub 490ff4309c fix: Allow lenientIf for multiple operands (issue #682) (#683)
* allow `lenientIf` for multiple operands

* update tests
2024-04-21 16:04:38 +08:00
Yang JunandJun Yang e09657c52b fix: allow %Z for TimezoneDate, update docs accordingly #684 2024-04-21 15:57:43 +08:00
semantic-release-bot d48ac56824 chore(release): 10.11.0 [skip ci]
# [10.11.0](https://github.com/harttle/liquidjs/compare/v10.10.2...v10.11.0) (2024-04-14)

### Features

* group_by/group_by_exp/find/find_exp from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([2b713b7](https://github.com/harttle/liquidjs/commit/2b713b721d1f355309a70ebb5846169c6c03c523))
* pop/shift/unshift filters from Jekyll ([258780e](https://github.com/harttle/liquidjs/commit/258780e9a87ce87534a6bb4336725cb1d38a2998))
2024-04-14 11:36:01 +00:00
Jun Yang 2b713b721d feat: group_by/group_by_exp/find/find_exp from Jekyll, #443 2024-04-14 19:34:07 +08:00
Jun Yang 258780e9a8 feat: pop/shift/unshift filters from Jekyll 2024-04-14 19:34:07 +08:00
Jun Yang 18d55929e5 docs: add docs for push filter 2024-04-14 19:34:07 +08:00
Jun Yang ccd83bc6bd docs: fix build status badge 2024-03-30 21:23:56 +08:00
semantic-release-bot 306b070507 chore(release): 10.10.2 [skip ci]
## [10.10.2](https://github.com/harttle/liquidjs/compare/v10.10.1...v10.10.2) (2024-03-21)

### Bug Fixes

* contains regression ([#677](https://github.com/harttle/liquidjs/issues/677)) ([05223c4](https://github.com/harttle/liquidjs/commit/05223c4378f9474f4e658af36cb8272e161d681f)), closes [#675](https://github.com/harttle/liquidjs/issues/675)
2024-03-21 15:57:46 +00:00
Jun YangandGitHub 05223c4378 fix: contains regression (#677)
* fix: `contains` regression on string-like objects, #675

* chore: fix build docs on macos
2024-03-21 23:56:10 +08:00
Harttle 01029aba87 docs: try to include all sponsors/backers 2024-03-11 22:06:17 +08:00
semantic-release-bot 902a8e4c22 chore(release): 10.10.1 [skip ci]
## [10.10.1](https://github.com/harttle/liquidjs/compare/v10.10.0...v10.10.1) (2024-02-18)

### Bug Fixes

* in conditionals, don't render anything after an else branch ([#671](https://github.com/harttle/liquidjs/issues/671)) ([f816955](https://github.com/harttle/liquidjs/commit/f81695570491ede77975de2c26a07612a2d62c28))
* Rely on equal for computing contains ([#668](https://github.com/harttle/liquidjs/issues/668)) ([1937aa1](https://github.com/harttle/liquidjs/commit/1937aa1f1dce01ee6332f39a6e658e85cbe4f30b))
2024-02-18 05:33:31 +00:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
08421ea70c docs: add joel-hamilton as a contributor for code (#674)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-02-18 13:31:18 +08:00
f816955704 fix: in conditionals, don't render anything after an else branch (#671)
* fix: only render the first 'else' template in the case of multiples

* fix: empty else block and cases with when conditions

* fix: don't render elsif after else

* chore: Update src/tags/unless.ts

* chore: Update src/tags/if.ts

* chore: Update src/tags/case.ts

---------

Co-authored-by: Jun Yang <[email protected]>
2024-02-18 13:30:16 +08:00
1937aa1f1d fix: Rely on equal for computing contains (#668)
* fix: rely on equal for computing contains

This change allows contains to be computed using the toValue of the items in the array.
Before this change if I had an array of "Drop" `contains` would not match against the value.

* Apply suggestions from code review

Co-authored-by: Jun Yang <[email protected]>

---------

Co-authored-by: Jun Yang <[email protected]>
2024-02-14 10:19:32 +08:00
allcontributors[bot]andJun Yang 4518a19588 docs: update .all-contributorsrc [skip ci] 2024-01-14 20:57:06 +08:00
allcontributors[bot]andJun Yang dafdfbc849 docs: update README.md [skip ci] 2024-01-14 20:57:06 +08:00
fupeng1andJun Yang 3632623456 chore: adjust typings dir 2024-01-14 20:55:59 +08:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
85f5b327fa docs: add brunodccarvalho as a contributor for code (#662)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-12-19 20:08:24 +08:00
semantic-release-bot 9347586cb5 chore(release): 10.10.0 [skip ci]
# [10.10.0](https://github.com/harttle/liquidjs/compare/v10.9.4...v10.10.0) (2023-12-19)

### Features

* Array sum filter ([#661](https://github.com/harttle/liquidjs/issues/661)) ([629d958](https://github.com/harttle/liquidjs/commit/629d958b86a97ddf2921d2285b7c9ea83430004e))
2023-12-19 12:06:51 +00:00
629d958b86 feat: Array sum filter (#661)
* feat(filters): add array sum filter

* docs(filters): array sum filter

* docs: update versoin number in source/filters/sum.md

---------

Co-authored-by: Jun Yang <[email protected]>
2023-12-19 20:05:15 +08:00
Harttle fe978c8cd9 docs: Liquid Drops 2023-11-29 21:53:09 +08:00
semantic-release-bot 8ff9aea8ce chore(release): 10.9.4 [skip ci]
## [10.9.4](https://github.com/harttle/liquidjs/compare/v10.9.3...v10.9.4) (2023-11-04)

### Bug Fixes

* allow unicode to be identifiers, fixes [#655](https://github.com/harttle/liquidjs/issues/655) ([dd7616a](https://github.com/harttle/liquidjs/commit/dd7616acb9a71b77f39d2fa24b6f68a7caef87f1))
2023-11-04 13:36:47 +00:00
Harttle dd7616acb9 fix: allow unicode to be identifiers, fixes #655 2023-11-04 21:33:29 +08:00
allcontributors[bot]andJun Yang d75ac93390 docs: update .all-contributorsrc [skip ci] 2023-10-31 19:57:42 +08:00
allcontributors[bot]andJun Yang 2caeeda1c1 docs: update README.md [skip ci] 2023-10-31 19:57:42 +08:00
Rasmus Wriedt LarsenandJun Yang 6ebf2ee427 docs: fix typo (ans => and) 2023-10-31 19:55:19 +08:00
semantic-release-bot 3bd825afb0 chore(release): 10.9.3 [skip ci]
## [10.9.3](https://github.com/harttle/liquidjs/compare/v10.9.2...v10.9.3) (2023-10-15)

### Bug Fixes

* package version in released files ([67a5b22](https://github.com/harttle/liquidjs/commit/67a5b229ca9ccabb4aee42bbb5c9f03d4076786a))
2023-10-15 13:11:10 +00:00
Harttle 67a5b229ca fix: package version in released files 2023-10-15 21:00:03 +08:00
Harttle c1c72b53d5 test: fix test case 2023-10-15 20:21:32 +08:00
semantic-release-bot 30e364c7d0 chore(release): 10.9.2 [skip ci]
## [10.9.2](https://github.com/harttle/liquidjs/compare/v10.9.1...v10.9.2) (2023-08-28)

### Bug Fixes

* handle windows newlines on `newline_to_br` and `strip_newlines` ([88aa63f](https://github.com/harttle/liquidjs/commit/88aa63fd58b5a5824c031acc6f3e4072bedd262f))
* sort and where bug when using `strictVariables` ([8af682d](https://github.com/harttle/liquidjs/commit/8af682d2ca68de99bafd4a7055e4912eeb318f57))
2023-08-28 13:15:00 +00:00
Francisco SotoandJun Yang 8af682d2ca fix: sort and where bug when using strictVariables 2023-08-28 21:08:45 +08:00
Francisco SotoandJun Yang 88aa63fd58 fix: handle windows newlines on newline_to_br and strip_newlines 2023-08-28 21:08:05 +08:00
semantic-release-bot fce9fcfa68 chore(release): 10.9.1 [skip ci]
## [10.9.1](https://github.com/harttle/liquidjs/compare/v10.9.0...v10.9.1) (2023-08-23)

### Bug Fixes

* map filter allow nil results in strict mode, fixes [#647](https://github.com/harttle/liquidjs/issues/647) ([45adbd7](https://github.com/harttle/liquidjs/commit/45adbd7008296a94da04d21a35917f744a0f4109))
2023-08-23 16:29:27 +00:00
Harttle 45adbd7008 fix: map filter allow nil results in strict mode, fixes #647 2023-08-24 00:20:57 +08:00
semantic-release-bot 942944eae0 chore(release): 10.9.0 [skip ci]
# [10.9.0](https://github.com/harttle/liquidjs/compare/v10.8.4...v10.9.0) (2023-08-22)

### Bug Fixes

* case should allow multiple values separated by or ([b8e7e2d](https://github.com/harttle/liquidjs/commit/b8e7e2d9467b17ca786e6fb422e9579dd178de76))
* for throws undefined var with a null value with strictVariables ([dc6a301](https://github.com/harttle/liquidjs/commit/dc6a3013874872ac85f1fbe5184c74631122d851))
* remove_last was eating an extra character ([fc27313](https://github.com/harttle/liquidjs/commit/fc2731376f8ef59ac7160f97cef1fb5d94f053db))

### Features

* more flexible squared property read expression, fixes [#643](https://github.com/harttle/liquidjs/issues/643) ([#646](https://github.com/harttle/liquidjs/issues/646)) ([660d9be](https://github.com/harttle/liquidjs/commit/660d9be55f8eac16ca5ac77fd0b38b0d7f94961e))
2023-08-22 16:52:37 +00:00
Jun YangandGitHub 660d9be55f feat: more flexible squared property read expression, fixes #643 (#646)
* fix: more flexible squared property read expression, fixes #643

* fix: unecessary error wrapping in browser bundles

* style: update code style and types

* perf: use token.value when evalToken
2023-08-23 00:45:49 +08:00
Francisco SotoandJun Yang dc6a301387 fix: for throws undefined var with a null value with strictVariables 2023-08-19 23:54:32 +08:00
allcontributors[bot]andJun Yang 803a0907fc docs: update .all-contributorsrc [skip ci] 2023-08-19 23:53:44 +08:00
allcontributors[bot]andJun Yang 4427ae1fb9 docs: update README.md [skip ci] 2023-08-19 23:53:44 +08:00
David LJandJun Yang 7009a054f3 docs: fix options link in setup tutorial 2023-08-19 23:53:14 +08:00
Francisco SotoandJun Yang b8e7e2d946 fix: case should allow multiple values separated by or
This is supported by Shopify liquid.
2023-08-19 23:52:24 +08:00
allcontributors[bot]andJun Yang 4c30c660ae docs: update .all-contributorsrc [skip ci] 2023-08-17 21:43:59 +08:00
allcontributors[bot]andJun Yang d916981dad docs: update README.md [skip ci] 2023-08-17 21:43:59 +08:00
Francisco SotoandJun Yang fc2731376f fix: remove_last was eating an extra character 2023-08-17 21:43:21 +08:00
allcontributors[bot]andJun Yang 3bd8d2e557 docs: update .all-contributorsrc [skip ci] 2023-08-08 21:59:48 +08:00
allcontributors[bot]andJun Yang 5d91e3d2ef docs: update README.md [skip ci] 2023-08-08 21:59:48 +08:00
Nick ReilinghandGitHub 5facd99a27 chore: grammar/typo fixes for differences.md (#634) 2023-08-08 21:58:39 +08:00
Harttle 3f4f328572 docs: update LiquidJS contributors and users 2023-07-16 14:22:54 +08:00
Harttle a7c94eeeb5 docs: update who's using liquid 2023-07-16 14:05:16 +08:00
semantic-release-bot 2222a1be87 chore(release): 10.8.4 [skip ci]
## [10.8.4](https://github.com/harttle/liquidjs/compare/v10.8.3...v10.8.4) (2023-07-07)

### Bug Fixes

* allow quotes in inline comment tag, fixes [#628](https://github.com/harttle/liquidjs/issues/628) ([bf425c3](https://github.com/harttle/liquidjs/commit/bf425c3adb929e68fa234bee8397560a436595bb))
2023-07-07 14:54:48 +00:00
Jun YangandGitHub bf425c3adb fix: allow quotes in inline comment tag, fixes #628 2023-07-07 22:48:55 +08:00
Harttle c0bc2de76e docs: add package-lock for demos 2023-07-02 22:03:20 +08:00
Harttle 4759371102 docs: remove Patreon from docs 2023-07-02 22:03:20 +08:00
semantic-release-bot e03e053362 chore(release): 10.8.3 [skip ci]
## [10.8.3](https://github.com/harttle/liquidjs/compare/v10.8.2...v10.8.3) (2023-06-16)

### Bug Fixes

* strftime getSuffix works for all dates ([0b4e2a9](https://github.com/harttle/liquidjs/commit/0b4e2a99790347bea0ab5f7d651f2330e3054601))
2023-06-16 14:02:18 +00:00
allcontributors[bot]GitHuballcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
d8691421b4 docs: add jgarber623 as a contributor for code (#624)
* docs: update README.md [skip ci]

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

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2023-06-15 21:08:11 +08:00
Jason GarberandJun Yang 0b4e2a9979 fix: strftime getSuffix works for all dates
As written, the strftime module's `getSuffix` method (responsible for
returning a date's ordinal string) works correctly for all dates in a
month _except_ 11, 12, and 13.

The existing code would return a string based on the last digit of the
date. In American English, these three dates use the `th` suffix rather
than `st`, `nd`, or `rd`.

This refactor/bug fix draws inspiration from Rails' ActiveSupport
ordinal inflector:

https://github.com/rails/rails/blob/main/activesupport/lib/active_support/locale/en.rb

The Ruby code above is designed to work with any number, so the bug fix
to this library is simpler.

The test suite is also updated with additional examples to verify the
correctness of these changes.
2023-06-15 21:01:55 +08:00
HarttleandJun Yang e401a30972 chore: split Github Actions workflows 2023-06-05 23:32:35 +08:00
254 changed files with 24225 additions and 3120 deletions
+129 -3
View File
@@ -321,8 +321,7 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/2703309?v=4",
"profile": "https://github.com/amit777",
"contributions": [
"code",
"financial"
"code"
]
},
{
@@ -577,8 +576,135 @@
"code",
"doc"
]
},
{
"login": "jgarber623",
"name": "Jason Garber",
"avatar_url": "https://avatars.githubusercontent.com/u/73866?v=4",
"profile": "https://sixtwothree.org",
"contributions": [
"code"
]
},
{
"login": "NReilingh",
"name": "Nick Reilingh",
"avatar_url": "https://avatars.githubusercontent.com/u/2458645?v=4",
"profile": "http://nickreilingh.com/",
"contributions": [
"doc"
]
},
{
"login": "ebobby",
"name": "Francisco Soto",
"avatar_url": "https://avatars.githubusercontent.com/u/170356?v=4",
"profile": "http://ebobby.org",
"contributions": [
"code"
]
},
{
"login": "davidlj95",
"name": "David LJ",
"avatar_url": "https://avatars.githubusercontent.com/u/8050648?v=4",
"profile": "https://www.davidlj95.com",
"contributions": [
"doc"
]
},
{
"login": "RasmusWL",
"name": "Rasmus Wriedt Larsen",
"avatar_url": "https://avatars.githubusercontent.com/u/1054041?v=4",
"profile": "https://github.com/RasmusWL",
"contributions": [
"doc"
]
},
{
"login": "brunodccarvalho",
"name": "Bruno Carvalho",
"avatar_url": "https://avatars.githubusercontent.com/u/24962950?v=4",
"profile": "https://github.com/brunodccarvalho",
"contributions": [
"code"
]
},
{
"login": "fupengl",
"name": "傅鹏",
"avatar_url": "https://avatars.githubusercontent.com/u/20211964?v=4",
"profile": "https://github.com/fupengl",
"contributions": [
"code"
]
},
{
"login": "joel-hamilton",
"name": "Joel Hamilton",
"avatar_url": "https://avatars.githubusercontent.com/u/12899024?v=4",
"profile": "https://github.com/joel-hamilton",
"contributions": [
"code"
]
},
{
"login": "amedve",
"name": "Max Medve",
"avatar_url": "https://avatars.githubusercontent.com/u/23156422?v=4",
"profile": "https://github.com/amedve",
"contributions": [
"code"
]
},
{
"login": "cossssmin",
"name": "Cosmin Popovici",
"avatar_url": "https://avatars.githubusercontent.com/u/1656595?v=4",
"profile": "https://maizzle.com",
"contributions": [
"doc"
]
},
{
"login": "admtnnr",
"name": "Adam Tanner",
"avatar_url": "https://avatars.githubusercontent.com/u/27502?v=4",
"profile": "https://github.com/admtnnr",
"contributions": [
"code"
]
},
{
"login": "GuillermoCasalCaro",
"name": "Guillermo Casal Caro",
"avatar_url": "https://avatars.githubusercontent.com/u/18685581?v=4",
"profile": "https://github.com/GuillermoCasalCaro",
"contributions": [
"code"
]
},
{
"login": "jsoref",
"name": "Josh Soref",
"avatar_url": "https://avatars.githubusercontent.com/u/2119212?v=4",
"profile": "https://github.com/jsoref",
"contributions": [
"doc"
]
},
{
"login": "vrugtehagel",
"name": "Koen",
"avatar_url": "https://avatars.githubusercontent.com/u/41021050?v=4",
"profile": "https://vrugtehagel.nl",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,
"skipCi": true
"skipCi": true,
"commitType": "docs"
}
+1
View File
@@ -23,6 +23,7 @@
"prefer-const": 2,
"no-unused-vars": "off",
"indent": "off",
"no-mixed-operators": "off",
"no-dupe-class-members": "off",
"no-useless-constructor": "off",
"@typescript-eslint/indent": ["error", 2],
+40
View File
@@ -0,0 +1,40 @@
name: Build
on:
workflow_call:
inputs:
os:
required: true
type: string
bundles:
required: false
type: string
env:
BUNDLES: ${{ inputs.bundles }}
jobs:
build:
name: Build
runs-on: ${{ inputs.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: dist-${{ inputs.os }}
path: dist
- name: Archive npm failure logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
path: ~/.npm/_logs
-41
View File
@@ -1,41 +0,0 @@
name: Check
on: [push, pull_request]
jobs:
check:
name: Check
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
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
TZ=Etc/GMT npm run test
TZ=Asia/Shanghai npm run test
TZ=America/New_York npm run test
- name: Coverage
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Performance
run: |
npm run perf:diff
- name: Archive npm failure logs
uses: actions/upload-artifact@v2
if: failure()
with:
name: npm-logs
path: ~/.npm/_logs
+28
View File
@@ -0,0 +1,28 @@
name: CI Build
on:
push:
branches:
- 'master'
- 'test'
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
uses: ./.github/workflows/build.yml
with:
os: ${{ matrix.os }}
lint:
uses: ./.github/workflows/lint.yml
test:
needs: build
uses: ./.github/workflows/test.yml
coverage:
uses: ./.github/workflows/coverage.yml
performance:
needs: build
uses: ./.github/workflows/performance.yml
with:
os: ubuntu-latest
docs:
uses: ./.github/workflows/docs.yml
+29
View File
@@ -0,0 +1,29 @@
name: Test Coverage
on: [workflow_dispatch, workflow_call]
jobs:
coverage:
name: Test Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Test
run: npm run test:coverage
- name: Coverage
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Archive npm failure logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
path: ~/.npm/_logs
+7 -9
View File
@@ -1,32 +1,30 @@
name: Docs
on:
push:
branches:
- master
on: [workflow_dispatch, workflow_call]
jobs:
docs:
name: Docs
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: '14'
node-version: '20'
- name: Build
run: |
npm ci
npm run build
npm run build:docs
- name: Publish
if: github.ref == 'refs/heads/master'
uses: JamesIves/[email protected]
with:
branch: gh-pages
folder: docs/public
- name: Archive npm failure logs
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
+25
View File
@@ -0,0 +1,25 @@
name: Lint
on: [workflow_dispatch, workflow_call]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Archive npm failure logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
path: ~/.npm/_logs
+33
View File
@@ -0,0 +1,33 @@
name: Performance Check
on:
workflow_call:
inputs:
os:
required: true
type: string
jobs:
performance:
name: Performance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: dist-${{ inputs.os }}
path: dist
- name: Check Performance
run: npm run perf:diff
- name: Archive npm failure logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
path: ~/.npm/_logs
+22
View File
@@ -0,0 +1,22 @@
name: PR Build
on: pull_request
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
uses: ./.github/workflows/build.yml
with:
os: ${{ matrix.os }}
lint:
uses: ./.github/workflows/lint.yml
test:
needs: build
uses: ./.github/workflows/test.yml
coverage:
uses: ./.github/workflows/coverage.yml
performance:
needs: build
uses: ./.github/workflows/performance.yml
with:
os: ubuntu-latest
@@ -1,15 +1,12 @@
name: "PR Title Checker"
name: PR Check
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
main:
name: Validate PR title
title:
name: Check PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
+11 -16
View File
@@ -6,32 +6,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
uses: actions/setup-node@v3
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: Install Dependencies
run: npm ci
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
run: |
if [ ${{ github.ref == 'refs/heads/master' }} ]; then
npx semantic-release
else
npx semantic-release --dry-run
fi
- name: Archive npm failure logs
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
+48
View File
@@ -0,0 +1,48 @@
name: Test
on: [workflow_dispatch, workflow_call]
jobs:
test:
name: Test
strategy:
matrix:
os: [ubuntu-latest]
timezone: [Etc/GMT, Asia/Shanghai, America/New_York]
node-version: [22]
include:
- os: macos-latest
timezone: America/New_York
node-versoin: 22
- os: ubuntu-latest
timezone: Etc/GMT
node-version: 16
- os: ubuntu-latest
timezone: Asia/Shanghai
node-version: 15
- os: ubuntu-latest
timezone: Asia/Shanghai
node-version: 14
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: dist-${{ matrix.os }}
path: dist
- name: Run Test
run: TZ=${{ matrix.timezone }} npm test
- name: Archive npm failure logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: npm-logs
path: ~/.npm/_logs
+5 -1
View File
@@ -9,8 +9,12 @@ coverage/
# modules
node_modules/
# tmp
docs/public/js/liquid.browser.min.js
docs/themes/navy/layout/partial/all-contributors.swig
docs/themes/navy/layout/partial/financial-contributors.swig
dist/
demo/*/package-lock.json
demo/*/yarn.json
# editors
+183 -4
View File
@@ -1,3 +1,182 @@
## [10.16.3](https://github.com/harttle/liquidjs/compare/v10.16.2...v10.16.3) (2024-08-16)
### Bug Fixes
* support for NodeJS 15, fixes [#732](https://github.com/harttle/liquidjs/issues/732) ([4548c11](https://github.com/harttle/liquidjs/commit/4548c1140629bf270d163a403c2994d785c7f710))
## [10.16.2](https://github.com/harttle/liquidjs/compare/v10.16.1...v10.16.2) (2024-08-15)
### Bug Fixes
* support for NodeJS 14 ([85bd0d3](https://github.com/harttle/liquidjs/commit/85bd0d35a6d949a02db49ba546407fe5be17db5e))
## [10.16.1](https://github.com/harttle/liquidjs/compare/v10.16.0...v10.16.1) (2024-07-25)
### Bug Fixes
* parser throws on non-string input, [#726](https://github.com/harttle/liquidjs/issues/726) ([21a8223](https://github.com/harttle/liquidjs/commit/21a822348f3c315dae56fba2674ad3db0cf2f80d))
# [10.16.0](https://github.com/harttle/liquidjs/compare/v10.15.0...v10.16.0) (2024-07-21)
### Features
* locale support for date filter, [#567](https://github.com/harttle/liquidjs/issues/567) ([#723](https://github.com/harttle/liquidjs/issues/723)) ([e4aeb02](https://github.com/harttle/liquidjs/commit/e4aeb023fddf5ead90db209599cfd99450274658))
# [10.15.0](https://github.com/harttle/liquidjs/compare/v10.14.0...v10.15.0) (2024-07-09)
### Bug Fixes
* report error for malformed else/elsif/endif/endfor, [#713](https://github.com/harttle/liquidjs/issues/713) ([22b5a12](https://github.com/harttle/liquidjs/commit/22b5a123333a066aaf7dff580df061e7cd6aa7b2))
### Features
* DoS prevention, [#250](https://github.com/harttle/liquidjs/issues/250) ([e443068](https://github.com/harttle/liquidjs/commit/e443068cb9281883ff0fe9f755a15f52ada4e7e2))
* support in-memory template mapping, inspired by [@jg-rp](https://github.com/jg-rp) [#714](https://github.com/harttle/liquidjs/issues/714) ([df27ac6](https://github.com/harttle/liquidjs/commit/df27ac694739496982012432077fe28b1476662a))
# [10.14.0](https://github.com/harttle/liquidjs/compare/v10.13.1...v10.14.0) (2024-06-17)
### Bug Fixes
* use drop `valueOf` when evaluated as condition ([#705](https://github.com/harttle/liquidjs/issues/705)) ([a7da93f](https://github.com/harttle/liquidjs/commit/a7da93ff0f2c1c66f9c85b45ffcc1326c23254c7))
### Features
* support catching all errors, [#220](https://github.com/harttle/liquidjs/issues/220) ([#710](https://github.com/harttle/liquidjs/issues/710)) ([3b5627b](https://github.com/harttle/liquidjs/commit/3b5627b04072b1d6703ef5ba782a3a0f26fd2a60))
## [10.13.1](https://github.com/harttle/liquidjs/compare/v10.13.0...v10.13.1) (2024-05-24)
### Bug Fixes
* allow liquidMethodMissing to return any supported value type ([#698](https://github.com/harttle/liquidjs/issues/698)) ([0983f2c](https://github.com/harttle/liquidjs/commit/0983f2c42012b2b97258d0cdcb07b6d43c904814))
* isComparable full interface check ([#701](https://github.com/harttle/liquidjs/issues/701)) ([55e144a](https://github.com/harttle/liquidjs/commit/55e144a0298047349d55d8483a46b2513303d940))
# [10.13.0](https://github.com/harttle/liquidjs/compare/v10.12.0...v10.13.0) (2024-05-13)
### Features
* array_to_sentence_string and number_of_words filters from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([50253a9](https://github.com/harttle/liquidjs/commit/50253a98caf5356d3c33e148be66f34fbe75a204))
* date filters from Jekyll ([4955e75](https://github.com/harttle/liquidjs/commit/4955e75be7f38a3fd15e71f2c192cff6f0d6e2d5))
* escape filters from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([b12eb8a](https://github.com/harttle/liquidjs/commit/b12eb8ab4b58b002459725b6c0ed00159cdc15e6))
* jsonify, inspect, to_integer, normalize_whitespace filters ([842b45c](https://github.com/harttle/liquidjs/commit/842b45c96a46290a1e1ba43fc5cc7a465f4ba9de))
* slugify filter from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([47ddc11](https://github.com/harttle/liquidjs/commit/47ddc1193b84bbdeb8d48457bb5aead24d5aff77))
# [10.12.0](https://github.com/harttle/liquidjs/compare/v10.11.1...v10.12.0) (2024-04-28)
### Bug Fixes
* case/when array equality, [#673](https://github.com/harttle/liquidjs/issues/673) ([2b63035](https://github.com/harttle/liquidjs/commit/2b630353c478368cb36dbfcb38961b25bf48249e))
### Features
* introduce where_exp filter from Jekyll ([8c7cef9](https://github.com/harttle/liquidjs/commit/8c7cef9f95cda765164ada8d58af7d402b3d3143))
## [10.11.1](https://github.com/harttle/liquidjs/compare/v10.11.0...v10.11.1) (2024-04-21)
### Bug Fixes
* allow %Z for TimezoneDate, update docs accordingly [#684](https://github.com/harttle/liquidjs/issues/684) ([e09657c](https://github.com/harttle/liquidjs/commit/e09657c52b5e9920256d73f99455e2e81cadf065))
* Allow `lenientIf` for multiple operands (issue [#682](https://github.com/harttle/liquidjs/issues/682)) ([#683](https://github.com/harttle/liquidjs/issues/683)) ([490ff43](https://github.com/harttle/liquidjs/commit/490ff4309cc231a25be23df5374a5d032aac144e))
# [10.11.0](https://github.com/harttle/liquidjs/compare/v10.10.2...v10.11.0) (2024-04-14)
### Features
* group_by/group_by_exp/find/find_exp from Jekyll, [#443](https://github.com/harttle/liquidjs/issues/443) ([2b713b7](https://github.com/harttle/liquidjs/commit/2b713b721d1f355309a70ebb5846169c6c03c523))
* pop/shift/unshift filters from Jekyll ([258780e](https://github.com/harttle/liquidjs/commit/258780e9a87ce87534a6bb4336725cb1d38a2998))
## [10.10.2](https://github.com/harttle/liquidjs/compare/v10.10.1...v10.10.2) (2024-03-21)
### Bug Fixes
* contains regression ([#677](https://github.com/harttle/liquidjs/issues/677)) ([05223c4](https://github.com/harttle/liquidjs/commit/05223c4378f9474f4e658af36cb8272e161d681f)), closes [#675](https://github.com/harttle/liquidjs/issues/675)
## [10.10.1](https://github.com/harttle/liquidjs/compare/v10.10.0...v10.10.1) (2024-02-18)
### Bug Fixes
* in conditionals, don't render anything after an else branch ([#671](https://github.com/harttle/liquidjs/issues/671)) ([f816955](https://github.com/harttle/liquidjs/commit/f81695570491ede77975de2c26a07612a2d62c28))
* Rely on equal for computing contains ([#668](https://github.com/harttle/liquidjs/issues/668)) ([1937aa1](https://github.com/harttle/liquidjs/commit/1937aa1f1dce01ee6332f39a6e658e85cbe4f30b))
# [10.10.0](https://github.com/harttle/liquidjs/compare/v10.9.4...v10.10.0) (2023-12-19)
### Features
* Array sum filter ([#661](https://github.com/harttle/liquidjs/issues/661)) ([629d958](https://github.com/harttle/liquidjs/commit/629d958b86a97ddf2921d2285b7c9ea83430004e))
## [10.9.4](https://github.com/harttle/liquidjs/compare/v10.9.3...v10.9.4) (2023-11-04)
### Bug Fixes
* allow unicode to be identifiers, fixes [#655](https://github.com/harttle/liquidjs/issues/655) ([dd7616a](https://github.com/harttle/liquidjs/commit/dd7616acb9a71b77f39d2fa24b6f68a7caef87f1))
## [10.9.3](https://github.com/harttle/liquidjs/compare/v10.9.2...v10.9.3) (2023-10-15)
### Bug Fixes
* package version in released files ([67a5b22](https://github.com/harttle/liquidjs/commit/67a5b229ca9ccabb4aee42bbb5c9f03d4076786a))
## [10.9.2](https://github.com/harttle/liquidjs/compare/v10.9.1...v10.9.2) (2023-08-28)
### Bug Fixes
* handle windows newlines on `newline_to_br` and `strip_newlines` ([88aa63f](https://github.com/harttle/liquidjs/commit/88aa63fd58b5a5824c031acc6f3e4072bedd262f))
* sort and where bug when using `strictVariables` ([8af682d](https://github.com/harttle/liquidjs/commit/8af682d2ca68de99bafd4a7055e4912eeb318f57))
## [10.9.1](https://github.com/harttle/liquidjs/compare/v10.9.0...v10.9.1) (2023-08-23)
### Bug Fixes
* map filter allow nil results in strict mode, fixes [#647](https://github.com/harttle/liquidjs/issues/647) ([45adbd7](https://github.com/harttle/liquidjs/commit/45adbd7008296a94da04d21a35917f744a0f4109))
# [10.9.0](https://github.com/harttle/liquidjs/compare/v10.8.4...v10.9.0) (2023-08-22)
### Bug Fixes
* case should allow multiple values separated by or ([b8e7e2d](https://github.com/harttle/liquidjs/commit/b8e7e2d9467b17ca786e6fb422e9579dd178de76))
* for throws undefined var with a null value with strictVariables ([dc6a301](https://github.com/harttle/liquidjs/commit/dc6a3013874872ac85f1fbe5184c74631122d851))
* remove_last was eating an extra character ([fc27313](https://github.com/harttle/liquidjs/commit/fc2731376f8ef59ac7160f97cef1fb5d94f053db))
### Features
* more flexible squared property read expression, fixes [#643](https://github.com/harttle/liquidjs/issues/643) ([#646](https://github.com/harttle/liquidjs/issues/646)) ([660d9be](https://github.com/harttle/liquidjs/commit/660d9be55f8eac16ca5ac77fd0b38b0d7f94961e))
## [10.8.4](https://github.com/harttle/liquidjs/compare/v10.8.3...v10.8.4) (2023-07-07)
### Bug Fixes
* allow quotes in inline comment tag, fixes [#628](https://github.com/harttle/liquidjs/issues/628) ([bf425c3](https://github.com/harttle/liquidjs/commit/bf425c3adb929e68fa234bee8397560a436595bb))
## [10.8.3](https://github.com/harttle/liquidjs/compare/v10.8.2...v10.8.3) (2023-06-16)
### Bug Fixes
* strftime getSuffix works for all dates ([0b4e2a9](https://github.com/harttle/liquidjs/commit/0b4e2a99790347bea0ab5f7d651f2330e3054601))
## [10.8.2](https://github.com/harttle/liquidjs/compare/v10.8.1...v10.8.2) (2023-06-04)
@@ -942,7 +1121,7 @@
* Tag#render now returns void, use emitter argument
to write rendered html.
* ship to Node.js 8, the dist/liquid.cjs.js (main) nolonger
* ship to Node.js 8, the dist/liquid.cjs.js (main) no longer
supports Node.js 6, other bundles are also provided via dist/liquid.esm.js, dist/liquid.js (ES5 umd) and liquid.min.js (minified ES5 umd)
* remove default export, now should be used like import
{Liquid} from 'liquidjs'
@@ -987,7 +1166,7 @@ supports Node.js 6, other bundles are also provided via dist/liquid.esm.js, dist
### Features
* at_least, at_most, sort_naturual for [#132](https://github.com/harttle/liquidjs/issues/132) ([e6f5f1c](https://github.com/harttle/liquidjs/commit/e6f5f1c))
* at_least, at_most, sort_natural for [#132](https://github.com/harttle/liquidjs/issues/132) ([e6f5f1c](https://github.com/harttle/liquidjs/commit/e6f5f1c))
# [8.3.0](https://github.com/harttle/liquidjs/compare/v8.2.4...v8.3.0) (2019-06-27)
@@ -1051,7 +1230,7 @@ supports Node.js 6, other bundles are also provided via dist/liquid.esm.js, dist
### Performance Improvements
* use polymophism instead duck test ([82d7673](https://github.com/harttle/liquidjs/commit/82d7673))
* use polymorphism instead duck test ([82d7673](https://github.com/harttle/liquidjs/commit/82d7673))
## [8.0.1](https://github.com/harttle/liquidjs/compare/v8.0.0...v8.0.1) (2019-03-22)
@@ -1075,7 +1254,7 @@ supports Node.js 6, other bundles are also provided via dist/liquid.esm.js, dist
### BREAKING CHANGES
* Options and method names in JavaScript API are now renamed to cammelCase, for a complete list see #109
* Options and method names in JavaScript API are now renamed to camelCase, for a complete list see #109
## [7.5.1](https://github.com/harttle/liquidjs/compare/v7.5.0...v7.5.1) (2019-03-05)
+17 -25
View File
@@ -16,14 +16,14 @@
- Ensure the build runs because the Husky pre-commit hook checks it
- `npm run check` checks runs the build, tests, lint and perf tests
- `commitlint` checks the commit message format
If there is a problem you will see it in the pre-commit hook output.
In VS Code, this output will be shown in a new file in a new tab if the
pre-commit hook fails.
If you want to check the commit message without using the VS Code Source
Control UI, you can run `echo "feat: my commit message" > npx commitlint`
directly.
- `git switch -c your_branch_name` (do this in your fork not the main repo)
- `git add .`
- `git commit -m "feat: Adding my change"`
@@ -33,32 +33,24 @@
## Playground
The Playground runs off the `docs` directory.
`npm run:docs` is used to build it and that's included in `npm run build`.
`npm run build:docs` is used to build it.
To start the site locally, go to `docs` and run `npm start`, then visit
Then, to start the site locally, go to `docs` and run `npm start`, then visit
http://localhost:4000/playground.html.
At the moment, the Playground uses the latest NPM version of the LiquidJS
library instead of using the built artifact produced by `npm run build:dist`
(also included in `npm run build`).
The Playground uses a local built LiquidJS, which is created during `npm run build:docs`.
To update that, you'll need to run `./bin/build-docs-liquid.sh` each time after making changes.
Then refresh the Playground site for the changes to take effect.
To use the Playground with the local build of the library, make these changes:
## Performance
- Copy `dist/liquid.browser.min.js` to `docs/public/js/liquid.browser.min.js`
- Open `docs/themes/navy/layout/partial/after_footer.swig`
- Remove `https://cdn.jsdelivr.net/npm/liquidjs/dist/liquid.browser.min.js` line
- Add `{{ js('liquid.browser.min.js') }}` line before `{{ js('js/main') }}` line
- Refresh the Playground site for the changes to take effect
- Replace `liquid.browser.min.js` each time after making changes and building
If your change can have a performance impact, you can update and run performance cases under `benchmark/`.
```diff
{% if page.layout === 'playground' %}
-<script src="https://cdn.jsdelivr.net/npm/liquidjs/dist/liquid.browser.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src-min/ace.js"></script>
{% endif %}
+{{ js('js/liquid.browser.min.js') }}
{{ js('js/main') }}
<script src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
```
1. `npm run build:cjs` to build a CommonJS bundle for the perf test.
2. `npm run perf:diff` to check whether there's a regression compared against `liquidjs@latest`
Further more, `benchmark/` contains different cases to check its ops/sec. Useful when debugging perf regressions, to use it:
- `cd benchmark` go into benchmark project
- `npm ci` install dependencies
- `npm start` run the cases
+61 -22
View File
@@ -2,16 +2,16 @@
[![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/actions/workflow/status/harttle/liquidjs/check.yml?branch=master&style=flat-square)](https://github.com/harttle/liquidjs/actions/workflows/check.yml?query=branch%3Amaster)
[![Build Status](https://img.shields.io/github/actions/workflow/status/harttle/liquidjs/ci-build.yml?branch=master&style=flat-square)](https://github.com/harttle/liquidjs/actions/workflows/ci-build.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 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.
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]
* Please star [LiquidJS on GitHub][github]!
* Support [LiquidJS on Open Collective][oc] or [Patreon][patreon]
* Financial support via [GitHub Sponsors](https://github.com/sponsors/harttle).
<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>
@@ -50,26 +50,49 @@ npx liquidjs --template 'Hello, {{ name }}!' --context '{"name": "Snake"}'
For more details, refer to the [Setup Guide][setup].
## Related Projects
## Who's Using LiquidJS?
* [@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.
* [gulp-liquidjs](https://www.npmjs.com/package/@tuanpham-dev/gulp-liquidjs): A shopify compatible Liquid template engine for Gulp using liquidjs.
* [grunt-liquify](https://www.npmjs.com/package/grunt-liquify): A Grunt task to process Liquid using liquidjs. Use it to add Liquid magic to your scripts and css assets.
* [react-liquid](https://github.com/aquibm/react-liquid#readme): Liquid templating language component for React
- [Eleventy](https://www.11ty.dev/): Eleventy, a simpler static site generator.
- [Opensense](https://www.opensense.com/): The smarter way to send email.
- [Directus](https://docs.directus.io/): an instant REST+GraphQL API and intuitive no-code data collaboration app for any SQL database.
- [Semgrep](https://github.com/returntocorp/semgrep): Lightweight static analysis for many languages.
- [Rock](https://www.rockrms.com/): An open source CMS, Relationship Management System (RMS) and Church Management System (ChMS) all rolled into one.
- [Mitosis](https://github.com/BuilderIO/mitosis): Write components once, run everywhere. Compiles to React, Vue, Qwik, Solid, Angular, Svelte, and more.
- [Pattern Lab](https://patternlab.io/): a frontend workshop environment that helps you build, view, test, and showcase your design system's UI components.
- [Builder.io](https://www.builder.io/m/developers): the first and only headless CMS with a visual editor that lets you drag and drop with your components, directly within your current site or app. Completely API-driven, for cleaner code and simpler workflows.
- [Microsoft Power Pages](https://learn.microsoft.com/en-us/power-pages/introduction): a secure, enterprise-grade, low-code software as a service (SaaS) platform for creating, hosting, and administering modern external-facing business websites.
- [Azure API Management developer portal](https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-developer-portal): an automatically generated, fully customizable website with the documentation of your APIs.
- [WISMOlabs](https://wismolabs.com/): Post Purchase Experience platform for eCommerce retailers enhancing customer satisfaction by using LiquidJS to provide customizable post-purchase experiences through programmable email, SMS, order tracking pages, and webhooks.
Feel free to create a PR or contact me to add your use case into this list!
## Financial Support
If you love LiquidJS or your company is using LiquidJS? Please consider [support us on Open Collective or Patreon][financial-support].
If you personally love LiquidJS or it's benefiting your business, please consider financially support us via [GitHub Sponsors](https://github.com/sponsors/harttle). Special thanks to our sponsors!
### Backers
If you personally like LiquidJS and find it useful to you, you can buy me a coffee!
<img src="https://opencollective.com/liquidjs/backers.svg?avatarHeight=72">
### Sponsors
If LiquidJS is benefiting your business/company, please sponsor us to contribute to our effort!
<img src="https://opencollective.com/liquidjs/sponsors.svg?avatarHeight=72">
<!-- FINANCIAL-CONTRIBUTORS-BEGIN -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://www.opensense.com/"><img src="https://images.opencollective.com/opensense-inc/bf840ae/logo/256.png?height=100" width="100px;" alt="Opensense Inc."/><br /><sub><b>Opensense</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.11ty.dev/"><img src="https://avatars.githubusercontent.com/u/35147177?v=4?s=100" width="100px;" alt="Eleventy"/><br /><sub><b>Eleventy</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://about.me/peterdehaan"><img src="https://avatars2.githubusercontent.com/u/557895?v=4?s=100" width="100px;" alt="Peter deHaan"/><br /><sub><b>Peter deHaan</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://opencollective.com/touchless"><img src="https://images.opencollective.com/touchless/273bc74/logo/256.png?height=100" width="100px;" alt="Touchless"/><br /><sub><b>Touchless</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.dropkiq.com/"><img src="https://images.opencollective.com/1bertlol/43a8ea8/logo/256.png?height=100" width="100px;" alt="Adam Darrah"/><br /><sub><b>Dropkiq</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://dailycontributors.com/"><img src="https://images.opencollective.com/dailycontributors/3c2e057/logo/256.png?height=100&width=100" width="100px;" alt="Dailycontributors"/><br /><sub><b>Dailycontributors</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coni2k"><img src="https://avatars0.githubusercontent.com/u/1284601?v=4?s=100" width="100px;" alt="coni2k"/><br /><sub><b>Serkan Holat</b></sub></a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amit777"><img src="https://avatars0.githubusercontent.com/u/2703309?v=4?s=100" width="100px;" alt="amit777"/><br /><sub><b>amit777</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://opencollective.com/khaled-salem"><img src="https://images.opencollective.com/khaled-salem/avatar/256.png?height=256" width="100px;" alt="Khaled Salem"/><br /><sub><b>Khaled Salem</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://sentry.io/"><img src="https://avatars.githubusercontent.com/u/1396951?v=4?s=100" width="100px;" alt="Sentry"/><br /><sub><b>Sentry</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.checkoutblocks.com/"><img src="https://avatars.githubusercontent.com/u/114603307?v=4?s=100" width="100px;" alt="Checkout Blocks"/><br /><sub><b>Checkout Blocks</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://customer.io/"><img src="https://avatars.githubusercontent.com/u/1152079?v=4?s=100" width="100px;" alt="Customer IO"/><br /><sub><b>Customer IO</b></sub></a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/15fathoms"><img src="https://avatars.githubusercontent.com/u/79156039?v=4?s=100" width="100px;" alt="Emmanuel Cartelli"/><br /><sub><b>Emmanuel Cartelli</b></sub></a><br /></td>
</tr>
</tbody>
</table>
<!-- FINANCIAL-CONTRIBUTORS-END -->
## Contributors ✨
@@ -122,7 +145,7 @@ Want to contribute? see [Contribution Guidelines][contribution]. Thanks goes to
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/IAmTrySound"><img src="https://avatars0.githubusercontent.com/u/5635476?v=4?s=100" width="100px;" alt="Bogdan Chadkin"/><br /><sub><b>Bogdan Chadkin</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=TrySound" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://hightouch.io"><img src="https://avatars0.githubusercontent.com/u/5959235?v=4?s=100" width="100px;" alt="Tejas Manohar"/><br /><sub><b>Tejas Manohar</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=tejasmanohar" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://about.me/peterdehaan"><img src="https://avatars2.githubusercontent.com/u/557895?v=4?s=100" width="100px;" alt="Peter deHaan"/><br /><sub><b>Peter deHaan</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=pdehaan" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amit777"><img src="https://avatars0.githubusercontent.com/u/2703309?v=4?s=100" width="100px;" alt="amit777"/><br /><sub><b>amit777</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=amit777" title="Code">💻</a> <a href="#financial-amit777" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amit777"><img src="https://avatars0.githubusercontent.com/u/2703309?v=4?s=100" width="100px;" alt="amit777"/><br /><sub><b>amit777</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=amit777" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.ifi.uzh.ch/en/ce/people/schuldenzucker.html"><img src="https://avatars3.githubusercontent.com/u/1100776?v=4?s=100" width="100px;" alt="Steffen Schuldenzucker"/><br /><sub><b>Steffen Schuldenzucker</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=sschuldenzucker" title="Code">💻</a></td>
</tr>
<tr>
@@ -159,6 +182,24 @@ Want to contribute? see [Contribution Guidelines][contribution]. Thanks goes to
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bangank36"><img src="https://avatars.githubusercontent.com/u/10071857?v=4?s=100" width="100px;" alt="BaNgan"/><br /><sub><b>BaNgan</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=bangank36" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mahyar-pasarzangene"><img src="https://avatars.githubusercontent.com/u/16485039?v=4?s=100" width="100px;" alt="Mahyar Pasarzangene"/><br /><sub><b>Mahyar Pasarzangene</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=mahyar-pasarzangene" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://hubelbauer.net/"><img src="https://avatars.githubusercontent.com/u/6831144?v=4?s=100" width="100px;" alt="Tomáš Hübelbauer"/><br /><sub><b>Tomáš Hübelbauer</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=TomasHubelbauer" title="Code">💻</a> <a href="https://github.com/harttle/liquidjs/commits?author=TomasHubelbauer" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://sixtwothree.org"><img src="https://avatars.githubusercontent.com/u/73866?v=4?s=100" width="100px;" alt="Jason Garber"/><br /><sub><b>Jason Garber</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=jgarber623" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="http://nickreilingh.com/"><img src="https://avatars.githubusercontent.com/u/2458645?v=4?s=100" width="100px;" alt="Nick Reilingh"/><br /><sub><b>Nick Reilingh</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=NReilingh" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://ebobby.org"><img src="https://avatars.githubusercontent.com/u/170356?v=4?s=100" width="100px;" alt="Francisco Soto"/><br /><sub><b>Francisco Soto</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=ebobby" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.davidlj95.com"><img src="https://avatars.githubusercontent.com/u/8050648?v=4?s=100" width="100px;" alt="David LJ"/><br /><sub><b>David LJ</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=davidlj95" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RasmusWL"><img src="https://avatars.githubusercontent.com/u/1054041?v=4?s=100" width="100px;" alt="Rasmus Wriedt Larsen"/><br /><sub><b>Rasmus Wriedt Larsen</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=RasmusWL" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/brunodccarvalho"><img src="https://avatars.githubusercontent.com/u/24962950?v=4?s=100" width="100px;" alt="Bruno Carvalho"/><br /><sub><b>Bruno Carvalho</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=brunodccarvalho" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fupengl"><img src="https://avatars.githubusercontent.com/u/20211964?v=4?s=100" width="100px;" alt="傅鹏"/><br /><sub><b>傅鹏</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=fupengl" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/joel-hamilton"><img src="https://avatars.githubusercontent.com/u/12899024?v=4?s=100" width="100px;" alt="Joel Hamilton"/><br /><sub><b>Joel Hamilton</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=joel-hamilton" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amedve"><img src="https://avatars.githubusercontent.com/u/23156422?v=4?s=100" width="100px;" alt="Max Medve"/><br /><sub><b>Max Medve</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=amedve" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://maizzle.com"><img src="https://avatars.githubusercontent.com/u/1656595?v=4?s=100" width="100px;" alt="Cosmin Popovici"/><br /><sub><b>Cosmin Popovici</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=cossssmin" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/admtnnr"><img src="https://avatars.githubusercontent.com/u/27502?v=4?s=100" width="100px;" alt="Adam Tanner"/><br /><sub><b>Adam Tanner</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=admtnnr" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GuillermoCasalCaro"><img src="https://avatars.githubusercontent.com/u/18685581?v=4?s=100" width="100px;" alt="Guillermo Casal Caro"/><br /><sub><b>Guillermo Casal Caro</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=GuillermoCasalCaro" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?v=4?s=100" width="100px;" alt="Josh Soref"/><br /><sub><b>Josh Soref</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=jsoref" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://vrugtehagel.nl"><img src="https://avatars.githubusercontent.com/u/41021050?v=4?s=100" width="100px;" alt="Koen"/><br /><sub><b>Koen</b></sub></a><br /><a href="https://github.com/harttle/liquidjs/commits?author=vrugtehagel" title="Code">💻</a></td>
</tr>
</tbody>
</table>
@@ -173,7 +214,5 @@ Want to contribute? see [Contribution Guidelines][contribution]. Thanks goes to
[setup]: https://liquidjs.com/tutorials/setup.html
[doc]: https://liquidjs.com
[github]: https://github.com/harttle/liquidjs
[patreon]: https://www.patreon.com/harttle
[oc]: https://opencollective.com/liquidjs/
[contribution]: https://liquidjs.com/tutorials/contribution-guidelines.html
[financial-support]: https://liquidjs.com/tutorials/contribution-guidelines.html#Financial-Support
+1 -1
View File
@@ -7,7 +7,7 @@ function createEngine (pkg) {
cache: true,
extname: '.liquid'
})
liquid.registerFilter('url', path => `http://example.com${path}`)
liquid.registerFilter('url', path => `https://example.com${path}`)
return {
load: path => liquid.parse(readFileSync(path + '.liquid', 'utf8')),
render: (tpl, data) => liquid.renderSync(tpl, data)
+1 -1
View File
@@ -12,7 +12,7 @@ handlebars.registerHelper('concat', function (...args) {
})
handlebars.registerHelper('url', function (path) {
return `http://example.com${path}`
return `https://example.com${path}`
})
handlebars.registerHelper('inc', function (num) {
+1 -1
View File
@@ -1,7 +1,7 @@
const swig = require('swig')
swig.setFilter('url', function (path) {
return `http://example.com${path}`
return `https://example.com${path}`
})
swig.setFilter('prepend', function (input, arg) {
+1 -1
View File
@@ -10,7 +10,7 @@ function tag () {
new Benchmark.Suite('tag')
.add('if', test('{% if "foobar" %}foo{% endif %}'))
.add('unless', test('{%unless "foo"%}true{%else%}false{%endunless%}'))
.add('for', test('{% for i in (1..3) %}{{fooloop.index}}{% endfor %}'))
.add('for', test('{% for i in (1..3) %}{{forloop.index}}{% endfor %}'))
.add('switch', test('{%case 3%}{% when 1 %}1{% when 2 %}2{% when 3 %}3{%endcase%}'))
.add('assign', test('{%assign a="foo bar"%}'))
.add('capture', test('{%capture foo%}what is this{%endcapture%}'))
+1 -1
View File
@@ -5,7 +5,7 @@ function capitalize (str) {
return str[0].toUpperCase() + str.slice(1).toLowerCase()
}
function url (path) {
return `http://example.com${path}`
return `https://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"/>
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
rm -rf docs/source/api
typedoc ./src --gitRevision master --out docs/source/api
typedoc --plugin typedoc-plugin-missing-exports ./src --gitRevision master --out docs/source/api
+3 -14
View File
@@ -1,17 +1,8 @@
#!/usr/bin/env bash
# Run `sed` in a way that's compatible with both macOS (BSD) and Linux (GNU)
sedi() {
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "$@"
else
sed -i "$@"
fi
}
cd docs
cp ../CHANGELOG.md source/tutorials/changelog.md
sedi \
sed -i \
-e 's/{%/{% raw %}{%{% endraw %}/g' \
-e 's/{{/{% raw %}{{{% endraw %}/g' \
-e '1 s/"/\&quot;/g' \
@@ -20,7 +11,5 @@ sedi \
source/tutorials/changelog.md
cp source/tutorials/changelog.md source/zh-cn/tutorials/changelog.md
sedi -e '1i\
---\ntitle: Changelog\nauto: true\n---\n' source/tutorials/changelog.md
sedi -e '1i\
---\ntitle: 更新日志\nauto: true\n---\n' source/zh-cn/tutorials/changelog.md
sed -i -e '1i\---\ntitle: Changelog\nauto: true\n---\n' source/tutorials/changelog.md
sed -i -e '1i\---\ntitle: 更新日志\nauto: true\n---\n' source/zh-cn/tutorials/changelog.md
+15 -8
View File
@@ -3,17 +3,24 @@
# Run `sed` in a way that's compatible with both macOS (BSD) and Linux (GNU)
sedi() {
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "$@"
/usr/bin/sed -i '' "$@"
else
sed -i "$@"
fi
}
cp .all-contributorsrc docs/.all-contributorsrc
sedi \
-e 's/README.md/docs\/themes\/navy\/layout\/partial\/all-contributors.swig/g' \
-e 's/"contributorsPerLine": 7/"contributorsPerLine": 65535/g' \
docs/.all-contributorsrc
# create docs/themes/navy/layout/partial/all-contributors.swig
awk '/ALL-CONTRIBUTORS-LIST:START/{flag=1;next}/ALL-CONTRIBUTORS-LIST:END/{flag=0}flag' README.md | \
sed 's/<br \/>.*<\/td>/<\/a><\/td>/g' | \
sed 's/width="[^"]*"//g' | \
tr -d '\n' | \
sed 's/<\/tr>\s*<tr>//g' \
> docs/themes/navy/layout/partial/all-contributors.swig
all-contributors --config docs/.all-contributorsrc generate
sedi 's/<br \/>.*<\/td>/<\/a><\/td>/g' docs/themes/navy/layout/partial/all-contributors.swig
# create docs/themes/navy/layout/partial/financial-contributors.swig
awk '/FINANCIAL-CONTRIBUTORS-BEGIN/{flag=1;next}/FINANCIAL-CONTRIBUTORS-END/{flag=0}flag' README.md | \
sed 's/<br \/>.*<\/td>/<\/a><\/td>/g' | \
sed 's/width="[^"]*"//g' | \
tr -d '\n' | \
sed 's/<\/tr>\s*<tr>//g' \
> docs/themes/navy/layout/partial/financial-contributors.swig
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
BUNDLES=min npm run build
mkdir -p docs/public/js/
cp dist/liquid.browser.min.js docs/public/js/
+1
View File
@@ -2,6 +2,7 @@
set -ex
./bin/build-docs-liquid.sh
./bin/build-contributors.sh
./bin/build-apidoc.sh
./bin/build-changelog.sh
Regular → Executable
+12 -4
View File
@@ -4,18 +4,19 @@ const isQuote = c => c === '"' || c === "'"
const isOperator = c => '!=<>'.includes(c)
const isNumber = c => c >= '0' && c <= '9'
const isCharacter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
const isIdentifier = c => '_-?'.includes(c) || isCharacter(c) || isNumber(c)
const isBlank = c => c === '\n' || c === '\t' || c === ' ' || c === '\r' || c === '\v' || c === '\f'
const isWord = c => '_-?'.includes(c) || isCharacter(c) || isNumber(c)
const isBlank = c => '\n\t \r\v\f'.includes(c)
const isInlineBlank = c => c === '\t' || c === ' ' || c === '\r'
const isSign = c => c === '-' || c === '+'
// See https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
const unicodeBlanks = '\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000'
const unicodePunctuation = '“”'
const types = []
for (let i = 0; i < 128; i++) {
const c = String.fromCharCode(i)
let n = 0
if (isIdentifier(c)) n |= 1
if (isWord(c)) n |= 1
if (isOperator(c)) n |= 2
if (isBlank(c)) n |= 4
if (isQuote(c)) n |= 8
@@ -31,13 +32,20 @@ console.log(`
// This file is generated by bin/character-gen.js
// bitmask character types to boost performance
export const TYPES = [${types.join(', ')}]
export const IDENTIFIER = 1
export const WORD = 1
export const OPERATOR = 2
export const BLANK = 4
export const QUOTE = 8
export const INLINE_BLANK = 16
export const NUMBER = 32
export const SIGN = 64
export const PUNCTUATION = 128
export function isWord (char: string): boolean {
const code = char.charCodeAt(0)
return code >= 128 ? !TYPES[code] : !!(TYPES[code] & WORD)
}
`.trim())
console.log([...unicodeBlanks].map(char => `TYPES[${char.charCodeAt(0)}]`).join(' = ') + ' = BLANK')
console.log([...unicodePunctuation].map(char => `TYPES[${char.charCodeAt(0)}]`).join(' = ') + ' = PUNCTUATION')
+2 -6
View File
@@ -1,16 +1,12 @@
#!/usr/bin/env bash
VERSION_LATEST=$(cat package.json | grep '"version":' | awk -F'"' '{print $4}')
VERSION_LATEST=$(cat package.json | grep '"version":' | head -1 | 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
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
+17
View File
@@ -0,0 +1,17 @@
{
"name": "liquidjs-demo-nodejs",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"hello-liquid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hello-liquid/-/hello-liquid-1.0.0.tgz",
"integrity": "sha512-WNmZp5s647BN2WHPq4FHVH85CcqNVet5DXIVw1UtVMaV+MJHFA+ylge0hqHSw0iOI/Ojrx8KEKZurYZix5PekQ=="
},
"liquidjs": {
"version": "9.42.0",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-9.42.0.tgz",
"integrity": "sha512-krvhwGFrMCMGhybGkxJIvlWVVnoCSpYCn7NhEN43+uvlg2vOkYWpq8be+L3NMlOfwe4ZrKQ7hCh1EmS4yhLKow=="
}
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"name": "liquidjs-demo-nodejs",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"liquidjs": {
"version": "9.32.1",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-9.32.1.tgz",
"integrity": "sha512-U/ymmm4M3sNJszHlF0Gzneky17qk+vWmu3nFkWKdniQhqaZNk6eZQdbcKkFGFPN4I9ijrBRjDsLBLysu292j8w=="
}
}
}
+41 -41
View File
@@ -381,7 +381,7 @@ This works for any library, not just `react-router-dom`.
## Importing a Component
This project setup supports ES6 modules thanks to Webpack.<br>
While you can still use `require()` and `module.exports`, we encourage you to use [`import` and `export`](http://exploringjs.com/es6/ch_modules.html) instead.
While you can still use `require()` and `module.exports`, we encourage you to use [`import` and `export`](https://exploringjs.com/es6/ch_modules.html) instead.
For example:
@@ -414,7 +414,7 @@ class DangerButton extends Component {
export default DangerButton;
```
Be aware of the [difference between default and named exports](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281). It is a common source of mistakes.
Be aware of the [difference between default and named exports](https://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281). It is a common source of mistakes.
We suggest that you stick to using default imports and exports when a module only exports a single thing (for example, a component). Thats what you get when you use `export default Button` and `import Button from './Button'`.
@@ -422,15 +422,15 @@ Named exports are useful for utility modules that export several functions. A mo
Learn more about ES6 modules:
- [When to use the curly braces?](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281)
- [Exploring ES6: Modules](http://exploringjs.com/es6/ch_modules.html)
- [When to use the curly braces?](https://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281)
- [Exploring ES6: Modules](https://exploringjs.com/es6/ch_modules.html)
- [Understanding ES6: Modules](https://leanpub.com/understandinges6/read#leanpub-auto-encapsulating-code-with-modules)
## Code Splitting
Instead of downloading the entire app before users can use it, code splitting allows you to split your code into small chunks which you can then load on demand.
This project setup supports code splitting via [dynamic `import()`](http://2ality.com/2017/01/import-operator.html#loading-code-on-demand). Its [proposal](https://github.com/tc39/proposal-dynamic-import) is in stage 3. The `import()` function-like form takes the module name as an argument and returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which always resolves to the namespace object of the module.
This project setup supports code splitting via [dynamic `import()`](https://2ality.com/2017/01/import-operator.html#loading-code-on-demand). Its [proposal](https://github.com/tc39/proposal-dynamic-import) is in stage 3. The `import()` function-like form takes the module name as an argument and returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which always resolves to the namespace object of the module.
Here is an example:
@@ -476,7 +476,7 @@ You can also use it with `async` / `await` syntax if you prefer it.
### With React Router
If you are using React Router check out [this tutorial](http://serverless-stack.com/chapters/code-splitting-in-create-react-app.html) on how to use code splitting with it. You can find the companion GitHub repository [here](https://github.com/AnomalyInnovations/serverless-stack-demo-client/tree/code-splitting-in-create-react-app).
If you are using React Router check out [this tutorial](https://serverless-stack.com/chapters/code-splitting-in-create-react-app.html) on how to use code splitting with it. You can find the companion GitHub repository [here](https://github.com/AnomalyInnovations/serverless-stack-demo-client/tree/code-splitting-in-create-react-app).
Also check out the [Code Splitting](https://reactjs.org/docs/code-splitting.html) section in React documentation.
@@ -602,7 +602,7 @@ This project setup minifies your CSS and adds vendor prefixes to it automaticall
Support for new CSS features like the [`all` property](https://developer.mozilla.org/en-US/docs/Web/CSS/all), [`break` properties](https://www.w3.org/TR/css-break-3/#breaking-controls), [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables), and [media query ranges](https://www.w3.org/TR/mediaqueries-4/#range-context) are automatically polyfilled to add support for older browsers.
You can customize your target support browsers by adjusting the `browserslist` key in `package.json` accoring to the [Browserslist specification](https://github.com/browserslist/browserslist#readme).
You can customize your target support browsers by adjusting the `browserslist` key in `package.json` according to the [Browserslist specification](https://github.com/browserslist/browserslist#readme).
For example, this:
@@ -671,7 +671,7 @@ This works in CSS too:
}
```
Webpack finds all relative module references in CSS (they start with `./`) and replaces them with the final paths from the compiled bundle. If you make a typo or accidentally delete an important file, you will see a compilation error, just like when you import a non-existent JavaScript module. The final filenames in the compiled bundle are generated by Webpack from content hashes. If the file content changes in the future, Webpack will give it a different name in production so you dont need to worry about long-term caching of assets.
Webpack finds all relative module references in CSS (they start with `./`) and replaces them with the final paths from the compiled bundle. If you make a typo or accidentally delete an important file, you will see a compilation error, just like when you import a nonexistent JavaScript module. The final filenames in the compiled bundle are generated by Webpack from content hashes. If the file content changes in the future, Webpack will give it a different name in production so you dont need to worry about long-term caching of assets.
Please be advised that this is also a custom feature of Webpack.
@@ -755,7 +755,7 @@ The `public` folder is useful as a workaround for a number of less common cases:
- You need a file with a specific name in the build output, such as [`manifest.webmanifest`](https://developer.mozilla.org/en-US/docs/Web/Manifest).
- You have thousands of images and need to dynamically reference their paths.
- You want to include a small script like [`pace.js`](http://github.hubspot.com/pace/docs/welcome/) outside of the bundled code.
- You want to include a small script like [`pace.js`](https://github.hubspot.com/pace/docs/welcome/) outside of the bundled code.
- Some library may be incompatible with Webpack and you have no other option but to include it as a `<script>` tag.
Note that if you add a `<script>` that declares global variables, you also need to read the next section on using them.
@@ -813,7 +813,7 @@ Now you are ready to use the imported reactstrap components within your componen
Sometimes you might need to tweak the visual styles of Bootstrap (or equivalent package).<br>
As of `[email protected]` you can import `.scss` files. This makes it possible to use a package's built-in Sass variables for global style preferences.
To customize Bootstrap, create a file called `src/custom.scss` (or similar) and import the Bootstrap source stylesheet. Add any overrides _before_ the imported file(s). You can reference [Bootstrap's documentation](http://getbootstrap.com/docs/4.1/getting-started/theming/#css-variables) for the names of the available variables.
To customize Bootstrap, create a file called `src/custom.scss` (or similar) and import the Bootstrap source stylesheet. Add any overrides _before_ the imported file(s). You can reference [Bootstrap's documentation](https://getbootstrap.com/docs/4.1/getting-started/theming/#css-variables) for the names of the available variables.
```scss
// Override default variables before the import
@@ -1138,7 +1138,7 @@ To tell the development server to proxy any unknown requests to your API server
This way, when you `fetch('/api/todos')` in development, the development server will recognize that its not a static asset, and will proxy your request to `http://localhost:4000/api/todos` as a fallback. The development server will **only** attempt to send requests without `text/html` in its `Accept` header to the proxy.
Conveniently, this avoids [CORS issues](http://stackoverflow.com/questions/21854516/understanding-ajax-cors-and-security-considerations) and error messages like this in development:
Conveniently, this avoids [CORS issues](https://stackoverflow.com/questions/21854516/understanding-ajax-cors-and-security-considerations) and error messages like this in development:
```
Fetch API cannot load http://localhost:4000/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
@@ -1150,7 +1150,7 @@ The `proxy` option supports HTTP, HTTPS and WebSocket connections.<br>
If the `proxy` option is **not** flexible enough for you, alternatively you can:
- [Configure the proxy yourself](#configuring-the-proxy-manually)
- Enable CORS on your server ([heres how to do it for Express](http://enable-cors.org/server_expressjs.html)).
- Enable CORS on your server ([heres how to do it for Express](https://enable-cors.org/server_expressjs.html)).
- Use [environment variables](#adding-custom-environment-variables) to inject the right server host and port into your app.
### "Invalid Host Header" Errors After Configuring Proxy
@@ -1324,7 +1324,7 @@ When you run `npm test`, Jest will launch in the watch mode. Every time you save
The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run:
![Jest watch mode](http://facebook.github.io/jest/img/blog/15-watch.gif)
![Jest watch mode](https://facebook.github.io/jest/img/blog/15-watch.gif)
### Version Control Integration
@@ -1373,7 +1373,7 @@ This test mounts a component and makes sure that it didnt throw during render
When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior.
If youd like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](http://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](http://airbnb.io/enzyme/). To install it, run:
If youd like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](https://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](https://airbnb.io/enzyme/). To install it, run:
```sh
npm install --save enzyme enzyme-adapter-react-16 react-test-renderer
@@ -1412,9 +1412,9 @@ it('renders without crashing', () => {
});
```
Unlike the previous smoke test using `ReactDOM.render()`, this test only renders `<App>` and doesnt go deeper. For example, even if `<App>` itself renders a `<Button>` that throws, this test will pass. Shallow rendering is great for isolated unit tests, but you may still want to create some full rendering tests to ensure the components integrate correctly. Enzyme supports [full rendering with `mount()`](http://airbnb.io/enzyme/docs/api/mount.html), and you can also use it for testing state changes and component lifecycle.
Unlike the previous smoke test using `ReactDOM.render()`, this test only renders `<App>` and doesnt go deeper. For example, even if `<App>` itself renders a `<Button>` that throws, this test will pass. Shallow rendering is great for isolated unit tests, but you may still want to create some full rendering tests to ensure the components integrate correctly. Enzyme supports [full rendering with `mount()`](https://airbnb.io/enzyme/docs/api/mount.html), and you can also use it for testing state changes and component lifecycle.
You can read the [Enzyme documentation](http://airbnb.io/enzyme/) for more testing techniques. Enzyme documentation uses Chai and Sinon for assertions but you dont have to use them because Jest provides built-in `expect()` and `jest.fn()` for spies.
You can read the [Enzyme documentation](https://airbnb.io/enzyme/) for more testing techniques. Enzyme documentation uses Chai and Sinon for assertions but you dont have to use them because Jest provides built-in `expect()` and `jest.fn()` for spies.
Here is an example from Enzyme documentation that asserts specific output, rewritten to use Jest matchers:
@@ -1431,8 +1431,8 @@ it('renders welcome message', () => {
});
```
All Jest matchers are [extensively documented here](http://facebook.github.io/jest/docs/en/expect.html).<br>
Nevertheless you can use a third-party assertion library like [Chai](http://chaijs.com/) if you want to, as described below.
All Jest matchers are [extensively documented here](https://facebook.github.io/jest/docs/en/expect.html).<br>
Nevertheless you can use a third-party assertion library like [Chai](https://chaijs.com/) if you want to, as described below.
Additionally, you might find [jest-enzyme](https://github.com/blainekasten/enzyme-matchers) helpful to simplify your tests with readable matchers. The above `contains` code can be written more simply with jest-enzyme.
@@ -1462,7 +1462,7 @@ import 'jest-enzyme';
We recommend that you use `expect()` for assertions and `jest.fn()` for spies. If you are having issues with them please [file those against Jest](https://github.com/facebook/jest/issues/new), and well fix them. We intend to keep making them better for React, supporting, for example, [pretty-printing React elements as JSX](https://github.com/facebook/jest/pull/1566).
However, if you are used to other libraries, such as [Chai](http://chaijs.com/) and [Sinon](http://sinonjs.org/), or if you have existing code using them that youd like to port over, you can import them normally like this:
However, if you are used to other libraries, such as [Chai](https://chaijs.com/) and [Sinon](https://sinonjs.org/), or if you have existing code using them that youd like to port over, you can import them normally like this:
```js
import sinon from 'sinon';
@@ -1509,7 +1509,7 @@ Similarly, `fit()` lets you focus on a specific test without running any other t
Jest has an integrated coverage reporter that works well with ES6 and requires no configuration.<br>
Run `npm test -- --coverage` (note extra `--` in the middle) to include a coverage report like this:
![coverage report](http://i.imgur.com/5bFhnTS.png)
![coverage report](https://i.imgur.com/5bFhnTS.png)
Note that tests run much slower with coverage so it is recommended to run it separately from your normal workflow.
@@ -1640,18 +1640,18 @@ To help you make up your mind, here is a list of APIs that **need jsdom**:
- Any browser globals like `window` and `document`
- [`ReactDOM.render()`](https://facebook.github.io/react/docs/top-level-api.html#reactdom.render)
- [`TestUtils.renderIntoDocument()`](https://facebook.github.io/react/docs/test-utils.html#renderintodocument) ([a shortcut](https://github.com/facebook/react/blob/34761cf9a252964abfaab6faf74d473ad95d1f21/src/test/ReactTestUtils.js#L83-L91) for the above)
- [`mount()`](http://airbnb.io/enzyme/docs/api/mount.html) in [Enzyme](http://airbnb.io/enzyme/index.html)
- [`mount()`](https://airbnb.io/enzyme/docs/api/mount.html) in [Enzyme](https://airbnb.io/enzyme/index.html)
In contrast, **jsdom is not needed** for the following APIs:
- [`TestUtils.createRenderer()`](https://facebook.github.io/react/docs/test-utils.html#shallow-rendering) (shallow rendering)
- [`shallow()`](http://airbnb.io/enzyme/docs/api/shallow.html) in [Enzyme](http://airbnb.io/enzyme/index.html)
- [`shallow()`](https://airbnb.io/enzyme/docs/api/shallow.html) in [Enzyme](https://airbnb.io/enzyme/index.html)
Finally, jsdom is also not needed for [snapshot testing](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html).
Finally, jsdom is also not needed for [snapshot testing](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html).
### Snapshot Testing
Snapshot testing is a feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. [Read more about snapshot testing.](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html)
Snapshot testing is a feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. [Read more about snapshot testing.](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html)
### Editor Integration
@@ -1735,7 +1735,7 @@ Usually, its hard to see these states without running a sample app or some ex
Create React App doesnt include any tools for this by default, but you can easily add [Storybook for React](https://storybook.js.org) ([source](https://github.com/storybooks/storybook)) or [React Styleguidist](https://react-styleguidist.js.org/) ([source](https://github.com/styleguidist/react-styleguidist)) to your project. **These are third-party tools that let you develop components and see all their states in isolation from your app**.
![Storybook for React Demo](http://i.imgur.com/7CIAWpB.gif)
![Storybook for React Demo](https://i.imgur.com/7CIAWpB.gif)
You can also deploy your Storybook or style guide as a static app. This way, everyone in your team can view and review different states of UI components without starting a backend server or creating an account in your app.
@@ -1820,7 +1820,7 @@ following in their [`src/index.js`](src/index.js) file:
```js
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
```
@@ -1854,7 +1854,7 @@ following into account:
1. Service workers [require HTTPS](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers#you_need_https),
although to facilitate local testing, that policy
[does not apply to `localhost`](http://stackoverflow.com/questions/34160509/options-for-testing-service-workers-via-http/34161385#34161385).
[does not apply to `localhost`](https://stackoverflow.com/questions/34160509/options-for-testing-service-workers-via-http/34161385#34161385).
If your production web server does not support HTTPS, then the service worker
registration will fail, but the rest of your web app will remain functional.
@@ -1970,7 +1970,7 @@ serve -h
You dont necessarily need a static server in order to run a Create React App project in production. It works just as fine integrated into an existing dynamic one.
Heres a programmatic example using [Node](https://nodejs.org/) and [Express](http://expressjs.com/):
Heres a programmatic example using [Node](https://nodejs.org/) and [Express](https://expressjs.com/):
```javascript
const express = require('express');
@@ -2018,7 +2018,7 @@ If youre using [Apache HTTP Server](https://httpd.apache.org/), you need to c
It will get copied to the `build` folder when you run `npm run build`.
If youre using [Apache Tomcat](http://tomcat.apache.org/), you need to follow [this Stack Overflow answer](https://stackoverflow.com/a/41249464/4878474).
If youre using [Apache Tomcat](https://tomcat.apache.org/), you need to follow [this Stack Overflow answer](https://stackoverflow.com/a/41249464/4878474).
Now requests to `/todos/42` will be handled correctly both in development and in production.
@@ -2029,7 +2029,7 @@ service worker navigation routing can be configured or disabled by
[`eject`ing](#npm-run-eject) and then modifying the
[`navigateFallback`](https://github.com/GoogleChrome/sw-precache#navigatefallback-string)
and [`navigateFallbackWhitelist`](https://github.com/GoogleChrome/sw-precache#navigatefallbackwhitelist-arrayregexp)
options of the `SWPreachePlugin` [configuration](../config/webpack.config.prod.js).
options of the `SWPrecachePlugin` [configuration](../config/webpack.config.prod.js).
When users install your app to the homescreen of their device the default configuration will make a shortcut to `/index.html`. This may not work for client-side routers which expect the app to be served from `/`. Edit the web app manifest at [`public/manifest.json`](public/manifest.json) and change `start_url` to match the required URL scheme, for example:
@@ -2043,7 +2043,7 @@ By default, Create React App produces a build assuming your app is hosted at the
To override this, specify the `homepage` in your `package.json`, for example:
```js
"homepage": "http://mywebsite.com/relativepath",
"homepage": "https://example.com/relativepath",
```
This will let Create React App correctly infer the root path to use in the generated HTML file.
@@ -2068,7 +2068,7 @@ If you are not using the HTML5 `pushState` history API or not using client-side
"homepage": ".",
```
This will make sure that all the asset paths are relative to `index.html`. You will then be able to move your app from `http://mywebsite.com` to `http://mywebsite.com/relativepath` or even `http://mywebsite.com/relative/path` without having to rebuild it.
This will make sure that all the asset paths are relative to `index.html`. You will then be able to move your app from `https://example.com` to `https://example.com/relativepath` or even `https://example.com/relative/path` without having to rebuild it.
### Customizing Environment Variables for Arbitrary Build Environments
@@ -2077,7 +2077,7 @@ You can create an arbitrary build environment by creating a custom `.env` file a
For example, to create a build environment for a staging environment:
1. Create a file called `.env.staging`
1. Set environment variables as you would any other `.env` file (e.g. `REACT_APP_API_URL=http://api-staging.example.com`)
1. Set environment variables as you would any other `.env` file (e.g. `REACT_APP_API_URL=https://api-staging.example.com`)
1. Install [env-cmd](https://www.npmjs.com/package/env-cmd)
```sh
$ npm install env-cmd --save
@@ -2201,7 +2201,7 @@ or for a GitHub user page:
or for a custom domain page:
```json
"homepage": "https://mywebsite.com",
"homepage": "https://example.com",
```
Create React App uses the `homepage` field to determine the root URL in the built HTML file.
@@ -2259,7 +2259,7 @@ npm run deploy
Finally, make sure **GitHub Pages** option in your GitHub project settings is set to use the `gh-pages` branch:
<img src="http://i.imgur.com/HUjEr9l.png" width="500" alt="gh-pages branch setting">
<img src="https://i.imgur.com/HUjEr9l.png" width="500" alt="gh-pages branch setting">
#### Step 5: Optionally, configure the domain
@@ -2268,14 +2268,14 @@ You can configure a custom domain with GitHub Pages by adding a `CNAME` file to
Your CNAME file should look like this:
```
mywebsite.com
example.com
```
#### Notes on client-side routing
GitHub Pages doesnt support routers that use the HTML5 `pushState` history API under the hood (for example, React Router using `browserHistory`). This is because when there is a fresh page load for a url like `http://user.github.io/todomvc/todos/42`, where `/todos/42` is a frontend route, the GitHub Pages server returns 404 because it knows nothing of `/todos/42`. If you want to add a router to a project hosted on GitHub Pages, here are a couple of solutions:
GitHub Pages doesnt support routers that use the HTML5 `pushState` history API under the hood (for example, React Router using `browserHistory`). This is because when there is a fresh page load for a url like `https://user.github.io/todomvc/todos/42`, where `/todos/42` is a frontend route, the GitHub Pages server returns 404 because it knows nothing of `/todos/42`. If you want to add a router to a project hosted on GitHub Pages, here are a couple of solutions:
- You could switch from using HTML5 history API to routing with hashes. If you use React Router, you can switch to `hashHistory` for this effect, but the URL will be longer and more verbose (for example, `http://user.github.io/todomvc/#/todos/42?_k=yknaj`). [Read more](https://reacttraining.com/react-router/web/api/Router) about different history implementations in React Router.
- You could switch from using HTML5 history API to routing with hashes. If you use React Router, you can switch to `hashHistory` for this effect, but the URL will be longer and more verbose (for example, `https://user.github.io/todomvc/#/todos/42?_k=yknaj`). [Read more](https://reacttraining.com/react-router/web/api/Router) about different history implementations in React Router.
- Alternatively, you can use a trick to teach GitHub Pages to handle 404 by redirecting to your `index.html` page with a special redirect parameter. You would need to add a `404.html` file with the redirection code to the `build` folder before deploying your project, and youll need to add code handling the redirect parameter to `index.html`. You can find a detailed explanation of this technique [in this guide](https://github.com/rafrex/spa-github-pages).
#### Troubleshooting
@@ -2317,7 +2317,7 @@ MyDirectory in /tmp/build_1234/src
It means you need to ensure that the lettercase of the file or directory you `import` matches the one you see on your filesystem or on GitHub.
This is important because Linux (the operating system used by Heroku) is case sensitive. So `MyDirectory` and `mydirectory` are two distinct directories and thus, even though the project builds locally, the difference in case breaks the `import` statements on Heroku remotes.
This is important because Linux (the operating system used by Heroku) is case-sensitive. So `MyDirectory` and `mydirectory` are two distinct directories and thus, even though the project builds locally, the difference in case breaks the `import` statements on Heroku remotes.
##### "Could not find a required file."
@@ -2442,7 +2442,7 @@ We recommend deleting `node_modules` in your project and running `npm install` (
- [facebook/watchman#358](https://github.com/facebook/watchman/issues/358)
- [ember-cli/ember-cli#6259](https://github.com/ember-cli/ember-cli/issues/6259)
It is reported that installing Watchman 4.7.0 or newer fixes the issue. If you use [Homebrew](http://brew.sh/), you can run these commands to update it:
It is reported that installing Watchman 4.7.0 or newer fixes the issue. If you use [Homebrew](https://brew.sh/), you can run these commands to update it:
```
watchman shutdown-server
@@ -2466,7 +2466,7 @@ If you are completely sure that you didn't terminate the process, consider [addi
### `npm run build` fails on Heroku
This may be a problem with case sensitive filenames.
This may be a problem with case-sensitive filenames.
Please refer to [this section](#resolving-heroku-deployment-errors).
### Moment.js locales are missing
+16737
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"html-react-parser": "^0.4.7",
"liquidjs": "^9.1.0",
"liquidjs": "^10.8.3",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-promise": "^2.0.3",
+1 -1
View File
@@ -9,5 +9,5 @@ ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
+82
View File
@@ -0,0 +1,82 @@
{
"name": "liquidjs-demo-typescript",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@types/node": {
"version": "14.18.34",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz",
"integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==",
"dev": true
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"commander": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
},
"liquidjs": {
"version": "10.8.3",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.8.3.tgz",
"integrity": "sha512-LqHLYtH3vrkT3LyfOhPU0FJX5KPO4aB6SzGa4HRI29yz8pS0ZxqIe/fWtic8qiust1+qrHI92J67tdt92V4WOA==",
"requires": {
"commander": "^10.0.0"
}
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"ts-node": {
"version": "8.10.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
"integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==",
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"typescript": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg=="
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
}
}
}
+1 -1
View File
@@ -7,7 +7,7 @@
"start": "ts-node index.ts"
},
"dependencies": {
"liquidjs": "*",
"liquidjs": "^10.8.3",
"ts-node": "^8.10.2",
"typescript": "^4.2.4"
},
+979
View File
@@ -0,0 +1,979 @@
{
"name": "liquidjs-demo-nodejs",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true
},
"@jridgewell/gen-mapping": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
"dev": true,
"requires": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"dev": true
},
"@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true
},
"@jridgewell/source-map": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "3.1.0",
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
"@types/eslint": {
"version": "8.4.7",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz",
"integrity": "sha512-ehM7cCt2RSFs42mb+lcmhFT9ouIlV92PuaeRGn8N8c98oMjG4Z5pJHA9b1QiCcuqnbPSHcyfiD3mlhqMaHsQIw==",
"dev": true,
"requires": {
"@types/estree": "*",
"@types/json-schema": "*"
}
},
"@types/eslint-scope": {
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
"integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
"dev": true,
"requires": {
"@types/eslint": "*",
"@types/estree": "*"
}
},
"@types/estree": {
"version": "0.0.51",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
"dev": true
},
"@types/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"dev": true
},
"@types/node": {
"version": "18.11.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz",
"integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==",
"dev": true
},
"@webassemblyjs/ast": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
"integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
"dev": true,
"requires": {
"@webassemblyjs/helper-numbers": "1.11.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.1"
}
},
"@webassemblyjs/floating-point-hex-parser": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
"integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
"dev": true
},
"@webassemblyjs/helper-api-error": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
"integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
"dev": true
},
"@webassemblyjs/helper-buffer": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
"integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
"dev": true
},
"@webassemblyjs/helper-numbers": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
"integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
"dev": true,
"requires": {
"@webassemblyjs/floating-point-hex-parser": "1.11.1",
"@webassemblyjs/helper-api-error": "1.11.1",
"@xtuc/long": "4.2.2"
}
},
"@webassemblyjs/helper-wasm-bytecode": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
"integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
"dev": true
},
"@webassemblyjs/helper-wasm-section": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
"integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/helper-buffer": "1.11.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
"@webassemblyjs/wasm-gen": "1.11.1"
}
},
"@webassemblyjs/ieee754": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
"integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
"dev": true,
"requires": {
"@xtuc/ieee754": "^1.2.0"
}
},
"@webassemblyjs/leb128": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
"integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
"dev": true,
"requires": {
"@xtuc/long": "4.2.2"
}
},
"@webassemblyjs/utf8": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
"integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
"dev": true
},
"@webassemblyjs/wasm-edit": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
"integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/helper-buffer": "1.11.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
"@webassemblyjs/helper-wasm-section": "1.11.1",
"@webassemblyjs/wasm-gen": "1.11.1",
"@webassemblyjs/wasm-opt": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1",
"@webassemblyjs/wast-printer": "1.11.1"
}
},
"@webassemblyjs/wasm-gen": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
"integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
"@webassemblyjs/ieee754": "1.11.1",
"@webassemblyjs/leb128": "1.11.1",
"@webassemblyjs/utf8": "1.11.1"
}
},
"@webassemblyjs/wasm-opt": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
"integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/helper-buffer": "1.11.1",
"@webassemblyjs/wasm-gen": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1"
}
},
"@webassemblyjs/wasm-parser": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
"integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/helper-api-error": "1.11.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.1",
"@webassemblyjs/ieee754": "1.11.1",
"@webassemblyjs/leb128": "1.11.1",
"@webassemblyjs/utf8": "1.11.1"
}
},
"@webassemblyjs/wast-printer": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
"integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.11.1",
"@xtuc/long": "4.2.2"
}
},
"@webpack-cli/configtest": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
"integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
"dev": true
},
"@webpack-cli/info": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
"integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
"dev": true,
"requires": {
"envinfo": "^7.7.3"
}
},
"@webpack-cli/serve": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
"integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
"dev": true
},
"@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"dev": true
},
"@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"dev": true
},
"acorn": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
"dev": true
},
"acorn-import-assertions": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
"dev": true
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
},
"browserslist": {
"version": "4.21.4",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001400",
"electron-to-chromium": "^1.4.251",
"node-releases": "^2.0.6",
"update-browserslist-db": "^1.0.9"
}
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001423",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz",
"integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==",
"dev": true
},
"chrome-trace-event": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
"integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
"dev": true
},
"clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
"integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
"dev": true,
"requires": {
"is-plain-object": "^2.0.4",
"kind-of": "^6.0.2",
"shallow-clone": "^3.0.0"
}
},
"colorette": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"electron-to-chromium": {
"version": "1.4.284",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
"dev": true
},
"enhanced-resolve": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
"integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
}
},
"envinfo": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
"integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
"dev": true
},
"es-module-lexer": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
"integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
"dev": true
},
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true
},
"eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
}
},
"esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"requires": {
"estraverse": "^5.2.0"
},
"dependencies": {
"estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true
}
}
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true
},
"events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true
},
"fastest-levenshtein": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
"integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
"dev": true
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"dev": true
},
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"hello-liquid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hello-liquid/-/hello-liquid-1.0.0.tgz",
"integrity": "sha512-WNmZp5s647BN2WHPq4FHVH85CcqNVet5DXIVw1UtVMaV+MJHFA+ylge0hqHSw0iOI/Ojrx8KEKZurYZix5PekQ=="
},
"import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
"integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
"dev": true,
"requires": {
"pkg-dir": "^4.2.0",
"resolve-cwd": "^3.0.0"
}
},
"interpret": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
"dev": true
},
"is-core-module": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
"dev": true,
"requires": {
"isobject": "^3.0.1"
}
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
"dev": true
},
"jest-worker": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"dev": true,
"requires": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
}
},
"json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"liquidjs": {
"version": "9.42.0",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-9.42.0.tgz",
"integrity": "sha512-krvhwGFrMCMGhybGkxJIvlWVVnoCSpYCn7NhEN43+uvlg2vOkYWpq8be+L3NMlOfwe4ZrKQ7hCh1EmS4yhLKow=="
},
"loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
"dev": true
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"requires": {
"mime-db": "1.52.0"
}
},
"neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node-releases": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
"dev": true
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"requires": {
"find-up": "^4.0.0"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.0"
}
},
"rechoir": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
"integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
"dev": true,
"requires": {
"resolve": "^1.9.0"
}
},
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"dev": true,
"requires": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
},
"resolve-cwd": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
"integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
"dev": true,
"requires": {
"resolve-from": "^5.0.0"
}
},
"resolve-from": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
},
"serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
},
"shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
"integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
"dev": true,
"requires": {
"kind-of": "^6.0.2"
}
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
"tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true
},
"terser": {
"version": "5.15.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz",
"integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==",
"dev": true,
"requires": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
}
},
"terser-webpack-plugin": {
"version": "5.3.6",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
"integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
"dev": true,
"requires": {
"@jridgewell/trace-mapping": "^0.3.14",
"jest-worker": "^27.4.5",
"schema-utils": "^3.1.1",
"serialize-javascript": "^6.0.0",
"terser": "^5.14.1"
}
},
"update-browserslist-db": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
"dev": true,
"requires": {
"escalade": "^3.1.1",
"picocolors": "^1.0.0"
}
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
},
"watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"dev": true,
"requires": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
}
},
"webpack": {
"version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/wasm-edit": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1",
"acorn": "^8.7.1",
"acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.10.0",
"es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.9",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.4.0",
"webpack-sources": "^3.2.3"
}
},
"webpack-cli": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
"integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.2.0",
"@webpack-cli/info": "^1.5.0",
"@webpack-cli/serve": "^1.7.0",
"colorette": "^2.0.14",
"commander": "^7.0.0",
"cross-spawn": "^7.0.3",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"webpack-merge": "^5.7.3"
},
"dependencies": {
"commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
}
}
},
"webpack-merge": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
"integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
"dev": true,
"requires": {
"clone-deep": "^4.0.1",
"wildcard": "^2.0.0"
}
},
"webpack-sources": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
"dev": true
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
},
"wildcard": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
"dev": true
}
}
}
+7 -7
View File
@@ -1,6 +1,6 @@
title: LiquidJS
subtitle: "A simple, expressive and safe template engine."
description: "LiquidJS is a simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript."
description: "LiquidJS is a simple, expressive and safe Shopify / GitHub Pages compatible template engine in pure JavaScript."
author: Harttle
language:
- en
@@ -19,14 +19,15 @@ pretty_urls:
trailing_html: false
theme: navy
skip_render: "api/**/*"
highlight:
enable: false
skip_render: "api/**"
ignore: "api/**"
include: "api/**"
syntax_highlighter: prismjs
prismjs:
enable: true
preprocess: true
line_number: true
tab_replace: ''
line_threshold: 0
tab_replace: ""
algolia:
applicationID: 0X19J927JZ
@@ -34,5 +35,4 @@ algolia:
indexName: liquidjs
twitter: harttleharttle
github: harttle/liquidjs
patreon: harttle
oc: liquidjs
+535 -1741
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"hexo": {
"version": "5.4.0"
"version": "7.3.0"
},
"scripts": {
"build": "hexo generate",
@@ -13,7 +13,7 @@
},
"dependencies": {
"cheerio": "^0.22.0",
"hexo": "^5.4.0",
"hexo": "^7.3.0",
"hexo-algolia": "^1.3.1",
"hexo-clean-css": "^1.0.0",
"hexo-filter-nofollow": "^2.0.2",
@@ -28,11 +28,10 @@
"hexo-uglify": "^1.0.0"
},
"devDependencies": {
"all-contributors-cli": "^6.8.1",
"eslint": "^6.0.1",
"eslint-config-hexo": "^4.0.0"
},
"engines": {
"node": ">=8.10.0"
}
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ const { readFileSync } = require('fs')
const cheerio = require('cheerio')
const fullUrlFor = hexo.extend.helper.get('full_url_for').bind(hexo)
const localizedPath = ['tutorials', 'filters', 'tags', 'playground', 'api']
const localizedPath = ['tutorials', 'filters', 'tags', 'playground']
hexo.extend.helper.register('page_nav', function () {
const type = this.page.canonical_path.split('/')[0]
+28 -51
View File
@@ -8,15 +8,18 @@ tutorials:
express: use-in-expressjs.html
advanced:
caching: caching.html
registeration: register-filters-tags.html
escaping: escaping.html
registration: 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
drops: drops.html
sync_and_async: sync-and-async.html
whitespace: whitespace-control.html
plugins: plugins.html
operators: operators.html
truth: truthy-and-falsy.html
dos: dos.html
miscellaneous:
migration9: migrate-to-9.html
changelog: changelog.html
@@ -27,29 +30,45 @@ filters:
overview: overview.html
abs: abs.html
append: append.html
array_to_sentence_string: array_to_sentence_string.html
at_least: at_least.html
at_most: at_most.html
capitalize: capitalize.html
ceil: ceil.html
cgi_escape: cgi_escape.html
compact: compact.html
concat: concat.html
date: date.html
date_to_long_string: date_to_long_string.html
date_to_rfc822: date_to_rfc822.html
date_to_string: date_to_string.html
date_to_xmlschema: date_to_xmlschema.html
default: default.html
divided_by: divided_by.html
downcase: downcase.html
escape: escape.html
escape_once: escape_once.html
find: find.html
find_exp: find_exp.html
first: first.html
floor: floor.html
group_by: group_by.html
group_by_exp: group_by_exp.html
inspect: inspect.html
join: join.html
json: json.html
jsonify: jsonify.html
last: last.html
lstrip: lstrip.html
map: map.html
minus: minus.html
modulo: modulo.html
newline_to_br: newline_to_br.html
normalize_whitespace: normalize_whitespace.html
number_of_words: number_of_words.html
plus: plus.html
pop: pop.html
push: push.html
prepend: prepend.html
raw: raw.html
remove: remove.html
@@ -61,22 +80,30 @@ filters:
reverse: reverse.html
round: round.html
rstrip: rstrip.html
shift: shift.html
size: size.html
slice: slice.html
slugify: slugify.html
sort: sort.html
sort_natural: sort_natural.html
split: split.html
strip: strip.html
strip_html: strip_html.html
strip_newlines: strip_newlines.html
sum: sum.html
times: times.html
to_integer: to_integer.html
truncate: truncate.html
truncatewords: truncatewords.html
uniq: uniq.html
unshift: unshift.html
upcase: upcase.html
uri_escape: uri_escape.html
url_decode: url_decode.html
url_encode: url_encode.html
where: where.html
where_exp: where_exp.html
xml_escape: xml_escape.html
tags:
overview: overview.html
@@ -101,53 +128,3 @@ tags:
tablerow: tablerow.html
unless: unless.html
when: case.html
api:
quick_entry:
Liquid: "../classes/liquid_.liquid.html"
LiquidOptions: "../interfaces/liquid_options_.liquidoptions.html"
FS: "../interfaces/fs_fs_.fs.html"
Cache: "../interfaces/cache_cache_.cache.html"
classes:
BlankDrop: "../classes/drop_blank_drop_.blankdrop.html"
Context: "../classes/context_context_.context.html"
DelimitedToken: "../classes/tokens_delimited_token_.delimitedtoken.html"
Drop: "../classes/drop_drop_.drop.html"
EmptyDrop: "../classes/drop_empty_drop_.emptydrop.html"
Expression: "../classes/render_expression_.expression.html"
FilterToken: "../classes/tokens_filter_token_.filtertoken.html"
ForloopDrop: "../classes/drop_forloop_drop_.forloopdrop.html"
HTMLToken: "../classes/tokens_html_token_.htmltoken.html"
HashToken: "../classes/tokens_hash_token_.hashtoken.html"
LRU: "../classes/cache_lru_.lru.html"
Liquid: "../classes/liquid_.liquid.html"
LiteralToken: "../classes/tokens_literal_token_.literaltoken.html"
NullDrop: "../classes/drop_null_drop_.nulldrop.html"
NumberToken: "../classes/tokens_number_token_.numbertoken.html"
OperatorToken: "../classes/tokens_operator_token_.operatortoken.html"
OutputToken: "../classes/tokens_output_token_.outputtoken.html"
ParseError: "../classes/util_error_.parseerror.html"
ParseStream: "../classes/parser_parse_stream_.parsestream.html"
Parser: "../classes/parser_parser_.parser.html"
PropertyaccessToken: "../classes/tokens_property_access_token_.propertyaccesstoken.html"
QuotedToken: "../classes/tokens_quoted_token_.quotedtoken.html"
RangeToken: "../classes/tokens_range_token_.rangetoken.html"
Render: "../classes/render_render_.render.html"
RenderError: "../classes/util_error_.rendererror.html"
TablerowloopDrop: "../classes/drop_tablerowloop_drop_.tablerowloopdrop.html"
TagToken: "../classes/tokens_tag_token_.tagtoken.html"
Token: "../classes/tokens_token_.token.html"
TokenizationError: "../classes/util_error_.tokenizationerror.html"
Tokenizer: "../classes/parser_tokenizer_.tokenizer.html"
WordToken: "../classes/tokens_word_token_.wordtoken.html"
enums:
BlockMode: "../enums/context_block_mode_.blockmode.html"
TokenKind: "../enums/parser_token_kind_.tokenkind.html"
interfaces:
Cache: "../interfaces/cache_cache_.cache.html"
FilterImplOptions: "../interfaces/template_filter_filter_impl_options_.filterimploptions.html"
FS: "../interfaces/fs_fs_.fs.html"
LiquidOptions: "../interfaces/liquid_options_.liquidoptions.html"
NormalizedFullOptions: "../interfaces/liquid_options_.normalizedfulloptions.html"
PlainObject: "../interfaces/context_scope_.plainobject.html"
TagImplOptions: "../interfaces/template_tag_tag_impl_options_.tagimploptions.html"
@@ -0,0 +1,27 @@
---
title: array_to_sentence_string
---
{% since %}v10.13.0{% endsince %}
Convert an array into a sentence. Useful for listing tags. Optional argument for connector.
Input
```liquid
{{ "foo,bar,baz" | split: "," | array_to_sentence_string }}
```
Output
```text
foo, bar, and baz
```
Input
```liquid
{{ "foo,bar,baz" | split: "," | array_to_sentence_string: "or" }}
```
Output
```text
foo, bar, or baz
```
+17
View File
@@ -0,0 +1,17 @@
---
title: cgi_escape
---
{% since %}v10.13.0{% endsince %}
CGI escape a string for use in a URL. Replaces any special characters with appropriate `%XX` replacements. CGI escape normally replaces a space with a plus `+` sign.
Input
```liquid
{{ "foo, bar; baz?" | cgi_escape }}
```
Output
```text
foo%2C+bar%3B+baz%3F
```
+17 -17
View File
@@ -3,15 +3,18 @@ title: date
---
{% since %}v1.9.1{% endsince %}
# Format
* Converts a timestamp into another date format
* LiquidJS tries to be conformant with Shopify/Liquid which is using Ruby's core [Time#strftime(string)](http://www.ruby-doc.org/core/Time.html#method-i-strftime)
* Refer [format flags](https://ruby-doc.org/core/strftime_formatting_rdoc.html)
* Not all options are supported though - refer [differences here](/tutorials/differences.html#Differences)
* The input is firstly converted to `Date` object via [new Date()][jsDate]
* Date format can be provided individually as a filter option
* If not provided, then `%A, %B %-e, %Y at %-l:%M %P %z` format will be used as default format
* Override this using [`dateFormat`](/api/interfaces/LiquidOptions.html#dateFormat) LiquidJS option, to set your preferred default format for all date filters
Date filter is used to convert a timestamp into the specified format.
* LiquidJS tries to conform to Shopify/Liquid, which uses Ruby's core [Time#strftime(string)](https://www.ruby-doc.org/core/Time.html#method-i-strftime). There're differences with [Ruby's format flags](https://ruby-doc.org/core/strftime_formatting_rdoc.html):
* `%Z` (since v10.11.1) is replaced by the passed-in timezone name from `LiquidOption` or in-place value (see TimeZone below). If passed-in timezone is an offset number instead of string, it'll behave like `%z`. If there's none passed-in timezone, it returns [the runtime's default time zone](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions#timezone).
* LiquidJS provides an additional `%q` flag for date ordinals. e.g. `{{ '2023/02/02' | date: '%d%q of %b'}}` => `02nd of Feb`
* Date literals are firstly converted to `Date` object via [new Date()][jsDate], that means literal values are considered in runtime's time zone by default.
* The format filter argument is optional:
* If not provided, it defaults to `%A, %B %-e, %Y at %-l:%M %P %z`.
* The above default can be overridden by [`dateFormat`](/api/interfaces/LiquidOptions.html#dateFormat) LiquidJS option.
* LiquidJS `date` supports locale specific weekdays and month names, which will fallback to English where `Intl` is not supported.
* Ordinals (`%q`) and Jekyll specific date filters are English-only.
* [`locale`](/api/interfaces/LiquidOptions.html#locale) can be set when creating Liquid instance. Defaults to `Intl.DateTimeFormat().resolvedOptions.locale`).
### Examples
```liquid
@@ -23,16 +26,14 @@ title: date
```
# TimeZone
* By default, dates will be converted to local timezone before output
* You can override that by,
* setting a timezone for each individual `date` filter via the second parameter
* using the [`timezoneOffset`](/api/interfaces/LiquidOptions.html#timezoneOffset) LiquidJS option
* Its default value is your local timezone offset which can be obtained by `new Date().getTimezoneOffset()`
* During output, LiquidJS uses local timezone which can override by:
* setting a timezone in-place when calling `date` filter, or
* setting the [`timezoneOffset`](/api/interfaces/LiquidOptions.html#timezoneOffset) LiquidJS option
* It defaults to runtime's time one.
* Offset can be set as,
* minutes: `-360` means `'+06:00'` and `360` means `'-06:00'`
* timeZone ID: `Asia/Colombo` or `America/New_York`
* Use minutes for better performance with repeated processing of templates with many dates like, converting template for each email recipient
* Refer [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for TZ database values
* See [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for TZ database values
### Examples
```liquid
@@ -41,7 +42,6 @@ title: date
{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", "Asia/Colombo" }} => 1991-01-01T04:30:00
```
# Input
* `date` works on strings if they contain well-formatted dates
* Note that LiquidJS is using [JavaScript Date][jsDate] 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.
@@ -0,0 +1,30 @@
---
title: date_to_long_string
---
{% since %}v10.13.0{% endsince %}
Convert a date to long format. Same with Jekyll `date_to_long_string` filter.
Input
```liquid
{{ site.time | date_to_long_string }}
```
Output
```text
07 November 2008
```
Input
```liquid
{{ site.time | date_to_long_string: "ordinal" }}
```
Output
```text
7th November 2008
```
Note that JavaScript `Date` has not timezone information, see [date][date] filter for details.
[date]: ./date.html
+20
View File
@@ -0,0 +1,20 @@
---
title: date_to_rfc822
---
{% since %}v10.13.0{% endsince %}
Convert a Date into the RFC-822 format used for RSS feeds, same as Jekyll filter `date_to_rfc822`.
Input
```liquid
{{ site.time | date_to_rfc822 }}
```
Output
```text
Mon, 07 Nov 2008 13:07:54 -0800
```
Note that JavaScript `Date` has not timezone information, see [date][date] filter for details.
[date]: ./date.html
+30
View File
@@ -0,0 +1,30 @@
---
title: date_to_string
---
{% since %}v10.13.0{% endsince %}
Convert a date to short format. Same with Jekyll `date_to_string` filter.
Input
```liquid
{{ site.time | date_to_string }}
```
Output
```text
07 Nov 2008
```
Input
```liquid
{{ site.time | date_to_string: "ordinal", "US" }}
```
Output
```text
Nov 7th, 2008
```
Note that JavaScript `Date` has not timezone information, see [date][date] filter for details.
[date]: ./date.html
+20
View File
@@ -0,0 +1,20 @@
---
title: date_to_xmlschema
---
{% since %}v10.13.0{% endsince %}
Convert a Date into XML Schema (ISO 8601) format, same as Jekyll filter `date_to_xmlschema`.
Input
```liquid
{{ site.time | date_to_xmlschema }}
```
Output
```text
2008-11-07T13:07:54-08:00
```
Note that JavaScript `Date` has not timezone information, see [date][date] filter for details.
[date]: ./date.html
+25
View File
@@ -0,0 +1,25 @@
---
title: find
---
{% since %}v10.11.0{% endsince %}
Return the first object in an array for which the queried attribute has the given value or return `nil` if no item in the array satisfies the given criteria. For the following `members` array:
```javascript
const members = [
{ graduation_year: 2013, name: 'Jay' },
{ graduation_year: 2014, name: 'John' },
{ graduation_year: 2014, name: 'Jack' }
]
```
Input
```liquid
{{ members | find: "graduation_year", 2014 | json }}
```
Output
```text
{"graduation_year":2014,"name":"John"}
```
+25
View File
@@ -0,0 +1,25 @@
---
title: find_exp
---
{% since %}v10.11.0{% endsince %}
Return the first object in an array for which the given expression evaluates to true or return `nil` if no item in the array satisfies the evaluated expression.
```javascript
const members = [
{ graduation_year: 2013, name: 'Jay' },
{ graduation_year: 2014, name: 'John' },
{ graduation_year: 2014, name: 'Jack' }
]
```
Input
```liquid
{{ members | find_exp: "item", "item.graduation_year == 2014" | json }}
```
Output
```text
{"graduation_year":2014,"name":"John"}
```
+48
View File
@@ -0,0 +1,48 @@
---
title: group_by
---
{% since %}v10.11.0{% endsince %}
Group an array's items by a given property. For `members` array:
```javascript
const members = [
{ graduation_year: 2003, name: 'Jay' },
{ graduation_year: 2003, name: 'John' },
{ graduation_year: 2004, name: 'Jack' }
]
```
Input
```liquid
{{ members | group_by: "graduation_year" | json: 2 }}
```
Output
```text
[
{
"name": 2003,
"items": [
{
"graduation_year": 2003,
"name": "Jay"
},
{
"graduation_year": 2003,
"name": "John"
}
]
},
{
"name": 2004,
"items": [
{
"graduation_year": 2004,
"name": "Jack"
}
]
}
]
```
+48
View File
@@ -0,0 +1,48 @@
---
title: group_by_exp
---
{% since %}v10.11.0{% endsince %}
Group an array's items using a Liquid expression. For `members` array below:
```javascript
const members = [
{ graduation_year: 2013, name: 'Jay' },
{ graduation_year: 2014, name: 'John' },
{ graduation_year: 2009, name: 'Jack' }
]
```
Input
```liquid
{{ members | group_by_exp: "item", "item.graduation_year | truncate: 3, ''" | json: 2 }}
```
Output
```text
[
{
"name": "201",
"items": [
{
"graduation_year": 2013,
"name": "Jay"
},
{
"graduation_year": 2014,
"name": "John"
}
]
},
{
"name": "200",
"items": [
{
"graduation_year": 2009,
"name": "Jack"
}
]
}
]
```
+42
View File
@@ -0,0 +1,42 @@
---
title: inspect
---
{% since %}v10.13.0{% endsince %}
Similar with `json`, but `inspect` allows cyclic structure. For the scope below:
```
const foo = {
bar: 'BAR'
}
foo.foo = foo
const scope = { foo }
```
Input
```liquid
{% foo | inspect %}
```
Output
```text
{"bar":"BAR","foo":"[Circular]"}
```
## Formatting
An additional `space` argument can be specified for the indent width.
Input
```liquid
{{ foo | inspect: 4 }}
```
Output
```text
{
"bar": "BAR",
"foo": "[Circular]"
}
```
+21
View File
@@ -16,3 +16,24 @@ Output
```text
["foo","bar","coo"]
```
## Space
{% since %}v10.11.0{% endsince %}
An additional `space` parameter can be specified to format the JSON.
Input
```liquid
{% assign arr = "foo bar coo" | split: " " %}
{{ arr | json: 4 }}
```
Output
```text
[
"foo",
"bar",
"coo"
]
```
+9
View File
@@ -0,0 +1,9 @@
---
title: jsonify
---
{% since %}v10.13.0{% endsince %}
See [json][json].
[json]: /filters/json.html
@@ -0,0 +1,17 @@
---
title: normalize_whitespace
---
{% since %}v10.13.0{% endsince %}
Replace any occurrence of whitespace with a single space.
Input
```liquid
{{ "a \n b" | normalize_whitespace }}
```
Output
```html
a b
```
+49
View File
@@ -0,0 +1,49 @@
---
title: number_of_words
---
{% since %}v10.13.0{% endsince %}
Count the number of words in some text. This filter takes an optional argument to control the handling of Chinese-Japanese-Korean (CJK) characters in the input string:
- Passing `'cjk'` as the argument will count every CJK character detected as one word irrespective of being separated by whitespace.
- Passing `'auto'` (auto-detect) works similar to `'cjk'` but is more performant if the filter is used on a variable string that may or may not contain CJK chars.
Input
```liquid
{{ "Hello world!" | number_of_words }}
```
Output
```text
2
```
Input
```liquid
{{ "你好hello世界world" | number_of_words }}
```
Output
```text
1
```
Input
```liquid
{{ "你好hello世界world" | number_of_words: "cjk" }}
```
Output
```text
6
```
Input
```liquid
{{ "你好hello世界world" | number_of_words: "auto" }}
```
Output
```text
6
```
+6 -6
View File
@@ -3,17 +3,17 @@ 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.
LiquidJS implements business-logic independent filters that are typically implemented in [shopify/liquid][shopify/liquid]. This section contains the specification and demos for all the filters implemented by LiquidJS.
There's 40+ filters supported by LiquidJS. These filters can be categorized into these groups:
Categories | Filters
--- | ---
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, replace_last,remove, remove_first, remove_last, 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, concat, compact, size
Date | date
Misc | default, json, raw
String | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, replace_last,remove, remove_first, remove_last, truncate, truncatewords, normalize_whitespace, number_of_words, array_to_sentence_string
HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br, xml_escape, cgi_escape, uri_escape, slugify
Array | slice, map, sort, sort_natural, uniq, where, where_exp, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift
Date | date, date_to_xmlschema, date_to_rfc822, date_to_string, date_to_long_string
Misc | default, json, jsonify, inspect, raw, to_integer
[shopify/liquid]: https://github.com/Shopify/liquid
+24
View File
@@ -0,0 +1,24 @@
---
title: pop
---
{% since %}v10.11.0{% endsince %}
Pop an element from the array. It's NON-DESTRUCTIVE, i.e. it does not mutate the array, but rather make a copy and mutate that.
Input
```liquid
{% assign fruits = "apples, oranges, peaches" | split: ", " %}
{% assign everything = fruits | pop %}
{% for item in everything %}
- {{ item }}
{% endfor %}
```
Output
```text
- apples
- oranges
```
+25
View File
@@ -0,0 +1,25 @@
---
title: push
---
{% since %}v10.8.0{% endsince %}
Push an element into array. It's NON-DESTRUCTIVE, i.e. it does not mutate the array, but rather make a copy and mutate that.
Input
```liquid
{% assign fruits = "apples, oranges" | split: ", " %}
{% assign everything = fruits | push: "peaches" %}
{% for item in everything %}
- {{ item }}
{% endfor %}
```
Output
```text
- apples
- oranges
- peaches
```
+24
View File
@@ -0,0 +1,24 @@
---
title: shift
---
{% since %}v10.11.0{% endsince %}
Shift an element from the array. It's NON-DESTRUCTIVE, i.e. it does not mutate the array, but rather make a copy and mutate that.
Input
```liquid
{% assign fruits = "apples, oranges, peaches" | split: ", " %}
{% assign everything = fruits | shift %}
{% for item in everything %}
- {{ item }}
{% endfor %}
```
Output
```text
- oranges
- peaches
```
+61
View File
@@ -0,0 +1,61 @@
---
title: slugify
---
{% since %}v10.13.0{% endsince %}
Convert a string into a lowercase URL "slug". The slugify filter accepts 2 options:
1. `mode: string`. The default is `"default"`. They are as follows (with what they filter):
- `"none"`: no characters
- `"raw"`: spaces
- `"default"`: spaces and non-alphanumeric characters
- `"pretty"`: spaces and non-alphanumeric characters except for `._~!$&'()+,;=@`
- `"ascii"`: spaces, non-alphanumeric, and non-ASCII characters
- `"latin"`: like default, except Latin characters are first transliterated (e.g. àèïòü to aeiou).
2. `case: boolean`. The default is `false`. The original case of slug will be retained if set to `true`.
Input
```liquid
{{ "The _config.yml file" | slugify }}
```
Output
```
the-config-yml-file
```
Input
```liquid
{{ "The _config.yml file" | slugify: "pretty" }}
```
Output
```
the-_config.yml-file
```
Input
```liquid
{{ "The _cönfig.yml file" | slugify: "ascii" }}
```
Output
```
the-c-nfig-yml-file
```
Input
```liquid
{{ "The cönfig.yml file" | slugify: "latin" }}
```
Output
```
the-config-yml-file
```
Input
```liquid
{{ "The cönfig.yml file" | slugify: "latin", true }}
```
Output
```
The-config-yml-file
```
+22
View File
@@ -0,0 +1,22 @@
---
title: sum
---
{% since %}v10.10.0{% endsince %}
Computes the sum of all the numbers in an array.
An optional argument specifies which property of the array's items to sum up.
In this example, assume the object `cart.products` contains an array of all products in the cart of a website.
Assume each cart product has a `qty` property that gives the count of that product instance in the cart.
Using the `sum` filter we can calculate the total number of products in the cart.
Input
```liquid
The cart has {{ order.products | sum: "qty" }} products.
```
Output
```text
The cart has 7 products.
```
+17
View File
@@ -0,0 +1,17 @@
---
title: to_integer
---
{% since %}v10.13.0{% endsince %}
Convert values to number.
Input
```liquid
{{ "123" | to_integer | json }}
```
Output
```text
123
```
+25
View File
@@ -0,0 +1,25 @@
---
title: unshift
---
{% since %}v10.11.0{% endsince %}
Unshift an element to the front of the array. It's NON-DESTRUCTIVE, i.e. it does not mutate the array, but rather make a copy and mutate that.
Input
```liquid
{% assign fruits = "oranges, peaches" | split: ", " %}
{% assign everything = fruits | unshift: "apples" %}
{% for item in everything %}
- {{ item }}
{% endfor %}
```
Output
```text
- apples
- oranges
- peaches
```
+19
View File
@@ -0,0 +1,19 @@
---
title: uri_escape
---
{% since %}v10.13.0{% endsince %}
Percent encodes any special characters in a URI. URI escape normally replaces a space with `%20`. [Reserved characters][reserved] will not be escaped.
Input
```liquid
{{ "https://example.com/?q=foo, \bar?" | uri_escape }}
```
Output
```text
https://example.com/?q=foo,%20%5Cbar?
```
[reserved]: https://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters
+24
View File
@@ -79,4 +79,28 @@ Output
Featured product: Hawaiian print sweater vest
```
Additionally, `property` can be any valid Liquid variable expression as used in output syntax, except that the scope of this expression is within each item. For the following `products` array:
```javascript
const products = [
{ meta: { details: { class: 'A' } }, order: 1 },
{ meta: { details: { class: 'B' } }, order: 2 },
{ meta: { details: { class: 'B' } }, order: 3 }
]
```
Input
```liquid
{% assign selected = products | where: 'meta.details["class"]', "B" %}
{% for item in selected -%}
- {{ item.order }}
{% endfor %}
```
Output
```text
- 2
- 3
```
[truthy]: ../tutorials/truthy-and-falsy.html
+37
View File
@@ -0,0 +1,37 @@
---
title: where_exp
---
{% since %}v10.12.0{% endsince %}
Select all the objects in an array where the expression is true. In this example, assume you have a list of products and you want to show your kitchen products separately. Using `where_exp`, you can create an array containing only the products that have a `"type"` of `"kitchen"`.
Input
```liquid
All products:
{% for product in products %}
- {{ product.title }}
{% endfor %}
{% assign kitchen_products = products | where_exp: "item", "item.type == 'kitchen'" %}
Kitchen products:
{% for product in kitchen_products %}
- {{ product.title }}
{% endfor %}
```
Output
```text
All products:
- Vacuum
- Spatula
- Television
- Garlic press
Kitchen products:
- Spatula
- Garlic press
```
[truthy]: ../tutorials/truthy-and-falsy.html
+17
View File
@@ -0,0 +1,17 @@
---
title: xml_escape
---
{% since %}v10.13.0{% endsince %}
Escape some text for use in XML.
Input
```liquid
{{ "Have you read \'James & the Giant Peach\'?" | xml_escape }}
```
Output
```text
Have you read &#39;James &amp; the Giant Peach&#39;?
```
+4 -4
View File
@@ -1,5 +1,5 @@
layout: index
description: LiquidJS is a simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript.
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
@@ -13,14 +13,14 @@ ul#intro-feature-list
.intro-feature
.intro-feature-icon
i.icon-rocket
h3.intro-feature-title Zero Dependency
p.intro-feature-desc Written with zero npm dependency and no native binding, available in both Node.js and browsers. All of the CMD, ESM and CJS bundles are available on CDN.
h3.intro-feature-title Pure JavaScript
p.intro-feature-desc Written with pure JavaScript with no native bindings, available in both Node.js and browsers. All of the CMD, ESM and CJS bundles are available on CDN.
li.intro-feature-wrap
.intro-feature
.intro-feature-icon
i.icon-shopify
h3.intro-feature-title Shopify Compatible
p.intro-feature-desc All filters and tags from Ruby #[a(href="https://github.com/shopify/liquid") shopify/liquid] are supported by LiquidJS. #[a(href="https://jekyllrb.com/") Jekyll sites], #[a(href="https://pages.github.com/") Github Pages] and #[a(href="https://themes.shopify.com/") Shopify templates] can be ported to Node.js without pain.
p.intro-feature-desc All filters and tags from Ruby #[a(href="https://github.com/shopify/liquid") shopify/liquid] are supported by LiquidJS. #[a(href="https://jekyllrb.com/") Jekyll sites], #[a(href="https://pages.github.com/") GitHub Pages] and #[a(href="https://themes.shopify.com/") Shopify templates] can be ported to Node.js without pain.
li.intro-feature-wrap
.intro-feature
.intro-feature-icon
+1 -1
View File
@@ -1,7 +1,7 @@
{
"short_name": "LiquidJS",
"name": "LiquidJS",
"description": "A simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript.",
"description": "A simple, expressive and safe Shopify / GitHub Pages compatible template engine in pure JavaScript.",
"icons": [
{
"src": "/icon/apple-touch-icon-57x57.png",
+1 -1
View File
@@ -15,7 +15,7 @@ Input
{% when "cookie", "biscuit" %}
This is a cookie
{% else %}
This is not a cake nor a cookie
This is neither a cake nor a cookie
{% endcase %}
```
+1 -1
View File
@@ -3,7 +3,7 @@ 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.
LiquidJS implements business-logic independent tags that are typically implemented in [shopify/liquid][shopify/liquid]. This section contains the specification and demos for all the tags implemented by LiquidJS.
There're a dozen of tags supported by LiquidJS, with all tags in [shopify/liquid][shopify/liquid]. These tags can be categorized into these groups:
@@ -23,7 +23,7 @@ engine.registerFilter('fullURL', function (path) {
})
```
See this JSFiddle: <http://jsfiddle.net/ctj364up/1/>
See this JSFiddle: <https://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.
+2 -2
View File
@@ -6,7 +6,7 @@ In a typical website project, we'll have a directory of view templates and they'
LiquidJS provides multiple ways to cache the parsed templates to improve performance.
## Programmaticly
## Programmatically
The [.parse()][parse], [.parseFile()][parseFile], [.parseFileSync()][parseFileSync] APIs are used to parse templates from string or files. The result template can be then rendered multiple times with different context.
@@ -28,7 +28,7 @@ engine.renderSync(tpl, {name: 'alice'}) // 'Alice'
engine.renderSync(tpl, {name: 'bob'}) // 'Bob'
```
The template string/file is parsed only once and renderd multiple times using different context. Templates for different files can be stored into a `Map` and can be retrieved directly for subsequent renders.
The template string/file is parsed only once and rendered multiple times using different context. Templates for different files can be stored into a `Map` and can be retrieved directly for subsequent renders.
## The `cache` Option
@@ -20,21 +20,11 @@ Getting started and building is described in [CONTRIBUTING.md](https://github.co
## Financial Support
LiquidJS is Open Source and Free. To help it live and thrive, please consider contribute on [Open Collective][oc]. To acknowledge your contribution, your name and avatar will be listed here, on LiquidJS [homepage](https://liquidjs.com/) and on [Github README][liquidjs]. Please provide your Github ID by openning an issue or contacting me through Twitter (harttleharttle), I can help add you into [the contributors table](https://github.com/harttle/liquidjs#contributors-).
### 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>
LiquidJS is Open Source and Free. To help it live and thrive, especially when LiquidJS is benefiting your business, please consider contribute on [GitHub Sponsors](https://github.com/sponsors/harttle) or [Open Collective][oc]. If I'm missing anything, find me via Twitter (harttleharttle) or email (harttleharttle at gmail), to add you into [the contributors table](https://github.com/harttle/liquidjs#contributors-).
[oc]: https://opencollective.com/liquidjs/contribute/backer-10665/checkout
[shopify/liquid]: https://shopify.github.io/liquid/
[caniuse-promises]: http://caniuse.com/#feat=promises
[caniuse-promises]: https://caniuse.com/#feat=promises
[pp]: https://github.com/taylorhakes/promise-polyfill
[tutorial]: https://shopify.github.io/liquid/basics/introduction/
[liquidjs]: https://github.com/harttle/liquidjs
+14 -6
View File
@@ -4,9 +4,9 @@ title: Differences with Shopify/liquid
## 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.
Being compatible with the Ruby version is one of our priorities. Liquid language is originally [implemented in Ruby][ruby-liquid] and used by Shopify and 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:
So "being compatible" means serving 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.
@@ -16,7 +16,7 @@ In the meantime, it's now implemented in JavaScript, that means it has to be mor
* **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`.
* **Additional tags and filters** like `layout` and `json`, `inspect`, `where_exp`, `group_by`, etc., see below for details.
## Differences
@@ -29,11 +29,16 @@ Though we're trying to be compatible with the Ruby version, there are still some
* 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 [date][date] filter supports `%q` for date ordinals like `{{ '2023/02/02' | date: '%d%q of %b'}}` => `02nd of Feb`
* LiquidJS has more tags/filters than [the Liquid language][liquid]:
* LiquidJS-defined tags: [layout][layout], [render][render] and corresponding `block` tag.
* LiquidJS-defined filters: [json][json], group_by, group_by_exp, where_exp, jsonify, inspect, etc.
* Tags/filters that don't depend on Shopify platform are borrowed from [Shopify][shopify-tags].
* Tags/filters that don't depend on Jekyll framework are borrowed from [Jekyll][jekyll-filters].
* Some tags/filters behave differently: [date][date] filter, malformed tags (like duplicated `else`, extra args for `endif`) throw errors in LiquidJS.
[date]: https://liquidjs.com/filters/date.html
[layout]: https://liquidjs.com/tags/layout.html
[layout]: ../tags/layout.html
[render]: ../tags/render.html
[json]: https://liquidjs.com/filters/json.html
[#26]: https://github.com/harttle/liquidjs/pull/26
[#59]: https://github.com/harttle/liquidjs/issues/59
@@ -47,3 +52,6 @@ Though we're trying to be compatible with the Ruby version, there are still some
[plugins]: ./plugins.html#Plugin-List
[ruby-liquid]: https://github.com/Shopify/liquid
[afs]: https://liquidjs.com/tutorials/render-file.html#Abstract-File-System
[liquid]: https://shopify.github.io/liquid/basics/introduction/
[shopify-tags]: https://shopify.dev/docs/api/liquid/tags
[jekyll-filters]: https://jekyllrb.com/docs/liquid/filters/
+57
View File
@@ -0,0 +1,57 @@
---
title: DoS Prevention
---
When the template or data context cannot be trusted, enabling DoS prevention options is crucial. LiquidJS provides 3 options for this purpose: `parseLimit`, `renderLimit`, and `memoryLimit`.
## TL;DR
Setting these options can largely ensure that your LiquidJS instance won't hang for extended periods or consume excessive memory. These limits are based on the available JavaScript APIs, so they are not precise hard limits but thresholds to help prevent your process from failing or hanging.
```typescript
const liquid = new Liquid({
parseLimit: 1e8, // typical size of your templates in each render
renderLimit: 1000, // limit each render to be completed in 1s
memoryLimit: 1e9, // memory available for LiquidJS (1e9 for 1GB)
})
```
When a `parse()` or `render()` cannot be completed within given resource, it throws.
## parseLimit
[parseLimit][parseLimit] restricts the size (character length) of templates parsed in each `.parse()` call, including referenced partials and layouts. Since LiquidJS parses template strings in near O(n) time, limiting total template length is usually sufficient.
A typical PC handles `1e8` (100M) characters without issues.
## renderLimit
Restricting template size alone is insufficient because dynamic loops with large counts can occur in render time. [renderLimit][renderLimit] mitigates this by limiting the time consumed by each `render()` call.
```liquid
{%- for i in (1..10000000) -%}
order: {{i}}
{%- endfor -%}
```
Render time is checked on a per-template basis (before rendering each template). In the above example, there are 2 templates in the loop: `order: ` and `{{i}}`, render time will be checked 10000000x2 times.
For time-consuming tags and filters within a single template, the process can still hang. For fully controlled rendering, consider using a process manager like [paralleljs][paralleljs].
## memoryLimit
Even with small number of templates and iterations, memory usage can grow exponentially. In the following example, memory doubles with each iteration:
```liquid
{% assign array = "1,2,3" | split: "," %}
{% for i in (1..32) %}
{% assign array = array | concat: array %}
{% endfor %}
```
[memoryLimit][memoryLimit] restricts memory-sensitive filters to prevent excessive memory allocation. As [JavaScript uses GC to manage memory](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management), `memoryLimit` limits only the total number of objects allocated by memory sensitive filters in LiquidJS thus may not reflect the actual memory footprint.
[paralleljs]: https://www.npmjs.com/package/paralleljs
[parseLimit]: /api/interfaces/LiquidOptions.html#parseLimit
[renderLimit]: /api/interfaces/LiquidOptions.html#renderLimit
[memoryLimit]: /api/interfaces/LiquidOptions.html#memoryLimit
+201
View File
@@ -0,0 +1,201 @@
---
title: Liquid Drops
---
LiquidJS also provides a mechanism similar to [Shopify Drops][shopify-drops], allowing template authors to incorporate custom functionality in resolving variable values.
{% note info Drop for JavaScript %}
<em>Drop</em> interface is implemented differently in LiquidJS compared to built-in filters and other template functionalities. Since LiquidJS runs in JavaScript, custom Drops need to be reimplemented in JavaScript anyway. There's no compatibility between JavaScript classes and Ruby classes.
{% endnote %}
## Basic Usage
```javascript
import { Liquid, Drop } from 'liquidjs'
class SettingsDrop extends Drop {
constructor() {
super()
this.foo = 'FOO'
}
bar() {
return 'BAR'
}
}
const engine = new Liquid()
const template = `foo: {{settings.foo}}, bar: {{settings.bar}}`
const context = { settings: new SettingsDrop() }
// Outputs: "foo: FOO, bar: BAR"
engine.parseAndRender(template, context).then(html => console.log(html))
```
[Runkit link](https://runkit.com/embed/2is7di4mc7kk)
As shown above, besides reading properties from context scopes, you can also call methods. You only need to create a custom class inherited from `Drop`.
{% note tip Async Methods %}
LiquidJS is fully async-friendly. You can safely return a Promise in your Drop methods or define your methods in Drop as `async`.
{% endnote %}
## liquidMethodMissing
For cases when there isn't a fixed set of properties, you can leverage `liquidMethodMissing` to dynamically resolve the value of a variable name.
```javascript
import { Liquid, Drop } from 'liquidjs'
class SettingsDrop extends Drop {
liquidMethodMissing(key) {
return key.toUpperCase()
}
}
const engine = new Liquid()
// Outputs: "COO"
engine.parseAndRender("{{settings.coo}}", { settings: new SettingsDrop() })
.then(html => console.log(html))
```
`liquidMethodMissing` supports Promise, meaning you can make async calls within it. A more useful case can be fetching the value dynamically from the database. By using Drops, you can avoid hardcoding each property into the context. For example:
```javascript
import { Liquid, Drop } from 'liquidjs'
class DBDrop extends Drop {
async liquidMethodMissing(key) {
const record = await db.getRecordByKey(key)
return record.value
}
}
const engine = new Liquid()
const context = { db: new DBDrop() }
engine.parseAndRender("{{db.coo}}", context).then(html => console.log(html))
```
## valueOf
Drops can implement a `valueOf()` method, the return value of which can be used to replace itself in the output. For example:
```javascript
import { Liquid, Drop } from 'liquidjs'
class ColorDrop extends Drop {
valueOf() {
return 'red'
}
}
const engine = new Liquid()
const context = { color: new ColorDrop() }
// Outputs: "red"
engine.parseAndRender("{{color}}", context).then(html => console.log(html))
```
## toLiquid
`toLiquid()` is not a method of `Drop`, but it can be used to return a `Drop`. In cases where you have a fixed structure in the `context` that cannot change its values, you can implement `toLiquid()` to let LiquidJS use the returned value instead of itself to render the templates.
```javascript
import { Liquid, Drop } from 'liquidjs'
const context = {
person: {
firstName: "Jun",
lastName: "Yang",
name: "Jun Yang",
toLiquid: () => ({
firstName: this.firstName,
lastName: this.lastName,
// use a different `name`
name: "Yang, Jun"
})
}
}
const engine = new Liquid()
// Outputs: "Yang, Jun"
engine.parseAndRender("{{person.name}}", context).then(html => console.log(html))
```
Of course, you can also return a `PersonDrop` instance in the `toLiquid()` method and implement this functionality within `PersonDrop`:
```javascript
import { Liquid, Drop } from 'liquidjs'
class PersonDrop extends Drop {
constructor(person) {
super()
this.person = person
}
name() {
return this.person.lastName + ", " + this.person.firstName
}
}
const context = {
person: {
firstName: "Jun",
lastName: "Yang",
name: "Jun Yang",
toLiquid: function () { return new PersonDrop(this) }
}
}
const engine = new Liquid()
// Outputs: "Yang, Jun"
engine.parseAndRender("{{person.name}}", context).then(html => console.log(html))
```
{% note info <code>toLiquid()</code> vs. <code>valueOf()</code> Difference %}
<ul>
<li><code>valueOf()</code> is typically used to define how the current variable should be rendered, while <code>toLiquid()</code> is often used to convert an object into a Drop or another scope provided to the template.</li>
<li><code>valueOf()</code> is a method exclusive to Drops; whereas <code>toLiquid()</code> can be used on any scope object.</li>
<li><code>valueOf()</code> is called when the variable itself is about to be rendered, replacing itself; whereas <code>toLiquid()</code> is called when its properties are about to be read.</li>
</ul>
{% endnote %}
## Special Drops
LiquidJS itself implements several built-in drops to facilitate template writing. This part is compatible with Shopify Liquid, as we need templates to be portable.
### blank
Useful to check whether a string variable is `false`, `null`, `undefined`, an empty string, or a string containing only blank characters.
```liquid
{% unless author == blank %}
{{author}}
{% endif %}
```
### empty
Useful to check if an array, string, or object is empty.
```liquid
{% if authors == empty %}
Author list is empty
{% endif %}
```
{% note info <code>empty</code> implementation %}
For arrays and strings, LiquidJS checks their `.length` property. For objects, LiquidJS calls `Object.keys()` to check whether they have keys.
{% endnote %}
### nil
`nil` Drop is used to check whether a variable is not defined or defined as `null` or `undefined`, essentially equivalent to JavaScript `== null` check.
```liquid
{% if nonexistent == nil %}
null variable
{% endif %}
```
### Other Drops
There are still several Drops for specific tags, like `forloop`, `tablerowloop`, `block`, which are covered by respective tag documents.
[shopify-drops]: https://github.com/Shopify/liquid/wiki/Introduction-to-Drops
+76
View File
@@ -0,0 +1,76 @@
---
title: Escaping
---
Escaping is important in all languages, including LiquidJS. While escaping has 2 different meanings for a template engine:
1. Escaping for the output, i.e. HTML escape. Used to escape HTML special characters so the output will not break HTML structures, aka HTML safe.
2. Escaping for the language itself, i.e. Liquid escape. Used to output strings that's considered special in Liquid language. This will be useful when you're writing an article in Liquid template to introduce Liquid language.
## HTML Escape
By default output is not escaped. While you can use [escape][escape] filter for this:
Input
```liquid
{{ "1 < 2" | escape }}
```
Output
```text
1 &lt; 2
```
There's also [escape_once][escape_once], [newline_to_br][newline_to_br], [strip_html][strip_html] filters for you to fine tune your output.
In cases where variables are mostly not trusted, [outputEscape][outputEscape] can be set to `"escape"` to apply escape by default. In this case, when you need some output not to be escaped, [raw][raw] filter can be used:
Input
```liquid
{{ "1 < 2" }}
{{ "<button>OK</button>" | raw }}
```
Output
```text
1 &lt; 2
<button>OK</button>
```
## Liquid Escape
To disable Liquid language and output strings like `{{` and `{%`, the [raw][raw] tag can be used.
Input
```liquid
{% raw %}
In LiquidJS, {{ this | escape }} will be HTML-escaped, but
{{{ that }}} will not.
{% endraw %}
```
Output
```text
In LiquidJS, {{ this | escape }} will be HTML-escaped, but
{{{ that }}} will not.
```
Within strings literals in LiquidJS template, `\` can be used to escape special characters in string syntax. For example:
Input
```liquid
{{ "\"" }}
```
Output
```liquid
"
```
[outputEscape]: ./options.html#outputEscape
[escape]: ../filters/escape.html
[raw]: ../filters/raw.html
[escape_once]: ../filters/escape.html
[strip_html]: ../filters/strip_html.html
[newline_to_br]: ../filters/newline_to_br.html
[raw]: ../tags/raw.html
+1 -1
View File
@@ -3,7 +3,7 @@ title: The Liquid Template Language
describe: A short introduction to the Liquid template language and some simple demos.
---
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 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:
+1 -1
View File
@@ -26,4 +26,4 @@ LiquidJS 9 has some fundamental improvements, including bugfixes, new features a
* LiquidJS no longer has a default export, use `import {Liquid} from 'liquidjs'` instead. The `window.Liquid` for the UMD bundle is also changed to `window.liquidjs.Liquid`;
* The duplicate static method `Liquid.evalValue` is removed, use the instance method `liquid.evalValue` instead;
* Shipped to Node.js 8, the CJS bundle (main entry in Node.js) nolonger supports Node.js &leq; 6. ESM (dist/liquid.node.esm.js) and UMD (dist/liquid.browser.umd.js, dist/liquid.browser.min.js) bundles are not affected.
* Shipped to Node.js 8, the CJS bundle (main entry in Node.js) no longer supports Node.js &leq; 6. ESM (dist/liquid.node.esm.js) and UMD (dist/liquid.browser.umd.js, dist/liquid.browser.min.js) bundles are not affected.
+13 -3
View File
@@ -98,10 +98,18 @@ Before 2.0.1, <code>extname</code> is set to `.liquid` by default. To change tha
## jsTruthy
**jsTruthy** is used to use standard Javascript truthiness rather than the Shopify.
**jsTruthy** is used to use standard JavaScript truthiness rather than the Shopify.
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.
## outputEscape
[outputEscape][outputEscape] can be used to automatically escape output strings. It can be one of `"escape"`, `"json"`, or `(val: unknown) => string`, defaults to `undefined`.
- For untrusted output variables, set `outputEscape: "escape"` makes them be HTML escaped by default. You'll need [raw][raw] filter for direct output.
- `"json"` is useful when you're using LiquidJS to create valid JSON files.
- It can even be a function which allows you to control what variables are output throughout LiquidJS. Please note the input can be any type other than string, e.g. an filter returned an non-string value.
## 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.
@@ -132,8 +140,8 @@ it defaults to false. For example, when set to true, a blank string would evalu
**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 `true`.
{% note info Non-existent Tags %}
Non-existent tags always throw errors during parsing and this behavior can not be customized.
{% note info Nonexistent Tags %}
Nonexistent tags always throw errors during parsing and this behavior cannot be customized.
{% endnote %}
## Parameter Order
@@ -151,3 +159,5 @@ Parameter orders are ignored by default, for ea `{% for i in (1..8) reversed lim
[wc]: ./whitespace-control.html
[intro]: ./intro-to-liquid.html
[jekyllInclude]: /api/interfaces/LiquidOptions.html#jekyllInclude
[raw]: ../filters/raw.html
[outputEscape]: /api/interfaces/LiquidOptions.html#outputEscape
+4 -4
View File
@@ -23,7 +23,7 @@ engine.registerTag('random', {
})
```
Here's a JSFiddle version: <http://jsfiddle.net/ctj364up/2/>
Here's a JSFiddle version: <https://jsfiddle.net/ctj364up/2/>
## Parse Parameters as Values
@@ -58,9 +58,9 @@ engine.registerTag('random', {
})
```
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/>
Calling this tag in scope `{ bar: "bar", obj: { coo: "coo" } }` yields exactly the same result as the first example. See this JSFiddle: <https://jsfiddle.net/ctj364up/3/>
{% note info Async ans Promises %}
{% note info Async and 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 %}
@@ -92,7 +92,7 @@ engine.registerTag('random', {
})
```
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/>
Rendering `{% raw %}{% random from:2, to:max %}{% endraw %}` in scope `{ max: 10 }` will generate a random number in the range [2, 10]. See this JSFiddle: <https://jsfiddle.net/ctj364up/4/>
[register-tags]: /tutorials/register-filters-tags.html
+3 -2
View File
@@ -36,7 +36,7 @@ engine
## Plugin List
Since this library excludes certain features that are available on the Shopify platform but not on the [Shopify/liquid](https://github.com/Shopify/liquid/) repo, see <https://github.com/harttle/liquidjs#differences-and-limitations>.
Since this library excludes certain features that are available on the Shopify platform but not on the [Shopify/liquid](https://github.com/Shopify/liquid/) repo, see [Differences with Shopify/liquid][differences].
Here's a list of plugins that backfill those features. Feel free to add yours, this file is publicly editable.
@@ -44,4 +44,5 @@ Here's a list of plugins that backfill those features. Feel free to add yours, t
* Color Filters: https://github.com/harttle/liquidjs-color-filters
[liquid]: /api/classes/Liquid.html
[register]: /harttle/liquidjs/wiki/Register-Filters-Tags
[register]: /harttle/liquidjs/wiki/Register-Filters-Tags
[differences]: /tutorials/differences.html
+21 -4
View File
@@ -52,23 +52,23 @@ var engine = new Liquid({
{% note tip Relative Paths %}Relative paths in <code>root</code> will be resolved against <code>cwd()</code>.{% endnote %}
When `{% raw %}{% render "foo" %}{% endraw %}` is renderd or `liquid.renderFile('foo')` is called, the following files will be looked up and the first existing file will be used:
When `{% raw %}{% render "foo" %}{% endraw %}` is rendered or `liquid.renderFile('foo')` is called, the following files will be looked up and the first existing file will be used:
- `cwd()`/views/foo.liquid
- `cwd()`/views/partials/foo.liquid
If none of the above files exists, an `ENOENT` error will be throwed. Here's a demo for Node.js: [demo/nodejs](https://github.com/harttle/liquidjs/tree/master/demo/nodejs).
If none of the above files exists, an `ENOENT` error will be thrown. Here's a demo for Node.js: [demo/nodejs](https://github.com/harttle/liquidjs/tree/master/demo/nodejs).
When LiquidJS is used in browser, say current location is <https://example.com/bar/index.html>, only the first `root` will be used and the file to be fetched is:
- <https://example.com/bar/foo.liquid>
If fetch fails, a 404/500 error or network failures for example, an `ENOENT` error will be throwed.
If fetch fails, a 404/500 error or network failures for example, an `ENOENT` error will be thrown.
Here's a demo for browsers: [demo/browser](https://github.com/harttle/liquidjs/tree/master/demo/browser).
## Abstract File System
LiquidJS defines an abstract file system interface in [src/fs/fs.ts][ifs] and the default implementation is [src/fs/fs-impl.ts][fs-node] for Node.js and [src/build/fs-impl-browser.ts][fs-browser] for the browser bundle.
LiquidJS defines an [abstract file system interface][ifs] and the default implementation is [src/fs/fs-impl.ts][fs-node] for Node.js and [src/build/fs-impl-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:
@@ -100,6 +100,23 @@ 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 %}
## In-memory Template
To facilitate rendering w/o files, there's a `templates` option to specify a mapping of filenames and their content. LiquidJS will read templates from the mapping.
```typescript
const engine = new Liquid({
templates: {
'views/entry': 'header {% include "../partials/footer" %}',
'partials/footer': 'footer'
}
})
engine.renderFileSync('views/entry'))
// Result: 'header footer'
```
Note that file system options like `root`, `layouts`, `partials`, `relativeReference` will be ignored when `templates` is specified.
[fs]: /api/interfaces/LiquidOptions.html#fs
[ifs]: /api/interfaces/FS.html
[fs-node]: https://github.com/harttle/liquidjs/blob/master/src/fs/fs-impl.ts
+5 -5
View File
@@ -24,8 +24,8 @@ Expected output:
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.
- `tagToken` is current token `{%raw%}{% wrap %}{%endraw%}`, and
- `remainTokens` is an array of all tokens following `{%raw%}{% wrap %}{%endraw%}` 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`.
@@ -57,7 +57,7 @@ engine.registerTag('wrap', {
})
```
`.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/>
`.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: <https://jsfiddle.net/por0zcn1/3/>
## Using ParseStream
@@ -75,7 +75,7 @@ parse(tagToken, remainTokens) {
}
```
Here's a JSFiddle version: <http://jsfiddle.net/por0zcn1/4/>. For simplicity, the following examples are implemented using `ParseStream`.
Here's a JSFiddle version: <https://jsfiddle.net/por0zcn1/4/>. For simplicity, the following examples are implemented using `ParseStream`.
## Manipulate the Context
@@ -123,7 +123,7 @@ engine.registerTag('repeat', {
})
```
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/>
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: <https://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.
+2 -2
View File
@@ -49,7 +49,7 @@ Pre-built UMD bundles are also available:
{% note info Working Demo %} Here's a living demo on jsFiddle: <a href="https://jsfiddle.net/pd4jhzLs/1/" target="_blank">jsfiddle.net/pd4jhzLs/1/</a>, and the source code is also available in <a href="https://github.com/harttle/liquidjs/blob/master/demo/browser/" target="_blank">liquidjs/demo/browser/</a>.{% endnote %}
{% note warn Compatibility %} You may need a <a href="https://github.com/taylorhakes/promise-polyfill" target="_blank">Promise polyfill</a> for legacy browsers like IE and Android UC, see <a href="http://caniuse.com/#feat=promises" target="_blank">caniuse statistics</a>. {% endnote %}
{% note warn Compatibility %} You may need a <a href="https://github.com/taylorhakes/promise-polyfill" target="_blank">Promise polyfill</a> for legacy browsers like IE and Android UC, see <a href="https://caniuse.com/#feat=promises" target="_blank">caniuse statistics</a>. {% endnote %}
## LiquidJS in CLI
@@ -100,4 +100,4 @@ Most of the [options available through the JavaScript API][options] are also ava
A ReactJS demo is also added by [@stevenanthonyrevo](https://github.com/stevenanthonyrevo), see [liquidjs/demo/reactjs/](https://github.com/harttle/liquidjs/blob/master/demo/reactjs/).
[intro]: ./intro-to-liquid.html
[options]: ./options.md
[options]: ./options.html
+1 -1
View File
@@ -60,7 +60,7 @@ var engine = new Liquid({
```
[cache]: /api/interfaces/LiquidOptions.html#cache
[express-views]: http://expressjs.com/en/guide/using-template-engines.html
[express-views]: https://expressjs.com/en/guide/using-template-engines.html
[parseFile]: /api/classes/Liquid.html#parseFile
[parseFileSync]: /api/classes/Liquid.html#parseFileSync
[layout]: https://help.shopify.com/en/themes/liquid/tags/theme-tags#layout
@@ -0,0 +1,27 @@
---
title: array_to_sentence_string
---
{% since %}v10.13.0{% endsince %}
把数组转化为句子,用于做标签列表。有一个可选的连接词参数。
输入
```liquid
{{ "foo,bar,baz" | split: "," | array_to_sentence_string }}
```
输出
```text
foo, bar, and baz
```
输入
```liquid
{{ "foo,bar,baz" | split: "," | array_to_sentence_string: "or" }}
```
输出
```text
foo, bar, or baz
```
+17
View File
@@ -0,0 +1,17 @@
---
title: cgi_escape
---
{% since %}v10.13.0{% endsince %}
把字符串 CGI 转义,用于 URL。用对应的 `%XX` 替换特殊字符,空格会被转义为 `+` 号。
输入
```liquid
{{ "foo, bar; baz?" | cgi_escape }}
```
输出
```text
foo%2C+bar%3B+baz%3F
```
+8
View File
@@ -6,6 +6,14 @@ title: date
把时间戳转换为字符串。LiquidJS 尝试跟 Shopify/Liquid 保持一致,它用的是 Ruby 核心的 [Time#strftime(string)](http://www.ruby-doc.org/core/Time.html#method-i-strftime)。此外 LiquidJS 会先通过 [new Date()][newDate] 尝试把输入转换为 Date 对象。
但 LiquidJS 支持的格式与 [Ruby 的 flag](https://ruby-doc.org/core/strftime_formatting_rdoc.html) 有些不同:
* `%Z`(自 v10.11.1 起支持)只有在传入了时区时才起作用(可以通过 `LiquidOption` 传入,也可以在创建日期时单独传入,见下文)。如果传入的时区是个数字,那么它的表现将会与 `%z` 相同。如果没有传入时区,将会返回 [运行时默认时区](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions#timezone)。
* LiquidJS 提供额外的 `%q` 用来处理序数:`{{ '2023/02/02' | date: '%d%q of %b'}}` => `02nd of Feb`
* 日期字面量会通过 [new Date()][jsDate] 转化为 `Date` 对象,这意味着字面量默认使用运行时默认时区。
* 格式字参数是可选的:
* 如果不传,默认为 `%A, %B %-e, %Y at %-l:%M %P %z`
* 上述默认值可以通过 [`dateFormat`](/api/interfaces/LiquidOptions.html#dateFormat) 参数覆盖。
输入
```liquid
{{ article.published_at | date: "%a, %b %d, %y" }}
@@ -0,0 +1,31 @@
---
title: date_to_long_string
---
{% since %}v10.13.0{% endsince %}
把日期转换为长格式(只支持 US/UK 两种),与 Jekyll 的 `date_to_long_string` 过滤器一样。
输入
```liquid
{{ site.time | date_to_long_string }}
```
输出
```text
07 November 2008
```
输入
```liquid
{{ site.time | date_to_long_string: "ordinal" }}
```
输出
```text
7th November 2008
```
注意 JavaScript `Date` 没有时区信息,详情请参考 [date][date] 过滤器。
[date]: ./date.html
@@ -0,0 +1,20 @@
---
title: date_to_rfc822
---
{% since %}v10.13.0{% endsince %}
把日期转换为 RFC-822 格式用于 RSS feed,与 Jekyll 的 `date_to_rfc822` 过滤器一样。
输入
```liquid
{{ site.time | date_to_rfc822 }}
```
输入
```text
Mon, 07 Nov 2008 13:07:54 -0800
```
注意 JavaScript `Date` 没有时区信息,详情请参考 [date][date] 过滤器。
[date]: ./date.html
@@ -0,0 +1,30 @@
---
title: date_to_string
---
{% since %}v10.13.0{% endsince %}
把日期转换为短格式(只支持 US/UK 两种),与 Jekyll 的 `date_to_string` 过滤器一样。
输入
```liquid
{{ site.time | date_to_string }}
```
输出
```text
07 Nov 2008
```
输入
```liquid
{{ site.time | date_to_string: "ordinal", "US" }}
```
输出
```text
Nov 7th, 2008
```
注意 JavaScript `Date` 没有时区信息,详情请参考 [date][date] 过滤器。
[date]: ./date.html
@@ -0,0 +1,20 @@
---
title: date_to_xmlschema
---
{% since %}v10.13.0{% endsince %}
把日期转换为 XML Schema (ISO 8601) 格式,与 Jekyll 的 `date_to_xmlschema` 过滤器一样。
输入
```liquid
{{ site.time | date_to_xmlschema }}
```
输出
```text
2008-11-07T13:07:54-08:00
```
注意 JavaScript `Date` 没有时区信息,详情请参考 [date][date] 过滤器。
[date]: ./date.html
+25
View File
@@ -0,0 +1,25 @@
---
title: find
---
{% since %}v10.11.0{% endsince %}
在数组中找到给定的属性为给定的值的第一个元素并返回;如果没有这样的元素则返回 `nil`。对于 `members` 数组:
```javascript
const members = [
{ graduation_year: 2013, name: 'Jay' },
{ graduation_year: 2014, name: 'John' },
{ graduation_year: 2014, name: 'Jack' }
]
```
输入
```liquid
{{ members | find: "graduation_year", 2014 | json }}
```
输出
```text
{"graduation_year":2014,"name":"John"}
```
+25
View File
@@ -0,0 +1,25 @@
---
title: find_exp
---
{% since %}v10.11.0{% endsince %}
找到数组中给定的表达式值为 `true` 的第一个元素,如果没有这样的元素则返回 `nil`。对于下面的 `members` 数组:
```javascript
const members = [
{ graduation_year: 2013, name: 'Jay' },
{ graduation_year: 2014, name: 'John' },
{ graduation_year: 2014, name: 'Jack' }
]
```
输入
```liquid
{{ members | find_exp: "item", "item.graduation_year == 2014" | json }}
```
输出
```text
{"graduation_year":2014,"name":"John"}
```

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