mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-18 05:50:43 -07:00
feat: move filters/tags to instances, fixes #188
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { identifier } from '../../parser/lexical'
|
||||
import { ITagImplOptions, TagToken, Context } from '../../types'
|
||||
import { TagImplOptions, TagToken, Context } from '../../types'
|
||||
|
||||
const re = new RegExp(`(${identifier.source})\\s*=([^]*)`)
|
||||
|
||||
@@ -14,4 +14,4 @@ export default {
|
||||
render: function * (ctx: Context) {
|
||||
ctx.front()[this.key] = yield this.liquid._evalValue(this.value, ctx)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import BlockMode from '../../context/block-mode'
|
||||
import { ParseStream, TagToken, Token, ITemplate, Context, ITagImplOptions, Emitter, Hash } from '../../types'
|
||||
import { ParseStream, TagToken, Token, Template, Context, TagImplOptions, Emitter, Hash } from '../../types'
|
||||
|
||||
export default {
|
||||
parse: function (token: TagToken, remainTokens: Token[]) {
|
||||
const match = /\w+/.exec(token.args)
|
||||
this.block = match ? match[0] : ''
|
||||
this.tpls = [] as ITemplate[]
|
||||
this.tpls = [] as Template[]
|
||||
const stream: ParseStream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('tag:endblock', () => stream.stop())
|
||||
.on('template', (tpl: ITemplate) => this.tpls.push(tpl))
|
||||
.on('template', (tpl: Template) => this.tpls.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${token.raw} not closed`)
|
||||
})
|
||||
@@ -28,4 +28,4 @@ export default {
|
||||
}
|
||||
emitter.write(html)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { identifier } from '../../parser/lexical'
|
||||
import { ITemplate, Context, ITagImplOptions, TagToken, Token } from '../../types'
|
||||
import { Template, Context, TagImplOptions, TagToken, Token } from '../../types'
|
||||
|
||||
const re = new RegExp(`(${identifier.source})`)
|
||||
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
stream.on('tag:endcapture', () => stream.stop())
|
||||
.on('template', (tpl: ITemplate) => this.templates.push(tpl))
|
||||
.on('template', (tpl: Template) => this.templates.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
@@ -25,4 +25,4 @@ export default {
|
||||
const html = yield r.renderTemplates(this.templates, ctx)
|
||||
ctx.front()[this.variable] = html
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Expression, Hash, Emitter, TagToken, Token, Context, ITemplate, ITagImplOptions, ParseStream } from '../../types'
|
||||
import { Expression, Hash, Emitter, TagToken, Token, Context, Template, TagImplOptions, ParseStream } from '../../types'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
@@ -6,7 +6,7 @@ export default {
|
||||
this.cases = []
|
||||
this.elseTemplates = []
|
||||
|
||||
let p: ITemplate[] = []
|
||||
let p: Template[] = []
|
||||
const stream: ParseStream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('tag:when', (token: TagToken) => {
|
||||
this.cases.push({
|
||||
@@ -16,7 +16,7 @@ export default {
|
||||
})
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endcase', () => stream.stop())
|
||||
.on('template', (tpl: ITemplate) => p.push(tpl))
|
||||
.on('template', (tpl: Template) => p.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
@@ -37,4 +37,4 @@ export default {
|
||||
}
|
||||
yield r.renderTemplates(this.elseTemplates, ctx, emitter)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TagToken } from '../../parser/tag-token'
|
||||
import { Token } from '../../parser/token'
|
||||
import { ITagImplOptions } from '../../template/tag/itag-impl-options'
|
||||
import { TagImplOptions } from '../../template/tag/tag-impl-options'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
@@ -14,4 +14,4 @@ export default {
|
||||
})
|
||||
stream.start()
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { value as rValue } from '../../parser/lexical'
|
||||
import { Emitter, Expression, TagToken, Context, ITagImplOptions, Hash } from '../../types'
|
||||
import { Emitter, Expression, TagToken, Context, TagImplOptions, Hash } from '../../types'
|
||||
|
||||
const groupRE = new RegExp(`^(?:(${rValue.source})\\s*:\\s*)?(.*)$`)
|
||||
const candidatesRE = new RegExp(rValue.source, 'g')
|
||||
@@ -37,4 +37,4 @@ export default {
|
||||
const html = yield new Expression(candidate).value(ctx)
|
||||
emitter.write(html)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { identifier } from '../../parser/lexical'
|
||||
import { Emitter, TagToken, Context, ITagImplOptions, Hash } from '../../types'
|
||||
import { Emitter, TagToken, Context, TagImplOptions, Hash } from '../../types'
|
||||
import { isNumber, stringify } from '../../util/underscore'
|
||||
|
||||
export default {
|
||||
@@ -16,4 +16,4 @@ export default {
|
||||
}
|
||||
emitter.write(stringify(--scope[this.variable]))
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Emitter, TagToken, Token, Context, ITemplate, ITagImplOptions, ParseStream } from '../../types'
|
||||
import { Emitter, TagToken, Token, Context, Template, TagImplOptions, ParseStream } from '../../types'
|
||||
import { isString, isObject, isArray } from '../../util/underscore'
|
||||
import { Expression } from '../../render/expression'
|
||||
import { assert } from '../../util/assert'
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
.on('start', () => (p = this.templates))
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endfor', () => stream.stop())
|
||||
.on('template', (tpl: ITemplate) => p.push(tpl))
|
||||
.on('template', (tpl: Template) => p.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
@@ -72,4 +72,4 @@ export default {
|
||||
}
|
||||
ctx.pop()
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Hash, Emitter, isTruthy, Expression, TagToken, Token, Context, ITemplate, ITagImplOptions, ParseStream } from '../../types'
|
||||
import { Hash, Emitter, isTruthy, Expression, TagToken, Token, Context, Template, TagImplOptions, ParseStream } from '../../types'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
})
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endif', () => stream.stop())
|
||||
.on('template', (tpl: ITemplate) => p.push(tpl))
|
||||
.on('template', (tpl: Template) => p.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
@@ -39,4 +39,4 @@ export default {
|
||||
}
|
||||
yield r.renderTemplates(this.elseTemplates, ctx, emitter)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { Expression, Hash, Emitter, TagToken, Context, ITagImplOptions } from '../../types'
|
||||
import { Expression, Hash, Emitter, TagToken, Context, TagImplOptions } from '../../types'
|
||||
import { value, quotedLine } from '../../parser/lexical'
|
||||
import BlockMode from '../../context/block-mode'
|
||||
|
||||
@@ -46,4 +46,4 @@ export default {
|
||||
ctx.setRegister('blocks', originBlocks)
|
||||
ctx.setRegister('blockMode', originBlockMode)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { identifier } from '../../parser/lexical'
|
||||
import { isNumber, stringify } from '../../util/underscore'
|
||||
import { Emitter, TagToken, Context, ITagImplOptions, Hash } from '../../types'
|
||||
import { Emitter, TagToken, Context, TagImplOptions, Hash } from '../../types'
|
||||
|
||||
export default {
|
||||
parse: function (token: TagToken) {
|
||||
@@ -18,4 +18,4 @@ export default {
|
||||
scope[this.variable]++
|
||||
emitter.write(stringify(val))
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -16,9 +16,9 @@ import tablerow from './tablerow'
|
||||
import unless from './unless'
|
||||
import Break from './break'
|
||||
import Continue from './continue'
|
||||
import { ITagImplOptions } from '../../template/tag/itag-impl-options'
|
||||
import { TagImplOptions } from '../../template/tag/tag-impl-options'
|
||||
|
||||
const tags: { [key: string]: ITagImplOptions } = {
|
||||
const tags: { [key: string]: TagImplOptions } = {
|
||||
assign, 'for': For, capture, 'case': Case, comment, include, render, decrement, increment, cycle, 'if': If, layout, block, raw, tablerow, unless, 'break': Break, 'continue': Continue
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { value as rValue } from '../../parser/lexical'
|
||||
import { Emitter, Hash, Expression, TagToken, Token, Context, ITagImplOptions } from '../../types'
|
||||
import { Emitter, Hash, Expression, TagToken, Token, Context, TagImplOptions } from '../../types'
|
||||
import BlockMode from '../../context/block-mode'
|
||||
|
||||
const staticFileRE = /\S+/
|
||||
@@ -40,4 +40,4 @@ export default {
|
||||
ctx.pop()
|
||||
emitter.write(partial)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TagToken, Token, ITagImplOptions } from '../../types'
|
||||
import { TagToken, Token, TagImplOptions } from '../../types'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
@@ -18,4 +18,4 @@ export default {
|
||||
render: function () {
|
||||
return this.tokens.map((token: Token) => token.raw).join('')
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { Expression, Hash, Emitter, TagToken, Context, ITagImplOptions } from '../../types'
|
||||
import { Expression, Hash, Emitter, TagToken, Context, TagImplOptions } from '../../types'
|
||||
import { value, quotedLine } from '../../parser/lexical'
|
||||
import BlockMode from '../../context/block-mode'
|
||||
|
||||
@@ -47,4 +47,4 @@ export default {
|
||||
childCtx.setRegister('blocks', originBlocks)
|
||||
childCtx.setRegister('blockMode', originBlockMode)
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { assert } from '../../util/assert'
|
||||
import { Expression, Emitter, Hash, TagToken, Token, Context, ITemplate, ITagImplOptions, ParseStream } from '../../types'
|
||||
import { Expression, Emitter, Hash, TagToken, Token, Context, Template, TagImplOptions, ParseStream } from '../../types'
|
||||
import { identifier, value, hash } from '../../parser/lexical'
|
||||
import { TablerowloopDrop } from '../../drop/tablerowloop-drop'
|
||||
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
const stream: ParseStream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('start', () => (p = this.templates))
|
||||
.on('tag:endtablerow', () => stream.stop())
|
||||
.on('template', (tpl: ITemplate) => p.push(tpl))
|
||||
.on('template', (tpl: Template) => p.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
@@ -54,4 +54,4 @@ export default {
|
||||
if (collection.length) emitter.write('</tr>')
|
||||
ctx.pop()
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Emitter, Expression, isFalsy, ParseStream, Context, ITagImplOptions, Token, Hash, TagToken } from '../../types'
|
||||
import { Emitter, Expression, isFalsy, ParseStream, Context, TagImplOptions, Token, Hash, TagToken } from '../../types'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
@@ -27,4 +27,4 @@ export default {
|
||||
? r.renderTemplates(this.templates, ctx, emitter)
|
||||
: r.renderTemplates(this.elseTemplates, ctx, emitter))
|
||||
}
|
||||
} as ITagImplOptions
|
||||
} as TagImplOptions
|
||||
|
||||
+22
-18
@@ -1,16 +1,16 @@
|
||||
import { Context } from './context/context'
|
||||
import fs from './fs/node'
|
||||
import * as _ from './util/underscore'
|
||||
import { ITemplate } from './template/itemplate'
|
||||
import { Template } from './template/template'
|
||||
import { Tokenizer } from './parser/tokenizer'
|
||||
import { Render } from './render/render'
|
||||
import { Tag } from './template/tag/tag'
|
||||
import { Filter } from './template/filter/filter'
|
||||
import Parser from './parser/parser'
|
||||
import { ITagImplOptions } from './template/tag/itag-impl-options'
|
||||
import { TagImplOptions } from './template/tag/tag-impl-options'
|
||||
import { Value } from './template/value'
|
||||
import builtinTags from './builtin/tags'
|
||||
import builtinFilters from './builtin/filters'
|
||||
import { TagMap } from './template/tag/tag-map'
|
||||
import { FilterMap } from './template/filter/filter-map'
|
||||
import { LiquidOptions, normalizeStringArray, NormalizedFullOptions, applyDefault, normalize } from './liquid-options'
|
||||
import { FilterImplOptions } from './template/filter/filter-impl-options'
|
||||
import IFS from './fs/ifs'
|
||||
@@ -22,6 +22,8 @@ export class Liquid {
|
||||
public options: NormalizedFullOptions
|
||||
public renderer: Render
|
||||
public parser: Parser
|
||||
public filters: FilterMap
|
||||
public tags: TagMap
|
||||
private cache: object = {}
|
||||
private tokenizer: Tokenizer
|
||||
private fs: IFS
|
||||
@@ -32,24 +34,26 @@ export class Liquid {
|
||||
this.renderer = new Render()
|
||||
this.tokenizer = new Tokenizer(this.options)
|
||||
this.fs = opts.fs || fs
|
||||
this.filters = new FilterMap(this.options.strictFilters)
|
||||
this.tags = new TagMap()
|
||||
|
||||
_.forOwn(builtinTags, (conf, name) => this.registerTag(name, conf))
|
||||
_.forOwn(builtinFilters, (handler, name) => this.registerFilter(name, handler))
|
||||
}
|
||||
public parse (html: string, filepath?: string): ITemplate[] {
|
||||
public parse (html: string, filepath?: string): Template[] {
|
||||
const tokens = this.tokenizer.tokenize(html, filepath)
|
||||
return this.parser.parse(tokens)
|
||||
}
|
||||
|
||||
public _render (tpl: ITemplate[], scope?: object, opts?: LiquidOptions, sync?: boolean): IterableIterator<string> {
|
||||
public _render (tpl: Template[], scope?: object, opts?: LiquidOptions, sync?: boolean): IterableIterator<string> {
|
||||
const options = { ...this.options, ...normalize(opts) }
|
||||
const ctx = new Context(scope, options, sync)
|
||||
return this.renderer.renderTemplates(tpl, ctx)
|
||||
}
|
||||
public async render (tpl: ITemplate[], scope?: object, opts?: LiquidOptions): Promise<string> {
|
||||
public async render (tpl: Template[], scope?: object, opts?: LiquidOptions): Promise<string> {
|
||||
return toThenable(this._render(tpl, scope, opts, false))
|
||||
}
|
||||
public renderSync (tpl: ITemplate[], scope?: object, opts?: LiquidOptions): string {
|
||||
public renderSync (tpl: Template[], scope?: object, opts?: LiquidOptions): string {
|
||||
return toValue(this._render(tpl, scope, opts, true))
|
||||
}
|
||||
|
||||
@@ -80,10 +84,10 @@ export class Liquid {
|
||||
}
|
||||
throw this.lookupError(file, options.root)
|
||||
}
|
||||
public async parseFile (file: string, opts?: LiquidOptions): Promise<ITemplate[]> {
|
||||
public async parseFile (file: string, opts?: LiquidOptions): Promise<Template[]> {
|
||||
return toThenable(this._parseFile(file, opts, false))
|
||||
}
|
||||
public parseFileSync (file: string, opts?: LiquidOptions): ITemplate[] {
|
||||
public parseFileSync (file: string, opts?: LiquidOptions): Template[] {
|
||||
return toValue(this._parseFile(file, opts, true))
|
||||
}
|
||||
public async renderFile (file: string, ctx?: object, opts?: LiquidOptions) {
|
||||
@@ -97,7 +101,7 @@ export class Liquid {
|
||||
}
|
||||
|
||||
public _evalValue (str: string, ctx: Context): IterableIterator<any> {
|
||||
const value = new Value(str, this.options.strictFilters)
|
||||
const value = new Value(str, this.filters)
|
||||
return value.value(ctx)
|
||||
}
|
||||
public async evalValue (str: string, ctx: Context): Promise<any> {
|
||||
@@ -108,19 +112,19 @@ export class Liquid {
|
||||
}
|
||||
|
||||
public registerFilter (name: string, filter: FilterImplOptions) {
|
||||
return Filter.register(name, filter)
|
||||
this.filters.set(name, filter)
|
||||
}
|
||||
public registerTag (name: string, tag: ITagImplOptions) {
|
||||
return Tag.register(name, tag)
|
||||
public registerTag (name: string, tag: TagImplOptions) {
|
||||
this.tags.set(name, tag)
|
||||
}
|
||||
public plugin (plugin: (this: Liquid, L: typeof Liquid) => void) {
|
||||
return plugin.call(this, Liquid)
|
||||
}
|
||||
public express () {
|
||||
const self = this // eslint-disable-line
|
||||
return function (this: any, filePath: string, ctx: object, cb: (err: Error | null, html?: string) => void) {
|
||||
return function (this: any, filePath: string, ctx: object, callback: (err: Error | null, rendered: string) => void) {
|
||||
const opts = { root: [...normalizeStringArray(this.root), ...self.options.root] }
|
||||
self.renderFile(filePath, ctx, opts).then(html => cb(null, html), cb)
|
||||
self.renderFile(filePath, ctx, opts).then(html => callback(null, html) as any, callback as any)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,13 +138,13 @@ export class Liquid {
|
||||
/**
|
||||
* @deprecated use parseFile instead
|
||||
*/
|
||||
public async getTemplate (file: string, opts?: LiquidOptions): Promise<ITemplate[]> {
|
||||
public async getTemplate (file: string, opts?: LiquidOptions): Promise<Template[]> {
|
||||
return this.parseFile(file, opts)
|
||||
}
|
||||
/**
|
||||
* @deprecated use parseFileSync instead
|
||||
*/
|
||||
public getTemplateSync (file: string, opts?: LiquidOptions): ITemplate[] {
|
||||
public getTemplateSync (file: string, opts?: LiquidOptions): Template[] {
|
||||
return this.parseFileSync(file, opts)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Token } from '../parser/token'
|
||||
import { ITemplate } from '../template/itemplate'
|
||||
import { Template } from '../template/template'
|
||||
import { TagToken } from './tag-token'
|
||||
|
||||
type ParseToken = ((token: Token, remainTokens: Token[]) => ITemplate)
|
||||
type ParseToken = ((token: Token, remainTokens: Token[]) => Template)
|
||||
|
||||
export class ParseStream {
|
||||
private tokens: Token[]
|
||||
@@ -14,11 +14,11 @@ export class ParseStream {
|
||||
this.tokens = tokens
|
||||
this.parseToken = parseToken
|
||||
}
|
||||
public on<T extends ITemplate | Token | undefined> (name: string, cb: (arg: T) => void): ParseStream {
|
||||
public on<T extends Template | Token | undefined> (name: string, cb: (arg: T) => void): ParseStream {
|
||||
this.handlers[name] = cb
|
||||
return this
|
||||
}
|
||||
private trigger <T extends Token | ITemplate> (event: string, arg?: T) {
|
||||
private trigger <T extends Token | Template> (event: string, arg?: T) {
|
||||
const h = this.handlers[event]
|
||||
return h ? (h(arg), true) : false
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { OutputToken } from './output-token'
|
||||
import { Tag } from '../template/tag/tag'
|
||||
import { Output } from '../template/output'
|
||||
import { HTML } from '../template/html'
|
||||
import { ITemplate } from '../template/itemplate'
|
||||
import { Template } from '../template/template'
|
||||
|
||||
export default class Parser {
|
||||
private liquid: Liquid
|
||||
@@ -17,7 +17,7 @@ export default class Parser {
|
||||
}
|
||||
public parse (tokens: Token[]) {
|
||||
let token
|
||||
const templates: ITemplate[] = []
|
||||
const templates: Template[] = []
|
||||
while ((token = tokens.shift())) {
|
||||
templates.push(this.parseToken(token, tokens))
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export default class Parser {
|
||||
return new Tag(token, remainTokens, this.liquid)
|
||||
}
|
||||
if (OutputToken.is(token)) {
|
||||
return new Output(token as OutputToken, this.liquid.options.strictFilters)
|
||||
return new Output(token as OutputToken, this.liquid.filters)
|
||||
}
|
||||
return new HTML(token)
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { RenderError } from '../util/error'
|
||||
import { Context } from '../context/context'
|
||||
import { ITemplate } from '../template/itemplate'
|
||||
import { Template } from '../template/template'
|
||||
import { Emitter } from './emitter'
|
||||
|
||||
export class Render {
|
||||
public * renderTemplates (templates: ITemplate[], ctx: Context, emitter = new Emitter()): IterableIterator<string> {
|
||||
public * renderTemplates (templates: Template[], ctx: Context, emitter = new Emitter()): IterableIterator<string> {
|
||||
for (const tpl of templates) {
|
||||
try {
|
||||
const html = yield tpl.render(ctx, emitter)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { FilterImplOptions } from './filter-impl-options'
|
||||
import { Filter, FilterArgs } from './filter'
|
||||
import { assert } from '../../util/assert'
|
||||
|
||||
export class FilterMap {
|
||||
private impls: {[key: string]: FilterImplOptions} = {}
|
||||
|
||||
constructor (private readonly strictFilters: boolean) {}
|
||||
|
||||
get (name: string) {
|
||||
const impl = this.impls[name]
|
||||
assert(impl || !this.strictFilters, `undefined filter: ${name}`)
|
||||
return impl
|
||||
}
|
||||
|
||||
set (name: string, impl: FilterImplOptions) {
|
||||
this.impls[name] = impl
|
||||
}
|
||||
|
||||
create (name: string, args: FilterArgs) {
|
||||
return new Filter(name, this.get(name), args)
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,8 @@ export class Filter {
|
||||
public name: string
|
||||
public args: FilterArgs
|
||||
private impl: FilterImplOptions
|
||||
private static impls: {[key: string]: FilterImplOptions} = {}
|
||||
|
||||
public constructor (name: string, args: FilterArgs, strictFilters: boolean) {
|
||||
const impl = Filter.impls[name]
|
||||
if (!impl && strictFilters) throw new TypeError(`undefined filter: ${name}`)
|
||||
|
||||
public constructor (name: string, impl: FilterImplOptions, args: FilterArgs) {
|
||||
this.name = name
|
||||
this.impl = impl || identify
|
||||
this.args = args
|
||||
@@ -29,12 +25,6 @@ export class Filter {
|
||||
}
|
||||
return this.impl.apply({ context }, [value, ...argv])
|
||||
}
|
||||
public static register (name: string, filter: FilterImplOptions) {
|
||||
Filter.impls[name] = filter
|
||||
}
|
||||
public static clear () {
|
||||
Filter.impls = {}
|
||||
}
|
||||
}
|
||||
|
||||
function isKeyValuePair (arr: FilterArg): arr is KeyValuePair {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { TemplateImpl } from '../template/template-impl'
|
||||
import { Template } from '../template/template'
|
||||
import { ITemplate } from '../template/itemplate'
|
||||
import { HTMLToken } from '../parser/html-token'
|
||||
import { Context } from '../context/context'
|
||||
import { Emitter } from '../render/emitter'
|
||||
|
||||
export class HTML extends Template<HTMLToken> implements ITemplate {
|
||||
export class HTML extends TemplateImpl<HTMLToken> implements Template {
|
||||
private str: string
|
||||
public constructor (token: HTMLToken) {
|
||||
super(token)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Context } from '../context/context'
|
||||
import { Token } from '../parser/token'
|
||||
import { Emitter } from '../render/emitter'
|
||||
|
||||
export interface ITemplate {
|
||||
token: Token;
|
||||
render(ctx: Context, emitter: Emitter): any;
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Value } from './value'
|
||||
import { FilterMap } from './filter/filter-map'
|
||||
import { stringify, toValue } from '../util/underscore'
|
||||
import { TemplateImpl } from '../template/template-impl'
|
||||
import { Template } from '../template/template'
|
||||
import { ITemplate } from '../template/itemplate'
|
||||
import { Context } from '../context/context'
|
||||
import { Emitter } from '../render/emitter'
|
||||
import { OutputToken } from '../parser/output-token'
|
||||
|
||||
export class Output extends Template<OutputToken> implements ITemplate {
|
||||
export class Output extends TemplateImpl<OutputToken> implements Template {
|
||||
private value: Value
|
||||
public constructor (token: OutputToken, strictFilters: boolean) {
|
||||
public constructor (token: OutputToken, filters: FilterMap) {
|
||||
super(token)
|
||||
this.value = new Value(token.value, strictFilters)
|
||||
this.value = new Value(token.value, filters)
|
||||
}
|
||||
public * render (ctx: Context, emitter: Emitter) {
|
||||
const val = yield this.value.value(ctx)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Liquid } from '../../liquid'
|
||||
import { ITagImplOptions } from './itag-impl-options'
|
||||
|
||||
export interface ITagImpl extends ITagImplOptions {
|
||||
liquid: Liquid;
|
||||
[key: string]: any;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Context } from '../../context/context'
|
||||
import { TagToken } from '../../parser/tag-token'
|
||||
import { Token } from '../../parser/token'
|
||||
import { ITagImpl } from './itag-impl'
|
||||
import { TagImpl } from './tag-impl'
|
||||
import { Hash } from '../../template/tag/hash'
|
||||
import { Emitter } from '../../render/emitter'
|
||||
|
||||
export interface ITagImplOptions {
|
||||
parse?: (this: ITagImpl, token: TagToken, remainingTokens: Token[]) => void;
|
||||
render: (this: ITagImpl, ctx: Context, hash: Hash, emitter: Emitter) => any;
|
||||
export interface TagImplOptions {
|
||||
parse?: (this: TagImpl, token: TagToken, remainingTokens: Token[]) => void;
|
||||
render: (this: TagImpl, ctx: Context, hash: Hash, emitter: Emitter) => any;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Liquid } from '../../liquid'
|
||||
import { TagImplOptions } from './tag-impl-options'
|
||||
|
||||
export interface TagImpl extends TagImplOptions {
|
||||
liquid: Liquid;
|
||||
[key: string]: any;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TagImplOptions } from './tag-impl-options'
|
||||
import { assert } from '../../util/assert'
|
||||
|
||||
export class TagMap {
|
||||
private impls: {[key: string]: TagImplOptions} = {}
|
||||
|
||||
get (name: string) {
|
||||
const impl = this.impls[name]
|
||||
assert(impl, `tag "${name}" not found`)
|
||||
return impl
|
||||
}
|
||||
|
||||
set (name: string, impl: TagImplOptions) {
|
||||
this.impls[name] = impl
|
||||
}
|
||||
}
|
||||
+7
-15
@@ -1,21 +1,19 @@
|
||||
import { isFunction } from '../../util/underscore'
|
||||
import { assert } from '../../util/assert'
|
||||
import { Liquid } from '../../liquid'
|
||||
import { Template } from '../../template/template'
|
||||
import { Emitter, Hash, Context, ITagImplOptions, TagToken, ITemplate, Token } from '../../types'
|
||||
import { ITagImpl } from './itag-impl'
|
||||
import { TemplateImpl } from '../../template/template-impl'
|
||||
import { Emitter, Hash, Context, TagImplOptions, TagToken, Template, Token } from '../../types'
|
||||
import { TagImpl } from './tag-impl'
|
||||
|
||||
export class Tag extends Template<TagToken> implements ITemplate {
|
||||
export class Tag extends TemplateImpl<TagToken> implements Template {
|
||||
public name: string
|
||||
private impl: ITagImpl
|
||||
private static impls: { [key: string]: ITagImplOptions } = {}
|
||||
private impl: TagImpl
|
||||
private static impls: { [key: string]: TagImplOptions } = {}
|
||||
|
||||
public constructor (token: TagToken, tokens: Token[], liquid: Liquid) {
|
||||
super(token)
|
||||
this.name = token.name
|
||||
|
||||
const impl = Tag.impls[token.name]
|
||||
assert(impl, `tag ${token.name} not found`)
|
||||
const impl = liquid.tags.get(token.name)
|
||||
|
||||
this.impl = Object.create(impl)
|
||||
this.impl.liquid = liquid
|
||||
@@ -28,10 +26,4 @@ export class Tag extends Template<TagToken> implements ITemplate {
|
||||
const impl = this.impl
|
||||
if (isFunction(impl.render)) return yield impl.render(ctx, hash, emitter)
|
||||
}
|
||||
public static register (name: string, tag: ITagImplOptions) {
|
||||
Tag.impls[name] = tag
|
||||
}
|
||||
public static clear () {
|
||||
Tag.impls = {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export abstract class TemplateImpl<T> {
|
||||
public token: T;
|
||||
public constructor (token: T) {
|
||||
this.token = token
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
export abstract class Template<T> {
|
||||
public token: T;
|
||||
public constructor (token: T) {
|
||||
this.token = token
|
||||
}
|
||||
import { Context } from '../context/context'
|
||||
import { Token } from '../parser/token'
|
||||
import { Emitter } from '../render/emitter'
|
||||
|
||||
export interface Template {
|
||||
token: Token;
|
||||
render(ctx: Context, emitter: Emitter): any;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { Expression } from '../render/expression'
|
||||
import { FilterMap } from '../template/filter/filter-map'
|
||||
import { FilterArgs, Filter } from './filter/filter'
|
||||
import { Context } from '../context/context'
|
||||
|
||||
export class Value {
|
||||
public readonly filters: Filter[] = []
|
||||
public readonly initial: string
|
||||
private strictFilters: boolean
|
||||
|
||||
/**
|
||||
* @param str value string, like: "i have a dream | truncate: 3
|
||||
*/
|
||||
public constructor (str: string, strictFilters: boolean) {
|
||||
public constructor (str: string, private readonly filterMap: FilterMap) {
|
||||
const tokens = Value.tokenize(str)
|
||||
this.strictFilters = strictFilters
|
||||
this.initial = tokens[0]
|
||||
this.parseFilters(tokens, 1)
|
||||
}
|
||||
@@ -45,7 +44,7 @@ export class Value {
|
||||
argValue = tokens[i]
|
||||
}
|
||||
}
|
||||
this.filters.push(new Filter(name, args, this.strictFilters))
|
||||
this.filters.push(new Filter(name, this.filterMap.get(name), args))
|
||||
}
|
||||
public * value (ctx: Context) {
|
||||
let val = yield new Expression(this.initial).evaluate(ctx)
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@ export { Expression } from './render/expression'
|
||||
export { isFalsy, isTruthy } from './render/boolean'
|
||||
export { TagToken } from './parser/tag-token'
|
||||
export { Context } from './context/context'
|
||||
export { ITemplate } from './template/itemplate'
|
||||
export { ITagImplOptions } from './template/tag/itag-impl-options'
|
||||
export { Template } from './template/template'
|
||||
export { TagImplOptions } from './template/tag/tag-impl-options'
|
||||
export { ParseStream } from './parser/parse-stream'
|
||||
export { Token } from './parser/token'
|
||||
export { Hash } from './template/tag/hash'
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import * as _ from './underscore'
|
||||
import { Token } from '../parser/token'
|
||||
import { ITemplate } from '../template/itemplate'
|
||||
import { Template } from '../template/template'
|
||||
|
||||
abstract class LiquidError extends Error {
|
||||
private token: Token
|
||||
@@ -37,7 +37,7 @@ export class ParseError extends LiquidError {
|
||||
}
|
||||
|
||||
export class RenderError extends LiquidError {
|
||||
public constructor (err: Error, tpl: ITemplate) {
|
||||
public constructor (err: Error, tpl: Template) {
|
||||
super(err, tpl.token)
|
||||
this.name = 'RenderError'
|
||||
this.message = err.message
|
||||
|
||||
Reference in New Issue
Block a user