mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-17 05:10:40 -07:00
feat: add find_index, has, and reject filters (#799)
* feat: add find_index, has, and reject filters * Minor tweaks * Change semantics of jekyllStyle, add more tests * Some docs improvements
This commit is contained in:
+70
-18
@@ -117,7 +117,17 @@ export function slice<T> (this: FilterImpl, v: T[] | string, begin: number, leng
|
||||
return v.slice(begin, begin + length)
|
||||
}
|
||||
|
||||
export function * where<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): IterableIterator<unknown> {
|
||||
function expectedMatcher (this: FilterImpl, expected: any): (v: any) => boolean {
|
||||
if (this.context.opts.jekyllWhere) {
|
||||
return (v: any) => EmptyDrop.is(expected) ? equals(v, expected) : (isArray(v) ? arrayIncludes(v, expected) : equals(v, expected))
|
||||
} else if (expected === undefined) {
|
||||
return (v: any) => isTruthy(v, this.context)
|
||||
} else {
|
||||
return (v: any) => equals(v, expected)
|
||||
}
|
||||
}
|
||||
|
||||
function * filter<T extends object> (this: FilterImpl, include: boolean, arr: T[], property: string, expected: any): IterableIterator<unknown> {
|
||||
const values: unknown[] = []
|
||||
arr = toArray(arr)
|
||||
this.context.memoryLimit.use(arr.length)
|
||||
@@ -125,16 +135,11 @@ export function * where<T extends object> (this: FilterImpl, arr: T[], property:
|
||||
for (const item of arr) {
|
||||
values.push(yield evalToken(token, this.context.spawn(item)))
|
||||
}
|
||||
const matcher = this.context.opts.jekyllWhere
|
||||
? (v: any) => EmptyDrop.is(expected) ? equals(v, expected) : (isArray(v) ? arrayIncludes(v, expected) : equals(v, expected))
|
||||
: (v: any) => equals(v, expected)
|
||||
return arr.filter((_, i) => {
|
||||
if (expected === undefined) return isTruthy(values[i], this.context)
|
||||
return matcher(values[i])
|
||||
})
|
||||
const matcher = expectedMatcher.call(this, expected)
|
||||
return arr.filter((_, i) => matcher(values[i]) === include)
|
||||
}
|
||||
|
||||
export function * where_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
function * filter_exp<T extends object> (this: FilterImpl, include: boolean, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
const filtered: unknown[] = []
|
||||
const keyTemplate = new Value(stringify(exp), this.liquid)
|
||||
const array = toArray(arr)
|
||||
@@ -143,11 +148,27 @@ export function * where_exp<T extends object> (this: FilterImpl, arr: T[], itemN
|
||||
this.context.push({ [itemName]: item })
|
||||
const value = yield keyTemplate.value(this.context)
|
||||
this.context.pop()
|
||||
if (value) filtered.push(item)
|
||||
if (value === include) filtered.push(item)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
export function * where<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): IterableIterator<unknown> {
|
||||
return yield * filter.call(this, true, arr, property, expected)
|
||||
}
|
||||
|
||||
export function * reject<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): IterableIterator<unknown> {
|
||||
return yield * filter.call(this, false, arr, property, expected)
|
||||
}
|
||||
|
||||
export function * where_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
return yield * filter_exp.call(this, true, arr, itemName, exp)
|
||||
}
|
||||
|
||||
export function * reject_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
return yield * filter_exp.call(this, false, arr, itemName, exp)
|
||||
}
|
||||
|
||||
export function * group_by<T extends object> (this: FilterImpl, arr: T[], property: string): IterableIterator<unknown> {
|
||||
const map = new Map()
|
||||
arr = toEnumerable(arr)
|
||||
@@ -176,26 +197,57 @@ export function * group_by_exp<T extends object> (this: FilterImpl, arr: T[], it
|
||||
return [...map.entries()].map(([name, items]) => ({ name, items }))
|
||||
}
|
||||
|
||||
export function * find<T extends object> (this: FilterImpl, arr: T[], property: string, expected: string): IterableIterator<unknown> {
|
||||
function * search<T extends object> (this: FilterImpl, arr: T[], property: string, expected: string): IterableIterator<unknown> {
|
||||
const token = new Tokenizer(stringify(property)).readScopeValue()
|
||||
const array = toArray(arr)
|
||||
for (const item of array) {
|
||||
const value = yield evalToken(token, this.context.spawn(item))
|
||||
if (equals(value, expected)) return item
|
||||
const matcher = expectedMatcher.call(this, expected)
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
const value = yield evalToken(token, this.context.spawn(array[index]))
|
||||
if (matcher(value)) return [index, array[index]]
|
||||
}
|
||||
}
|
||||
|
||||
export function * find_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
function * search_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
const predicate = new Value(stringify(exp), this.liquid)
|
||||
const array = toArray(arr)
|
||||
for (const item of array) {
|
||||
this.context.push({ [itemName]: item })
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
this.context.push({ [itemName]: array[index] })
|
||||
const value = yield predicate.value(this.context)
|
||||
this.context.pop()
|
||||
if (value) return item
|
||||
if (value) return [index, array[index]]
|
||||
}
|
||||
}
|
||||
|
||||
export function * has<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): IterableIterator<unknown> {
|
||||
const result = yield * search.call(this, arr, property, expected)
|
||||
return !!result
|
||||
}
|
||||
|
||||
export function * has_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
const result = yield * search_exp.call(this, arr, itemName, exp)
|
||||
return !!result
|
||||
}
|
||||
|
||||
export function * find_index<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): IterableIterator<unknown> {
|
||||
const result = yield * search.call(this, arr, property, expected)
|
||||
return result ? result[0] : undefined
|
||||
}
|
||||
|
||||
export function * find_index_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
const result = yield * search_exp.call(this, arr, itemName, exp)
|
||||
return result ? result[0] : undefined
|
||||
}
|
||||
|
||||
export function * find<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): IterableIterator<unknown> {
|
||||
const result = yield * search.call(this, arr, property, expected)
|
||||
return result ? result[1] : undefined
|
||||
}
|
||||
|
||||
export function * find_exp<T extends object> (this: FilterImpl, arr: T[], itemName: string, exp: string): IterableIterator<unknown> {
|
||||
const result = yield * search_exp.call(this, arr, itemName, exp)
|
||||
return result ? result[1] : undefined
|
||||
}
|
||||
|
||||
export function uniq<T> (this: FilterImpl, arr: T[]): T[] {
|
||||
arr = toArray(arr)
|
||||
this.context.memoryLimit.use(arr.length)
|
||||
|
||||
Reference in New Issue
Block a user