fix: pass drops directly to filters/tags

This commit is contained in:
harttle
2019-05-12 20:03:32 +08:00
parent 4282accaa2
commit bef290923c
15 changed files with 93 additions and 42 deletions
+4 -1
View File
@@ -1,5 +1,8 @@
import { isFalsy } from '../../render/syntax'
import { toValue } from '../../util/underscore'
export default {
'default': <T1, T2>(v: string | T1, arg: T2): string | T1 | T2 => isFalsy(v) || v === '' ? arg : v
'default': function<T1, T2> (v: string | T1, arg: T2): string | T1 | T2 {
return isFalsy(toValue(v)) || v === '' ? arg : v
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
import { isString, isObject, isArray } from '../../util/underscore'
import { evalExp } from '../../render/syntax'
import { parseExp } from '../../render/syntax'
import assert from '../../util/assert'
import { identifier, value, hash } from '../../parser/lexical'
import TagToken from '../../parser/tag-token'
@@ -42,7 +42,7 @@ export default <ITagImplOptions>{
stream.start()
},
render: async function (ctx: Context, hash: Hash) {
let collection = await evalExp(this.collection, ctx)
let collection = await parseExp(this.collection, ctx)
if (!isArray(collection)) {
if (isString(collection) && collection.length > 0) {
+5 -11
View File
@@ -1,6 +1,6 @@
import assert from '../../util/assert'
import { value, quotedLine } from '../../parser/lexical'
import { evalValue } from '../../render/syntax'
import { evalValue, parseValue } from '../../render/syntax'
import BlockMode from '../../context/block-mode'
import TagToken from '../../parser/tag-token'
import Context from '../../context/context'
@@ -13,19 +13,13 @@ const withRE = new RegExp(`with\\s+(${value.source})`)
export default <ITagImplOptions>{
parse: function (token: TagToken) {
let match = staticFileRE.exec(token.args)
if (match) {
this.staticValue = match[0]
}
if (match) this.staticValue = match[0]
match = value.exec(token.args)
if (match) {
this.value = match[0]
}
if (match) this.value = match[0]
match = withRE.exec(token.args)
if (match) {
this.with = match[1]
}
if (match) this.with = match[1]
},
render: async function (ctx: Context, hash: Hash) {
let filepath
@@ -47,7 +41,7 @@ export default <ITagImplOptions>{
ctx.setRegister('blocks', {})
ctx.setRegister('blockMode', BlockMode.OUTPUT)
if (this.with) {
hash[filepath] = await evalValue(this.with, ctx)
hash[filepath] = await parseValue(this.with, ctx)
}
const templates = await this.liquid.getTemplate(filepath, ctx.opts)
ctx.push(hash)
+2 -3
View File
@@ -1,11 +1,10 @@
import { isNil, isString } from '../util/underscore'
import { Drop } from '../drop/drop'
import { isNil, isString, toValue } from '../util/underscore'
import { EmptyDrop } from '../drop/empty-drop'
export class BlankDrop extends EmptyDrop {
equals (value: any) {
if (value === false) return true
if (isNil(value instanceof Drop ? value.valueOf() : value)) return true
if (isNil(toValue(value))) return true
if (isString(value)) return /^\s*$/.test(value)
return super.equals(value)
}
+2 -2
View File
@@ -1,11 +1,11 @@
import { Drop } from './drop'
import { IComparable } from './icomparable'
import { isNil } from '../util/underscore'
import { isNil, toValue } from '../util/underscore'
import { BlankDrop } from '../drop/blank-drop'
export class NullDrop extends Drop implements IComparable {
equals (value: any) {
return isNil(value instanceof Drop ? value.valueOf() : value) || value instanceof BlankDrop
return isNil(toValue(value)) || value instanceof BlankDrop
}
gt () {
return false
+4 -7
View File
@@ -1,12 +1,11 @@
import * as lexical from '../parser/lexical'
import assert from '../util/assert'
import Context from '../context/context'
import { range, last, isFunction } from '../util/underscore'
import { range, last, isFunction, toValue } from '../util/underscore'
import { isComparable } from '../drop/icomparable'
import { NullDrop } from '../drop/null-drop'
import { EmptyDrop } from '../drop/empty-drop'
import { BlankDrop } from '../drop/blank-drop'
import { Drop } from '../drop/drop'
const binaryOperators: {[key: string]: (lhs: any, rhs: any) => boolean} = {
'==': (l: any, r: any) => {
@@ -71,11 +70,10 @@ export async function parseExp (exp: string, ctx: Context): Promise<any> {
}
export async function evalExp (str: string, ctx: Context): Promise<any> {
const value = await parseExp(str, ctx)
return value instanceof Drop ? value.valueOf() : value
return toValue(await parseExp(str, ctx))
}
async function parseValue (str: string | undefined, ctx: Context): Promise<any> {
export async function parseValue (str: string | undefined, ctx: Context): Promise<any> {
if (!str) return null
str = str.trim()
@@ -90,8 +88,7 @@ async function parseValue (str: string | undefined, ctx: Context): Promise<any>
}
export async function evalValue (str: string | undefined, ctx: Context) {
const value = await parseValue(str, ctx)
return value instanceof Drop ? value.valueOf() : value
return toValue(await parseValue(str, ctx))
}
export function isTruthy (val: any): boolean {
+10 -4
View File
@@ -1,9 +1,11 @@
import { evalValue } from '../../render/syntax'
import { parseValue } from '../../render/syntax'
import Context from '../../context/context'
import { isArray } from '../../util/underscore'
import { FilterImplOptions } from './filter-impl-options'
export type FilterArgs = Array<string|[string?, string?]>
type KeyValuePair = [string?, string?]
type FilterArg = string|KeyValuePair
export type FilterArgs = Array<FilterArg>
export class Filter {
name: string
@@ -22,8 +24,8 @@ export class Filter {
async render (value: any, context: Context) {
const argv: any[] = []
for (const arg of this.args) {
if (isArray(arg)) argv.push([arg[0], await evalValue(arg[1], context)])
else argv.push(await evalValue(arg, context))
if (isKeyValuePair(arg)) argv.push([arg[0], await parseValue(arg[1], context)])
else argv.push(await parseValue(arg, context))
}
return this.impl.apply({ context }, [value, ...argv])
}
@@ -34,3 +36,7 @@ export class Filter {
Filter.impls = {}
}
}
function isKeyValuePair (arr: FilterArg): arr is KeyValuePair {
return isArray(arr)
}
+3 -3
View File
@@ -1,5 +1,5 @@
import Value from './value'
import { stringify } from '../util/underscore'
import { stringify, toValue } from '../util/underscore'
import Template from '../template/template'
import ITemplate from '../template/itemplate'
import Context from '../context/context'
@@ -12,7 +12,7 @@ export default class Output extends Template<OutputToken> implements ITemplate {
this.value = new Value(token.value, strictFilters)
}
async render (ctx: Context): Promise<string> {
const html = await this.value.value(ctx)
return stringify(html)
const val = await this.value.value(ctx)
return stringify(toValue(val))
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
import { hashCapture } from '../../parser/lexical'
import { evalValue } from '../../render/syntax'
import { parseValue } from '../../render/syntax'
import Context from '../../context/context'
/**
@@ -17,7 +17,7 @@ export default class Hash {
while ((match = hashCapture.exec(markup))) {
const k = match[1]
const v = match[2]
instance[k] = await evalValue(v, ctx)
instance[k] = await parseValue(v, ctx)
}
return instance
}
+2 -2
View File
@@ -1,4 +1,4 @@
import { evalExp } from '../render/syntax'
import { parseExp } from '../render/syntax'
import { FilterArgs, Filter } from './filter/filter'
import Context from '../context/context'
@@ -48,7 +48,7 @@ export default class Value {
this.filters.push(new Filter(name, args, this.strictFilters))
}
async value (ctx: Context) {
let val = await evalExp(this.initial, ctx)
let val = await parseExp(this.initial, ctx)
for (const filter of this.filters) {
val = await filter.render(val, ctx)
}
+6
View File
@@ -1,3 +1,5 @@
import { Drop } from '../drop/drop'
const toStr = Object.prototype.toString
/*
@@ -31,6 +33,10 @@ export function stringify (value: any): string {
return String(value)
}
export function toValue (value: any): any {
return value instanceof Drop ? value.valueOf() : value
}
export function toLiquid (value: any): any {
if (isFunction(value.toLiquid)) return toLiquid(value.toLiquid())
return value