feat: implement liquid and echo tags, see #428

This commit is contained in:
James Prior
2021-12-19 21:09:26 +08:00
committed by Jun Yang
parent 5b2ea63b14
commit fde9924ee6
9 changed files with 243 additions and 1 deletions
+13
View File
@@ -0,0 +1,13 @@
import { Value } from '../../template/value'
import { Emitter } from '../../emitters/emitter'
import { TagImplOptions, TagToken, Context } from '../../types'
export default {
parse: function (token: TagToken) {
this.value = new Value(token.args, this.liquid)
},
render: function * (ctx: Context, emitter: Emitter): Generator<unknown, void, unknown> {
const val = yield this.value.value(ctx, false)
emitter.write(val)
}
} as TagImplOptions
+3 -1
View File
@@ -16,10 +16,12 @@ import tablerow from './tablerow'
import unless from './unless'
import Break from './break'
import Continue from './continue'
import echo from './echo'
import liquid from './liquid'
import { TagImplOptions } from '../../template/tag/tag-impl-options'
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
assign, 'for': For, capture, 'case': Case, comment, include, render, decrement, increment, cycle, 'if': If, layout, block, raw, tablerow, unless, 'break': Break, 'continue': Continue, echo, liquid
}
export default tags
+14
View File
@@ -0,0 +1,14 @@
import { Emitter } from '../../emitters/emitter'
import { TagImplOptions, TagToken, Context } from '../../types'
import { Tokenizer } from '../../parser/tokenizer'
export default {
parse: function (token: TagToken) {
const tokenizer = new Tokenizer(token.args, this.liquid.options.operatorsTrie)
const tokens = tokenizer.readLiquidTagTokens(this.liquid.options)
this.tpls = this.liquid.parser.parseTokens(tokens)
},
render: function * (ctx: Context, emitter: Emitter): Generator<unknown, void, unknown> {
yield this.liquid.renderer.renderTemplates(this.tpls, ctx, emitter)
}
} as TagImplOptions
+19
View File
@@ -24,6 +24,7 @@ import { TYPES, QUOTE, BLANK, IDENTIFIER } from '../util/character'
import { matchOperator } from './match-operator'
import { Trie } from '../util/operator-trie'
import { Expression } from '../render/expression'
import { LiquidTagToken } from '../tokens/liquid-tag-token'
export class Tokenizer {
p = 0
@@ -191,6 +192,24 @@ export class Tokenizer {
throw this.mkError(`raw ${this.snapshot(this.rawBeginAt)} not closed`, begin)
}
readLiquidTagTokens (options: NormalizedFullOptions = defaultOptions): LiquidTagToken[] {
const tokens: LiquidTagToken[] = []
while (this.p < this.N) {
const token = this.readLiquidTagToken(options)
if (token.name) tokens.push(token)
}
return tokens
}
readLiquidTagToken (options: NormalizedFullOptions): LiquidTagToken {
const { file, input } = this
const begin = this.p
let end = this.N
if (this.readToDelimiter('\n') !== -1) end = this.p
const token = new LiquidTagToken(input, begin, end, options, file)
return token
}
mkError (msg: string, begin: number) {
return new TokenizationError(msg, new IdentifierToken(this.input, begin, this.N, this.file))
}
+33
View File
@@ -0,0 +1,33 @@
import { DelimitedToken } from './delimited-token'
import { TokenizationError } from '../util/error'
import { NormalizedFullOptions } from '../liquid-options'
import { TokenKind } from '../parser/token-kind'
import { Tokenizer } from '../parser/tokenizer'
export class LiquidTagToken extends DelimitedToken {
public name: string
public args: string
public constructor (
input: string,
begin: number,
end: number,
options: NormalizedFullOptions,
file?: string
) {
const value = input.slice(begin, end)
super(TokenKind.Tag, value, input, begin, end, false, false, file)
if (!/\S/.test(value)) {
// A line that contains only whitespace.
this.name = ''
this.args = ''
} else {
const tokenizer = new Tokenizer(this.content, options.operatorsTrie)
this.name = tokenizer.readIdentifier().getText()
if (!this.name) throw new TokenizationError(`illegal liquid tag syntax`, this)
tokenizer.skipBlank()
this.args = tokenizer.remaining()
}
}
}