From 8c7cef9f95cda765164ada8d58af7d402b3d3143 Mon Sep 17 00:00:00 2001 From: Yang Jun Date: Sun, 28 Apr 2024 22:48:29 +0800 Subject: [PATCH] feat: introduce where_exp filter from Jekyll --- docs/source/_data/sidebar.yml | 1 + docs/source/filters/overview.md | 2 +- docs/source/filters/where_exp.md | 37 ++++++++++++++++++++++++++ docs/source/zh-cn/filters/overview.md | 2 +- docs/source/zh-cn/filters/where_exp.md | 37 ++++++++++++++++++++++++++ src/filters/array.ts | 10 +++++++ test/integration/filters/array.spec.ts | 22 +++++++++++++++ 7 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 docs/source/filters/where_exp.md create mode 100644 docs/source/zh-cn/filters/where_exp.md diff --git a/docs/source/_data/sidebar.yml b/docs/source/_data/sidebar.yml index 959ea56368..c609bb196a 100644 --- a/docs/source/_data/sidebar.yml +++ b/docs/source/_data/sidebar.yml @@ -88,6 +88,7 @@ filters: url_decode: url_decode.html url_encode: url_encode.html where: where.html + where_exp: where_exp.html tags: overview: overview.html diff --git a/docs/source/filters/overview.md b/docs/source/filters/overview.md index 0ed7480c2a..03559308b6 100644 --- a/docs/source/filters/overview.md +++ b/docs/source/filters/overview.md @@ -12,7 +12,7 @@ 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, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift +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 Misc | default, json, raw diff --git a/docs/source/filters/where_exp.md b/docs/source/filters/where_exp.md new file mode 100644 index 0000000000..92e09c374c --- /dev/null +++ b/docs/source/filters/where_exp.md @@ -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 diff --git a/docs/source/zh-cn/filters/overview.md b/docs/source/zh-cn/filters/overview.md index 5938d40153..8effee0070 100644 --- a/docs/source/zh-cn/filters/overview.md +++ b/docs/source/zh-cn/filters/overview.md @@ -12,7 +12,7 @@ LiquidJS 共支持 40+ 个过滤器,可以分为如下几类: 数学 | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most 字符串 | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, replace_last, remove, remove_first, remove_last, truncate, truncatewords HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br -数组 | slice, map, sort, sort_natural, uniq, where, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift +数组 | 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 其他 | default, json diff --git a/docs/source/zh-cn/filters/where_exp.md b/docs/source/zh-cn/filters/where_exp.md new file mode 100644 index 0000000000..f283689504 --- /dev/null +++ b/docs/source/zh-cn/filters/where_exp.md @@ -0,0 +1,37 @@ +--- +title: where_exp +--- + +{% since %}v10.12.0{% endsince %} + +从数组中选择所有表达式值为真的对象。下面的例子中,假设你要从产品列表中筛选出来厨房用品。利用 `where_exp` 可以创建一个只包含 `"type"` 为 `"kitchen"` 的列表。 + +输入 +```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 %} +``` + +输出 +```text +All products: +- Vacuum +- Spatula +- Television +- Garlic press + +Kitchen products: +- Spatula +- Garlic press +``` + +[truthy]: ../tutorials/truthy-and-falsy.html diff --git a/src/filters/array.ts b/src/filters/array.ts index 9e94bf5587..e0100f4c62 100644 --- a/src/filters/array.ts +++ b/src/filters/array.ts @@ -102,6 +102,16 @@ export function * where (this: FilterImpl, arr: T[], property: }) } +export function * where_exp (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator { + const filtered: unknown[] = [] + const keyTemplate = new Value(stringify(exp), this.liquid) + for (const item of toArray(arr)) { + const value = yield keyTemplate.value(new Context({ [itemName]: item })) + if (value) filtered.push(item) + } + return filtered +} + export function * group_by (arr: T[], property: string): IterableIterator { const map = new Map() arr = toArray(arr) diff --git a/test/integration/filters/array.spec.ts b/test/integration/filters/array.spec.ts index a5901aaf6a..0742411593 100644 --- a/test/integration/filters/array.spec.ts +++ b/test/integration/filters/array.spec.ts @@ -476,6 +476,28 @@ describe('filters/array', function () { `) }) }) + describe('where_exp', function () { + const products = [ + { title: 'Vacuum', type: 'living room' }, + { title: 'Spatula', type: 'kitchen' }, + { title: 'Television', type: 'living room' }, + { title: 'Garlic press', type: 'kitchen' }, + { title: 'Coffee mug', available: true }, + { title: 'Limited edition sneakers', available: false }, + { title: 'Boring sneakers', available: true } + ] + it('should support filter by exp', function () { + return test(`{% assign kitchen_products = products | where_exp: "item", "item.type == 'kitchen'" %} + Kitchen products: + {% for product in kitchen_products -%} + - {{ product.title }} + {% endfor %}`, { products }, ` + Kitchen products: + - Spatula + - Garlic press + `) + }) + }) describe('group_by', function () { const members = [ { graduation_year: 2003, name: 'Jay' },