fix: coerce to Array in map and where filter

This commit is contained in:
harttle
2020-04-01 02:22:44 +08:00
parent d65ed408f0
commit c923598b40
12 changed files with 187 additions and 284 deletions
+5 -4
View File
@@ -1,4 +1,5 @@
import { isArray, last as arrayLast } from '../../util/underscore'
import { toArray } from '../../util/collection'
import { isTruthy } from '../../render/boolean'
import { FilterImpl } from '../../template/filter/filter-impl'
@@ -10,11 +11,11 @@ export const sort = <T>(v: T[], arg: (lhs: T, rhs: T) => number) => v.sort(arg)
export const size = (v: string | any[]) => (v && v.length) || 0
export function map<T1, T2> (arr: {[key: string]: T1}[], arg: string): T1[] {
return arr.map(v => v[arg])
return toArray(arr).map(v => v[arg])
}
export function concat<T1, T2> (v: T1[], arg: T2[] | T2): (T1 | T2)[] {
return Array.prototype.concat.call(v, arg)
return toArray(v).concat(arg)
}
export function slice<T> (v: T[], begin: number, length = 1): T[] {
@@ -23,8 +24,8 @@ export function slice<T> (v: T[], begin: number, length = 1): T[] {
}
export function where<T extends object> (this: FilterImpl, arr: T[], property: string, expected?: any): T[] {
return arr.filter(obj => {
const value = this.context.getFromScope(obj, property.split('.'))
return toArray(arr).filter(obj => {
const value = this.context.getFromScope(obj, String(property).split('.'))
return expected === undefined ? isTruthy(value) : value === expected
})
}
+2 -2
View File
@@ -1,5 +1,5 @@
import { assert, Tokenizer, evalToken, Emitter, TagToken, TopLevelToken, Context, Template, TagImplOptions, ParseStream } from '../../types'
import { toCollection } from '../../util/collection'
import { toEnumerable } from '../../util/collection'
import { ForloopDrop } from '../../drop/forloop-drop'
import { Hash } from '../../template/tag/hash'
@@ -36,7 +36,7 @@ export default {
},
render: function * (ctx: Context, emitter: Emitter) {
const r = this.liquid.renderer
let collection = toCollection(evalToken(this.collection, ctx))
let collection = toEnumerable(evalToken(this.collection, ctx))
if (!collection.length) {
yield r.renderTemplates(this.elseTemplates, ctx, emitter)
+2 -2
View File
@@ -1,6 +1,6 @@
import { assert } from '../../util/assert'
import { ForloopDrop } from '../../drop/forloop-drop'
import { toCollection } from '../../util/collection'
import { toEnumerable } from '../../util/collection'
import { evalQuotedToken, TypeGuards, Tokenizer, evalToken, Hash, Emitter, TagToken, Context, TagImplOptions } from '../../types'
export default {
@@ -60,7 +60,7 @@ export default {
if (this['for']) {
const { value, alias } = this['for']
let collection = evalToken(value, ctx)
collection = toCollection(collection)
collection = toEnumerable(collection)
scope['forloop'] = new ForloopDrop(collection.length)
for (const item of collection) {
scope[alias] = item
+2 -2
View File
@@ -1,4 +1,4 @@
import { toCollection } from '../../util/collection'
import { toEnumerable } from '../../util/collection'
import { assert, evalToken, Emitter, Hash, TagToken, TopLevelToken, Context, Template, TagImplOptions, ParseStream } from '../../types'
import { TablerowloopDrop } from '../../drop/tablerowloop-drop'
import { Tokenizer } from '../../parser/tokenizer'
@@ -30,7 +30,7 @@ export default {
},
render: function * (ctx: Context, emitter: Emitter) {
let collection = toCollection(evalToken(this.collection, ctx))
let collection = toEnumerable(evalToken(this.collection, ctx))
const hash = yield this.hash.render(ctx)
const offset = hash.offset || 0
const limit = (hash.limit === undefined) ? collection.length : hash.limit
-1
View File
@@ -16,7 +16,6 @@ export class Value {
const tokenizer = new Tokenizer(str)
this.initial = tokenizer.readValue()
this.filters = tokenizer.readFilters().map(({ name, args }) => new Filter(name, this.filterMap.get(name), args))
tokenizer.skipBlank()
}
public * value (ctx: Context) {
let val = yield evalToken(this.initial, ctx)
+6 -1
View File
@@ -1,8 +1,13 @@
import { isString, isObject, isArray } from './underscore'
export function toCollection (val: any) {
export function toEnumerable (val: any) {
if (isArray(val)) return val
if (isString(val) && val.length > 0) return [val]
if (isObject(val)) return Object.keys(val).map((key) => [key, val[key]])
return []
}
export function toArray (val: any) {
if (isArray(val)) return val
return [ val ]
}