mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 12:20:40 -07:00
perf: use polymophism instead duck test
This commit is contained in:
@@ -48,7 +48,7 @@ export default <ITagImplOptions>{
|
|||||||
if (isString(collection) && collection.length > 0) {
|
if (isString(collection) && collection.length > 0) {
|
||||||
collection = [collection] as string[]
|
collection = [collection] as string[]
|
||||||
} else if (isObject(collection)) {
|
} else if (isObject(collection)) {
|
||||||
collection = Object.keys(collection).map((key) => [key, collection[key]]) as Array<[string, any]>
|
collection = Object.keys(collection).map((key) => [key, collection[key]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isArray(collection) || !collection.length) {
|
if (!isArray(collection) || !collection.length) {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export default class Context {
|
|||||||
}
|
}
|
||||||
return this.scopes.splice(i, 1)[0]
|
return this.scopes.splice(i, 1)[0]
|
||||||
}
|
}
|
||||||
findScope (key: string) {
|
private findScope (key: string) {
|
||||||
for (let i = this.scopes.length - 1; i >= 0; i--) {
|
for (let i = this.scopes.length - 1; i >= 0; i--) {
|
||||||
const candidate = this.scopes[i]
|
const candidate = this.scopes[i]
|
||||||
if (key in candidate) {
|
if (key in candidate) {
|
||||||
@@ -73,7 +73,7 @@ export default class Context {
|
|||||||
* accessSeq("foo['b]r']") // ['foo', 'b]r']
|
* accessSeq("foo['b]r']") // ['foo', 'b]r']
|
||||||
* accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar'
|
* accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar'
|
||||||
*/
|
*/
|
||||||
async parseProp (str: string) {
|
private async parseProp (str: string) {
|
||||||
str = String(str)
|
str = String(str)
|
||||||
const seq: string[] = []
|
const seq: string[] = []
|
||||||
let name = ''
|
let name = ''
|
||||||
@@ -107,8 +107,7 @@ export default class Context {
|
|||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
default:// foo.bar
|
default:// foo.bar
|
||||||
name += str[i]
|
name += str[i++]
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push()
|
push()
|
||||||
|
|||||||
@@ -2,17 +2,26 @@ import Token from './token'
|
|||||||
import { last } from '../util/underscore'
|
import { last } from '../util/underscore'
|
||||||
|
|
||||||
export default class DelimitedToken extends Token {
|
export default class DelimitedToken extends Token {
|
||||||
trimLeft: boolean
|
constructor (
|
||||||
trimRight: boolean
|
raw: string,
|
||||||
constructor (raw: string, value: string, input: string, line: number, pos: number, file?: string) {
|
value: string,
|
||||||
|
input: string,
|
||||||
|
line: number,
|
||||||
|
pos: number,
|
||||||
|
trimLeft: boolean,
|
||||||
|
trimRight: boolean,
|
||||||
|
file?: string
|
||||||
|
) {
|
||||||
super(raw, input, line, pos, file)
|
super(raw, input, line, pos, file)
|
||||||
this.trimLeft = value[0] === '-'
|
const tl = value[0] === '-'
|
||||||
this.trimRight = last(value) === '-'
|
const tr = last(value) === '-'
|
||||||
this.value = value
|
this.value = value
|
||||||
.slice(
|
.slice(
|
||||||
this.trimLeft ? 1 : 0,
|
tl ? 1 : 0,
|
||||||
this.trimRight ? -1 : value.length
|
tr ? -1 : value.length
|
||||||
)
|
)
|
||||||
.trim()
|
.trim()
|
||||||
|
this.trimLeft = tl || trimLeft
|
||||||
|
this.trimRight = tr || trimRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,7 @@ export default class HTMLToken extends Token {
|
|||||||
this.type = 'html'
|
this.type = 'html'
|
||||||
this.value = str
|
this.value = str
|
||||||
}
|
}
|
||||||
|
static is (token: Token): token is HTMLToken {
|
||||||
|
return token.type === 'html'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
import DelimitedToken from './delimited-token'
|
import DelimitedToken from './delimited-token'
|
||||||
|
import Token from './token'
|
||||||
|
import { NormalizedFullOptions } from '../liquid-options'
|
||||||
|
|
||||||
export default class OutputToken extends DelimitedToken {
|
export default class OutputToken extends DelimitedToken {
|
||||||
constructor (raw: string, value: string, input: string, line: number, pos: number, file?: string) {
|
constructor (
|
||||||
super(raw, value, input, line, pos, file)
|
raw: string,
|
||||||
|
value: string,
|
||||||
|
input: string,
|
||||||
|
line: number,
|
||||||
|
pos: number,
|
||||||
|
options: NormalizedFullOptions,
|
||||||
|
file?: string
|
||||||
|
) {
|
||||||
|
super(raw, value, input, line, pos, options.trimOutputLeft, options.trimOutputRight, file)
|
||||||
this.type = 'output'
|
this.type = 'output'
|
||||||
}
|
}
|
||||||
|
static is (token: Token): token is OutputToken {
|
||||||
|
return token.type === 'output'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,16 @@ export default class ParseStream {
|
|||||||
this.handlers[name] = cb
|
this.handlers[name] = cb
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
trigger <T extends Token | ITemplate> (event: string, arg?: T) {
|
private trigger <T extends Token | ITemplate> (event: string, arg?: T) {
|
||||||
const h = this.handlers[event]
|
const h = this.handlers[event]
|
||||||
if (typeof h === 'function') {
|
return h ? (h(arg), true) : false
|
||||||
h(arg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
start () {
|
start () {
|
||||||
this.trigger('start')
|
this.trigger('start')
|
||||||
let token: Token | undefined
|
let token: Token | undefined
|
||||||
while (!this.stopRequested && (token = this.tokens.shift())) {
|
while (!this.stopRequested && (token = this.tokens.shift())) {
|
||||||
if (this.trigger('token', token)) continue
|
if (this.trigger('token', token)) continue
|
||||||
if (token.type === 'tag' && this.trigger(`tag:${(<TagToken>token).name}`, token)) {
|
if (TagToken.is(token) && this.trigger(`tag:${token.name}`, token)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const template = this.parseToken(token, this.tokens)
|
const template = this.parseToken(token, this.tokens)
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ export default class Parser {
|
|||||||
}
|
}
|
||||||
parseToken (token: Token, remainTokens: Array<Token>) {
|
parseToken (token: Token, remainTokens: Array<Token>) {
|
||||||
try {
|
try {
|
||||||
if (token.type === 'tag') {
|
if (TagToken.is(token)) {
|
||||||
return new Tag(token as TagToken, remainTokens, this.liquid)
|
return new Tag(token, remainTokens, this.liquid)
|
||||||
}
|
}
|
||||||
if (token.type === 'output') {
|
if (OutputToken.is(token)) {
|
||||||
return new Output(token as OutputToken, this.liquid.options.strictFilters)
|
return new Output(token as OutputToken, this.liquid.options.strictFilters)
|
||||||
}
|
}
|
||||||
return new HTML(token)
|
return new HTML(token)
|
||||||
|
|||||||
+15
-2
@@ -1,12 +1,22 @@
|
|||||||
import DelimitedToken from './delimited-token'
|
import DelimitedToken from './delimited-token'
|
||||||
|
import Token from './token'
|
||||||
import { TokenizationError } from '../util/error'
|
import { TokenizationError } from '../util/error'
|
||||||
import * as lexical from './lexical'
|
import * as lexical from './lexical'
|
||||||
|
import { NormalizedFullOptions } from '../liquid-options'
|
||||||
|
|
||||||
export default class TagToken extends DelimitedToken {
|
export default class TagToken extends DelimitedToken {
|
||||||
name: string
|
name: string
|
||||||
args: string
|
args: string
|
||||||
constructor (raw: string, value: string, input: string, line: number, pos: number, file?: string) {
|
constructor (
|
||||||
super(raw, value, input, line, pos, file)
|
raw: string,
|
||||||
|
value: string,
|
||||||
|
input: string,
|
||||||
|
line: number,
|
||||||
|
pos: number,
|
||||||
|
options: NormalizedFullOptions,
|
||||||
|
file?: string
|
||||||
|
) {
|
||||||
|
super(raw, value, input, line, pos, options.trimTagLeft, options.trimTagRight, file)
|
||||||
this.type = 'tag'
|
this.type = 'tag'
|
||||||
const match = this.value.match(lexical.tagLine)
|
const match = this.value.match(lexical.tagLine)
|
||||||
if (!match) {
|
if (!match) {
|
||||||
@@ -15,4 +25,7 @@ export default class TagToken extends DelimitedToken {
|
|||||||
this.name = match[1]
|
this.name = match[1]
|
||||||
this.args = match[2]
|
this.args = match[2]
|
||||||
}
|
}
|
||||||
|
static is (token: Token): token is TagToken {
|
||||||
|
return token.type === 'tag'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
export default class Token {
|
export default class Token {
|
||||||
|
trimLeft: boolean = false
|
||||||
|
trimRight: boolean = false
|
||||||
type: string = 'notset'
|
type: string = 'notset'
|
||||||
line: number
|
line: number
|
||||||
col: number
|
col: number
|
||||||
|
|||||||
+24
-19
@@ -9,16 +9,18 @@ import { NormalizedFullOptions, applyDefault } from '../liquid-options'
|
|||||||
enum ParseState { HTML, OUTPUT, TAG }
|
enum ParseState { HTML, OUTPUT, TAG }
|
||||||
|
|
||||||
export default class Tokenizer {
|
export default class Tokenizer {
|
||||||
options: NormalizedFullOptions
|
private options: NormalizedFullOptions
|
||||||
constructor (options?: NormalizedFullOptions) {
|
constructor (options?: NormalizedFullOptions) {
|
||||||
this.options = applyDefault(options)
|
this.options = applyDefault(options)
|
||||||
}
|
}
|
||||||
tokenize (input: string, file?: string) {
|
tokenize (input: string, file?: string) {
|
||||||
const tokens: Token[] = []
|
const tokens: Token[] = []
|
||||||
const tagL = this.options.tagDelimiterLeft
|
const {
|
||||||
const tagR = this.options.tagDelimiterRight
|
tagDelimiterLeft,
|
||||||
const outputL = this.options.outputDelimiterLeft
|
tagDelimiterRight,
|
||||||
const outputR = this.options.outputDelimiterRight
|
outputDelimiterLeft,
|
||||||
|
outputDelimiterRight
|
||||||
|
} = this.options
|
||||||
let p = 0
|
let p = 0
|
||||||
let curLine = 1
|
let curLine = 1
|
||||||
let state = ParseState.HTML
|
let state = ParseState.HTML
|
||||||
@@ -33,36 +35,39 @@ export default class Tokenizer {
|
|||||||
lineBegin = p + 1
|
lineBegin = p + 1
|
||||||
}
|
}
|
||||||
if (state === ParseState.HTML) {
|
if (state === ParseState.HTML) {
|
||||||
if (input.substr(p, outputL.length) === outputL) {
|
if (input.substr(p, outputDelimiterLeft.length) === outputDelimiterLeft) {
|
||||||
if (buffer) tokens.push(new HTMLToken(buffer, input, line, col, file))
|
if (buffer) tokens.push(new HTMLToken(buffer, input, line, col, file))
|
||||||
buffer = outputL
|
buffer = outputDelimiterLeft
|
||||||
line = curLine
|
line = curLine
|
||||||
col = p - lineBegin + 1
|
col = p - lineBegin + 1
|
||||||
p += outputL.length
|
p += outputDelimiterLeft.length
|
||||||
state = ParseState.OUTPUT
|
state = ParseState.OUTPUT
|
||||||
continue
|
continue
|
||||||
} else if (input.substr(p, tagL.length) === tagL) {
|
} else if (input.substr(p, tagDelimiterLeft.length) === tagDelimiterLeft) {
|
||||||
if (buffer) tokens.push(new HTMLToken(buffer, input, line, col, file))
|
if (buffer) tokens.push(new HTMLToken(buffer, input, line, col, file))
|
||||||
buffer = tagL
|
buffer = tagDelimiterLeft
|
||||||
line = curLine
|
line = curLine
|
||||||
col = p - lineBegin + 1
|
col = p - lineBegin + 1
|
||||||
p += tagL.length
|
p += tagDelimiterLeft.length
|
||||||
state = ParseState.TAG
|
state = ParseState.TAG
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if (state === ParseState.OUTPUT && input.substr(p, outputR.length) === outputR) {
|
} else if (
|
||||||
buffer += outputR
|
state === ParseState.OUTPUT &&
|
||||||
tokens.push(new OutputToken(buffer, buffer.slice(outputL.length, -outputR.length), input, line, col, file))
|
input.substr(p, outputDelimiterRight.length) === outputDelimiterRight
|
||||||
p += outputR.length
|
) {
|
||||||
|
buffer += outputDelimiterRight
|
||||||
|
tokens.push(new OutputToken(buffer, buffer.slice(outputDelimiterLeft.length, -outputDelimiterRight.length), input, line, col, this.options, file))
|
||||||
|
p += outputDelimiterRight.length
|
||||||
buffer = ''
|
buffer = ''
|
||||||
line = curLine
|
line = curLine
|
||||||
col = p - lineBegin + 1
|
col = p - lineBegin + 1
|
||||||
state = ParseState.HTML
|
state = ParseState.HTML
|
||||||
continue
|
continue
|
||||||
} else if (input.substr(p, tagR.length) === tagR) {
|
} else if (input.substr(p, tagDelimiterRight.length) === tagDelimiterRight) {
|
||||||
buffer += tagR
|
buffer += tagDelimiterRight
|
||||||
tokens.push(new TagToken(buffer, buffer.slice(tagL.length, -tagR.length), input, line, col, file))
|
tokens.push(new TagToken(buffer, buffer.slice(tagDelimiterLeft.length, -tagDelimiterRight.length), input, line, col, this.options, file))
|
||||||
p += tagR.length
|
p += tagDelimiterRight.length
|
||||||
buffer = ''
|
buffer = ''
|
||||||
line = curLine
|
line = curLine
|
||||||
col = p - lineBegin + 1
|
col = p - lineBegin + 1
|
||||||
|
|||||||
@@ -1,47 +1,38 @@
|
|||||||
import DelimitedToken from '../parser/delimited-token'
|
|
||||||
import Token from '../parser/token'
|
import Token from '../parser/token'
|
||||||
import TagToken from '../parser/tag-token'
|
import TagToken from '../parser/tag-token'
|
||||||
|
import HTMLToken from '../parser/html-token'
|
||||||
import { NormalizedFullOptions } from '../liquid-options'
|
import { NormalizedFullOptions } from '../liquid-options'
|
||||||
|
|
||||||
export default function whiteSpaceCtrl (tokens: Token[], options: NormalizedFullOptions) {
|
export default function whiteSpaceCtrl (tokens: Token[], options: NormalizedFullOptions) {
|
||||||
options = { greedy: true, ...options }
|
options = { greedy: true, ...options }
|
||||||
let inRaw = false
|
let inRaw = false
|
||||||
|
|
||||||
tokens.forEach((token: Token, i: number) => {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
if (shouldTrimLeft(token as DelimitedToken, inRaw, options)) {
|
const token = tokens[i]
|
||||||
|
if (!inRaw && token.trimLeft) {
|
||||||
trimLeft(tokens[i - 1], options.greedy)
|
trimLeft(tokens[i - 1], options.greedy)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.type === 'tag' && (token as TagToken).name === 'raw') inRaw = true
|
if (TagToken.is(token)) {
|
||||||
if (token.type === 'tag' && (token as TagToken).name === 'endraw') inRaw = false
|
if (token.name === 'raw') inRaw = true
|
||||||
|
else if (token.name === 'endraw') inRaw = false
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldTrimRight(token as DelimitedToken, inRaw, options)) {
|
if (!inRaw && token.trimRight) {
|
||||||
trimRight(tokens[i + 1], options.greedy)
|
trimRight(tokens[i + 1], options.greedy)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function shouldTrimLeft (token: DelimitedToken, inRaw: boolean, options: NormalizedFullOptions) {
|
|
||||||
if (inRaw) return false
|
|
||||||
if (token.type === 'tag') return token.trimLeft || options.trimTagLeft
|
|
||||||
if (token.type === 'output') return token.trimLeft || options.trimOutputLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
function shouldTrimRight (token: DelimitedToken, inRaw: boolean, options: NormalizedFullOptions) {
|
|
||||||
if (inRaw) return false
|
|
||||||
if (token.type === 'tag') return token.trimRight || options.trimTagRight
|
|
||||||
if (token.type === 'output') return token.trimRight || options.trimOutputRight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function trimLeft (token: Token, greedy: boolean) {
|
function trimLeft (token: Token, greedy: boolean) {
|
||||||
if (!token || token.type !== 'html') return
|
if (!token || !HTMLToken.is(token)) return
|
||||||
|
|
||||||
const rLeft = greedy ? /\s+$/g : /[\t\r ]*$/g
|
const rLeft = greedy ? /\s+$/g : /[\t\r ]*$/g
|
||||||
token.value = token.value.replace(rLeft, '')
|
token.value = token.value.replace(rLeft, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function trimRight (token: Token, greedy: boolean) {
|
function trimRight (token: Token, greedy: boolean) {
|
||||||
if (!token || token.type !== 'html') return
|
if (!token || !HTMLToken.is(token)) return
|
||||||
|
|
||||||
const rRight = greedy ? /^\s+/g : /^[\t\r ]*\n?/g
|
const rRight = greedy ? /^\s+/g : /^[\t\r ]*\n?/g
|
||||||
token.value = token.value.replace(rRight, '')
|
token.value = token.value.replace(rRight, '')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as lexical from '../parser/lexical'
|
import * as lexical from '../parser/lexical'
|
||||||
import assert from '../util/assert'
|
import assert from '../util/assert'
|
||||||
import Context from '../context/context'
|
import Context from '../context/context'
|
||||||
import { range, last } from '../util/underscore'
|
import { range, last, isFunction } from '../util/underscore'
|
||||||
import { isComparable } from '../drop/icomparable'
|
import { isComparable } from '../drop/icomparable'
|
||||||
import { NullDrop } from '../drop/null-drop'
|
import { NullDrop } from '../drop/null-drop'
|
||||||
import { EmptyDrop } from '../drop/empty-drop'
|
import { EmptyDrop } from '../drop/empty-drop'
|
||||||
@@ -40,9 +40,7 @@ const binaryOperators: {[key: string]: (lhs: any, rhs: any) => boolean} = {
|
|||||||
return l <= r
|
return l <= r
|
||||||
},
|
},
|
||||||
'contains': (l: any, r: any) => {
|
'contains': (l: any, r: any) => {
|
||||||
if (!l) return false
|
return l && isFunction(l.indexOf) ? l.indexOf(r) > -1 : false
|
||||||
if (typeof l.indexOf !== 'function') return false
|
|
||||||
return l.indexOf(r) > -1
|
|
||||||
},
|
},
|
||||||
'and': (l: any, r: any) => isTruthy(l) && isTruthy(r),
|
'and': (l: any, r: any) => isTruthy(l) && isTruthy(r),
|
||||||
'or': (l: any, r: any) => isTruthy(l) || isTruthy(r)
|
'or': (l: any, r: any) => isTruthy(l) || isTruthy(r)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { create, stringify } from '../../util/underscore'
|
import { stringify, isFunction } from '../../util/underscore'
|
||||||
import assert from '../../util/assert'
|
import assert from '../../util/assert'
|
||||||
import Context from '../../context/context'
|
import Context from '../../context/context'
|
||||||
import ITagImpl from './itag-impl'
|
import ITagImpl from './itag-impl'
|
||||||
@@ -21,7 +21,8 @@ export default class Tag extends Template<TagToken> implements ITemplate {
|
|||||||
|
|
||||||
const impl = Tag.impls[token.name]
|
const impl = Tag.impls[token.name]
|
||||||
assert(impl, `tag ${token.name} not found`)
|
assert(impl, `tag ${token.name} not found`)
|
||||||
this.impl = create<ITagImplOptions, ITagImpl>(impl)
|
|
||||||
|
this.impl = Object.create(impl)
|
||||||
this.impl.liquid = liquid
|
this.impl.liquid = liquid
|
||||||
if (this.impl.parse) {
|
if (this.impl.parse) {
|
||||||
this.impl.parse(token, tokens)
|
this.impl.parse(token, tokens)
|
||||||
@@ -30,11 +31,7 @@ export default class Tag extends Template<TagToken> implements ITemplate {
|
|||||||
async render (ctx: Context) {
|
async render (ctx: Context) {
|
||||||
const hash = await Hash.create(this.token.args, ctx)
|
const hash = await Hash.create(this.token.args, ctx)
|
||||||
const impl = this.impl
|
const impl = this.impl
|
||||||
if (typeof impl.render !== 'function') {
|
return isFunction(impl.render) ? stringify(await impl.render(ctx, hash)) : ''
|
||||||
return ''
|
|
||||||
}
|
|
||||||
const html = await impl.render(ctx, hash)
|
|
||||||
return stringify(html)
|
|
||||||
}
|
}
|
||||||
static register (name: string, tag: ITagImplOptions) {
|
static register (name: string, tag: ITagImplOptions) {
|
||||||
Tag.impls[name] = tag
|
Tag.impls[name] = tag
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import Context from '../context/context'
|
|||||||
|
|
||||||
export default class Value {
|
export default class Value {
|
||||||
private strictFilters: boolean
|
private strictFilters: boolean
|
||||||
initial: string
|
private initial: string
|
||||||
filters: Array<Filter> = []
|
private filters: Array<Filter> = []
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param str value string, like: "i have a dream | truncate: 3
|
* @param str value string, like: "i have a dream | truncate: 3
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { AssertionError } from './error'
|
import { AssertionError } from './error'
|
||||||
|
|
||||||
export default function (predicate: any, message?: string) {
|
export default function<T> (predicate: T | null | undefined, message?: string) {
|
||||||
if (!predicate) {
|
if (!predicate) {
|
||||||
message = message || `expect ${predicate} to be true`
|
message = message || `expect ${predicate} to be true`
|
||||||
throw new AssertionError(message)
|
throw new AssertionError(message)
|
||||||
|
|||||||
@@ -36,10 +36,6 @@ export function toLiquid (value: any): any {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create<T1 extends object, T2 extends T1 = T1> (proto: T1): T2 {
|
|
||||||
return Object.create(proto)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isNil (value: any): boolean {
|
export function isNil (value: any): boolean {
|
||||||
return value === null || value === undefined
|
return value === null || value === undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Scope } from '../../../src/context/scope'
|
|||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
describe('scope', function () {
|
describe('scope', function () {
|
||||||
let ctx: Context, scope: Scope
|
let ctx: any, scope: Scope
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
scope = {
|
scope = {
|
||||||
foo: 'zoo',
|
foo: 'zoo',
|
||||||
|
|||||||
+13
-13
@@ -14,70 +14,70 @@ describe('Value', function () {
|
|||||||
|
|
||||||
describe('#constructor()', function () {
|
describe('#constructor()', function () {
|
||||||
it('should parse "foo', function () {
|
it('should parse "foo', function () {
|
||||||
const tpl = new Value('foo', false)
|
const tpl = new Value('foo', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo')
|
||||||
expect(tpl.filters).to.deep.equal([])
|
expect(tpl.filters).to.deep.equal([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse "foo | add"', function () {
|
it('should parse "foo | add"', function () {
|
||||||
const tpl = new Value('foo | add', false)
|
const tpl = new Value('foo | add', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo')
|
||||||
expect(tpl.filters.length).to.equal(1)
|
expect(tpl.filters.length).to.equal(1)
|
||||||
expect(tpl.filters[0].args).to.eql([])
|
expect(tpl.filters[0].args).to.eql([])
|
||||||
})
|
})
|
||||||
it('should parse "foo,foo | add"', function () {
|
it('should parse "foo,foo | add"', function () {
|
||||||
const tpl = new Value('foo,foo | add', false)
|
const tpl = new Value('foo,foo | add', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo') as any
|
||||||
expect(tpl.filters.length).to.equal(1)
|
expect(tpl.filters.length).to.equal(1)
|
||||||
expect(tpl.filters[0].args).to.eql([])
|
expect(tpl.filters[0].args).to.eql([])
|
||||||
})
|
})
|
||||||
it('should parse "foo | add: 3, false"', function () {
|
it('should parse "foo | add: 3, false"', function () {
|
||||||
const tpl = new Value('foo | add: 3, "foo"', false)
|
const tpl = new Value('foo | add: 3, "foo"', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo')
|
||||||
expect(tpl.filters.length).to.equal(1)
|
expect(tpl.filters.length).to.equal(1)
|
||||||
expect(tpl.filters[0].args).to.eql(['3', '"foo"'])
|
expect(tpl.filters[0].args).to.eql(['3', '"foo"'])
|
||||||
})
|
})
|
||||||
it('should parse "foo | add: "foo" bar, 3"', function () {
|
it('should parse "foo | add: "foo" bar, 3"', function () {
|
||||||
const tpl = new Value('foo | add: "foo" bar, 3', false)
|
const tpl = new Value('foo | add: "foo" bar, 3', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo')
|
||||||
expect(tpl.filters.length).to.equal(1)
|
expect(tpl.filters.length).to.equal(1)
|
||||||
expect(tpl.filters[0].name).to.eql('add')
|
expect(tpl.filters[0].name).to.eql('add')
|
||||||
expect(tpl.filters[0].args).to.eql(['"foo"', '3'])
|
expect(tpl.filters[0].args).to.eql(['"foo"', '3'])
|
||||||
})
|
})
|
||||||
it('should parse "foo | add: "|", 3', function () {
|
it('should parse "foo | add: "|", 3', function () {
|
||||||
const tpl = new Value('foo | add: "|", 3', false)
|
const tpl = new Value('foo | add: "|", 3', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo')
|
||||||
expect(tpl.filters.length).to.equal(1)
|
expect(tpl.filters.length).to.equal(1)
|
||||||
expect(tpl.filters[0].args).to.eql(['"|"', '3'])
|
expect(tpl.filters[0].args).to.eql(['"|"', '3'])
|
||||||
})
|
})
|
||||||
it('should parse "foo | add: "|", 3', function () {
|
it('should parse "foo | add: "|", 3', function () {
|
||||||
const tpl = new Value('foo | add: "|", 3', false)
|
const tpl = new Value('foo | add: "|", 3', false) as any
|
||||||
expect(tpl.initial).to.equal('foo')
|
expect(tpl.initial).to.equal('foo')
|
||||||
expect(tpl.filters.length).to.equal(1)
|
expect(tpl.filters.length).to.equal(1)
|
||||||
expect(tpl.filters[0].args).to.eql(['"|"', '3'])
|
expect(tpl.filters[0].args).to.eql(['"|"', '3'])
|
||||||
})
|
})
|
||||||
it('should support arguments as named key/values', function () {
|
it('should support arguments as named key/values', function () {
|
||||||
const f = new Value('o | foo: key1: "literal1", key2: value2', false)
|
const f = new Value('o | foo: key1: "literal1", key2: value2', false) as any
|
||||||
expect(f.filters[0].name).to.equal('foo')
|
expect(f.filters[0].name).to.equal('foo')
|
||||||
expect(f.filters[0].args).to.eql([['key1', '"literal1"'], ['key2', 'value2']])
|
expect(f.filters[0].args).to.eql([['key1', '"literal1"'], ['key2', 'value2']])
|
||||||
})
|
})
|
||||||
it('should support arguments as named key/values with inline literals', function () {
|
it('should support arguments as named key/values with inline literals', function () {
|
||||||
const f = new Value('o | foo: "test0", key1: "literal1", key2: value2', false)
|
const f = new Value('o | foo: "test0", key1: "literal1", key2: value2', false) as any
|
||||||
expect(f.filters[0].name).to.equal('foo')
|
expect(f.filters[0].name).to.equal('foo')
|
||||||
expect(f.filters[0].args).to.deep.equal(['"test0"', ['key1', '"literal1"'], ['key2', 'value2']])
|
expect(f.filters[0].args).to.deep.equal(['"test0"', ['key1', '"literal1"'], ['key2', 'value2']])
|
||||||
})
|
})
|
||||||
it('should support arguments as named key/values with inline values', function () {
|
it('should support arguments as named key/values with inline values', function () {
|
||||||
const f = new Value('o | foo: test0, key1: "literal1", key2: value2', false)
|
const f = new Value('o | foo: test0, key1: "literal1", key2: value2', false) as any
|
||||||
expect(f.filters[0].name).to.equal('foo')
|
expect(f.filters[0].name).to.equal('foo')
|
||||||
expect(f.filters[0].args).to.deep.equal(['test0', ['key1', '"literal1"'], ['key2', 'value2']])
|
expect(f.filters[0].args).to.deep.equal(['test0', ['key1', '"literal1"'], ['key2', 'value2']])
|
||||||
})
|
})
|
||||||
it('should support argument values named same as keys', function () {
|
it('should support argument values named same as keys', function () {
|
||||||
const f = new Value('o | foo: a: a', false)
|
const f = new Value('o | foo: a: a', false) as any
|
||||||
expect(f.filters[0].name).to.equal('foo')
|
expect(f.filters[0].name).to.equal('foo')
|
||||||
expect(f.filters[0].args).to.deep.equal([['a', 'a']])
|
expect(f.filters[0].args).to.deep.equal([['a', 'a']])
|
||||||
})
|
})
|
||||||
it('should support argument literals named same as keys', function () {
|
it('should support argument literals named same as keys', function () {
|
||||||
const f = new Value('o | foo: a: "a"', false)
|
const f = new Value('o | foo: a: "a"', false) as any
|
||||||
expect(f.filters[0].name).to.equal('foo')
|
expect(f.filters[0].name).to.equal('foo')
|
||||||
expect(f.filters[0].args).to.deep.equal([['a', '"a"']])
|
expect(f.filters[0].args).to.deep.equal([['a', '"a"']])
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user