mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 04:10:40 -07:00
chore(TypeScript): fix linting and generate .d.ts
This commit is contained in:
@@ -25,5 +25,5 @@ export default {
|
||||
'escape': escape,
|
||||
'escape_once': str => escape(unescape(str)),
|
||||
'newline_to_br': v => v.replace(/\n/g, '<br />'),
|
||||
'strip_html': v => String(v).replace(/<script.*?<\/script>|<!--.*?-->|<style.*?<\/style>|<.*?>/g, ''),
|
||||
'strip_html': v => String(v).replace(/<script.*?<\/script>|<!--.*?-->|<style.*?<\/style>|<.*?>/g, '')
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
return Math.round(v * amp) / amp
|
||||
},
|
||||
'plus': bindFixed((v, arg) => Number(v) + Number(arg)),
|
||||
'times': (v, arg) => v * arg,
|
||||
'times': (v, arg) => v * arg
|
||||
}
|
||||
|
||||
function getFixed (v) {
|
||||
|
||||
@@ -28,5 +28,5 @@ export default {
|
||||
let ret = arr.slice(0, l).join(' ')
|
||||
if (arr.length > l) ret += o
|
||||
return ret
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RenderBreakError } from 'src/util/error'
|
||||
|
||||
export default {
|
||||
render: async function (scope) {
|
||||
render: async function () {
|
||||
throw new RenderBreakError('break')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import assert from 'src/util/assert'
|
||||
import { identifier } from 'src/parser/lexical'
|
||||
import { CaptureScope } from 'src/scope/scopes'
|
||||
import TagToken from 'src/parser/tag-token'
|
||||
import Token from 'src/parser/token'
|
||||
import Scope from 'src/scope/scope'
|
||||
|
||||
const re = new RegExp(`(${identifier.source})`)
|
||||
|
||||
export default {
|
||||
parse: function (tagToken, remainTokens) {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
const match = tagToken.args.match(re)
|
||||
assert(match, `${tagToken.args} not valid identifier`)
|
||||
|
||||
@@ -13,14 +16,14 @@ export default {
|
||||
this.templates = []
|
||||
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
stream.on('tag:endcapture', token => stream.stop())
|
||||
stream.on('tag:endcapture', () => stream.stop())
|
||||
.on('template', tpl => this.templates.push(tpl))
|
||||
.on('end', x => {
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
stream.start()
|
||||
},
|
||||
render: async function (scope, hash) {
|
||||
render: async function (scope: Scope) {
|
||||
const html = await this.liquid.renderer.renderTemplates(this.templates, scope)
|
||||
const ctx = new CaptureScope()
|
||||
ctx[this.variable] = html
|
||||
|
||||
@@ -15,16 +15,16 @@ export default {
|
||||
})
|
||||
})
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endcase', token => stream.stop())
|
||||
.on('tag:endcase', () => stream.stop())
|
||||
.on('template', tpl => p.push(tpl))
|
||||
.on('end', x => {
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
|
||||
stream.start()
|
||||
},
|
||||
|
||||
render: function (scope, hash) {
|
||||
render: function (scope) {
|
||||
for (let i = 0; i < this.cases.length; i++) {
|
||||
const branch = this.cases[i]
|
||||
const val = evalExp(branch.val, scope)
|
||||
|
||||
@@ -5,7 +5,7 @@ export default {
|
||||
.on('token', token => {
|
||||
if (token.name === 'endcomment') stream.stop()
|
||||
})
|
||||
.on('end', x => {
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
stream.start()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RenderBreakError } from 'src/util/error'
|
||||
|
||||
export default {
|
||||
render: async function (scope) {
|
||||
render: async function () {
|
||||
throw new RenderBreakError('continue')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ const groupRE = new RegExp(`^(?:(${rValue.source})\\s*:\\s*)?(.*)$`)
|
||||
const candidatesRE = new RegExp(rValue.source, 'g')
|
||||
|
||||
export default {
|
||||
parse: function (tagToken, remainTokens) {
|
||||
parse: function (tagToken) {
|
||||
let match = groupRE.exec(tagToken.args)
|
||||
assert(match, `illegal tag: ${tagToken.raw}`)
|
||||
|
||||
@@ -21,7 +21,7 @@ export default {
|
||||
assert(this.candidates.length, `empty candidates: ${tagToken.raw}`)
|
||||
},
|
||||
|
||||
render: function (scope, hash) {
|
||||
render: function (scope) {
|
||||
const group = evalValue(this.group, scope)
|
||||
const fingerprint = `cycle:${group}:` + this.candidates.join(',')
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import assert from 'src/util/assert'
|
||||
import { identifier } from 'src/parser/lexical'
|
||||
import { CaptureScope, AssignScope, DecrementScope } from 'src/scope/scopes'
|
||||
import TagToken from 'src/parser/tag-token'
|
||||
import Scope from 'src/scope/scope'
|
||||
|
||||
export default {
|
||||
parse: function (token) {
|
||||
parse: function (token: TagToken) {
|
||||
const match = token.args.match(identifier)
|
||||
assert(match, `illegal identifier ${token.args}`)
|
||||
this.variable = match[0]
|
||||
},
|
||||
render: function (scope, hash) {
|
||||
render: function (scope: Scope) {
|
||||
let context = scope.findContextFor(
|
||||
this.variable,
|
||||
ctx => {
|
||||
|
||||
@@ -18,16 +18,16 @@ export default {
|
||||
})
|
||||
})
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endif', token => stream.stop())
|
||||
.on('tag:endif', () => stream.stop())
|
||||
.on('template', tpl => p.push(tpl))
|
||||
.on('end', x => {
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
|
||||
stream.start()
|
||||
},
|
||||
|
||||
render: function (scope, hash) {
|
||||
render: function (scope) {
|
||||
for (const branch of this.branches) {
|
||||
const cond = evalExp(branch.cond, scope)
|
||||
if (isTruthy(cond)) {
|
||||
|
||||
@@ -8,7 +8,7 @@ export default {
|
||||
assert(match, `illegal identifier ${token.args}`)
|
||||
this.variable = match[0]
|
||||
},
|
||||
render: function (scope, hash) {
|
||||
render: function (scope) {
|
||||
let context = scope.findContextFor(
|
||||
this.variable,
|
||||
ctx => {
|
||||
|
||||
@@ -15,7 +15,10 @@ import tablerow from './tablerow'
|
||||
import unless from './unless'
|
||||
import Break from './break'
|
||||
import Continue from './continue'
|
||||
import ITagImplOptions from 'src/template/tag/itag-impl-options'
|
||||
|
||||
export default {
|
||||
const tags: { [key: string]: ITagImplOptions } = {
|
||||
assign, 'for': For, capture, 'case': Case, comment, include, decrement, increment, cycle, 'if': If, layout, block, raw, tablerow, unless, 'break': Break, 'continue': Continue
|
||||
}
|
||||
|
||||
export default tags
|
||||
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
})
|
||||
stream.start()
|
||||
},
|
||||
render: function (scope, hash) {
|
||||
render: function () {
|
||||
return this.tokens.map(token => token.raw).join('')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
let p
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('start', () => (p = this.templates))
|
||||
.on('tag:endtablerow', token => stream.stop())
|
||||
.on('tag:endtablerow', () => stream.stop())
|
||||
.on('template', tpl => p.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
@@ -35,7 +35,7 @@ export default {
|
||||
|
||||
collection = collection.slice(offset, offset + limit)
|
||||
const cols = hash.cols || collection.length
|
||||
const contexts = collection.map((item, i) => {
|
||||
const contexts = collection.map(item => {
|
||||
const ctx = {}
|
||||
ctx[this.variable] = item
|
||||
return ctx
|
||||
|
||||
@@ -6,21 +6,21 @@ export default {
|
||||
this.elseTemplates = []
|
||||
let p
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('start', x => {
|
||||
.on('start', () => {
|
||||
p = this.templates
|
||||
this.cond = tagToken.args
|
||||
})
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endunless', token => stream.stop())
|
||||
.on('tag:endunless', () => stream.stop())
|
||||
.on('template', tpl => p.push(tpl))
|
||||
.on('end', x => {
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
|
||||
stream.start()
|
||||
},
|
||||
|
||||
render: function (scope, hash) {
|
||||
render: function (scope) {
|
||||
const cond = evalExp(this.cond, scope)
|
||||
return isFalsy(cond)
|
||||
? this.liquid.renderer.renderTemplates(this.templates, scope)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface LiquidOptions {
|
||||
/** `root` is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling `.renderFile()`. If an array, the files are looked up in the order they occur in the array. Defaults to `["."]`*/
|
||||
/** `root` is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling `.renderFile()`. If an array, the files are looked up in the order they occur in the array. Defaults to `["."]` */
|
||||
root?: string | string[]
|
||||
/** `extname` is used to lookup the template file when filepath doesn't include an extension name. Eg: setting to `".html"` will allow including file by basename. Defaults to `""`. */
|
||||
extname?: string
|
||||
@@ -8,17 +8,17 @@ export interface LiquidOptions {
|
||||
/** `dynamicPartials`: if set, treat `<filepath>` parameter in `{%include filepath %}`, `{%layout filepath%}` as a variable, otherwise as a literal value. Defaults to `true`. */
|
||||
dynamicPartials?: boolean
|
||||
/** `strict_filters` is used to enable strict filter existence. If set to `false`, undefined filters will be rendered as empty string. Otherwise, undefined filters will cause an exception. Defaults to `false`. */
|
||||
strict_filters?: boolean
|
||||
strict_filters?: boolean // eslint-disable-line
|
||||
/** `strict_variables` is used to enable strict variable derivation. If set to `false`, undefined variables will be rendered as empty string. Otherwise, undefined variables will cause an exception. Defaults to `false`. */
|
||||
strict_variables?: boolean
|
||||
strict_variables?: boolean // eslint-disable-line
|
||||
/** `trim_tag_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`. */
|
||||
trim_tag_right?: boolean
|
||||
trim_tag_right?: boolean // eslint-disable-line
|
||||
/** `trim_tag_left` is similar to `trim_tag_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
|
||||
trim_tag_left?: boolean
|
||||
trim_tag_left?: boolean // eslint-disable-line
|
||||
/** ``trim_value_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). Defaults to `false`. */
|
||||
trim_value_right?: boolean
|
||||
trim_value_right?: boolean // eslint-disable-line
|
||||
/** `trim_value_left` is similar to `trim_value_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
|
||||
trim_value_left?: boolean
|
||||
trim_value_left?: boolean // eslint-disable-line
|
||||
/** `greedy` is used to specify whether `trim_left`/`trim_right` is greedy. When set to `true`, all consecutive blank characters including `\n` will be trimed regardless of line breaks. Defaults to `true`. */
|
||||
greedy?: boolean
|
||||
}
|
||||
|
||||
+9
-7
@@ -3,7 +3,7 @@ import * as Types from './types'
|
||||
import * as template from 'template'
|
||||
import * as _ from './util/underscore'
|
||||
import ITemplate from './template/itemplate'
|
||||
import * as tokenizer from './parser/tokenizer'
|
||||
import Tokenizer from './parser/tokenizer'
|
||||
import Render from './render/render'
|
||||
import Tag from './template/tag/tag'
|
||||
import Filter from './template/filter'
|
||||
@@ -20,6 +20,7 @@ export default class Liquid {
|
||||
private cache: object
|
||||
private parser: Parser
|
||||
private renderer: Render
|
||||
private tokenizer: Tokenizer
|
||||
|
||||
constructor (options: LiquidOptions = {}) {
|
||||
options = _.assign({}, defaultOptions, options)
|
||||
@@ -31,31 +32,32 @@ export default class Liquid {
|
||||
this.options = options
|
||||
this.parser = new Parser(this)
|
||||
this.renderer = new Render()
|
||||
this.tokenizer = new Tokenizer(this.options)
|
||||
|
||||
_.forOwn(builtinTags, (conf, name) => this.registerTag(name, conf))
|
||||
_.forOwn(builtinFilters, (handler, name) => this.registerFilter(name, handler))
|
||||
}
|
||||
parse(html: string, filepath?: string) {
|
||||
const tokens = tokenizer.parse(html, filepath, this.options)
|
||||
parse (html: string, filepath?: string) {
|
||||
const tokens = this.tokenizer.tokenize(html, filepath)
|
||||
return this.parser.parse(tokens)
|
||||
}
|
||||
render(tpl: Array<ITemplate>, ctx?: object, opts?: LiquidOptions) {
|
||||
render (tpl: Array<ITemplate>, ctx?: object, opts?: LiquidOptions) {
|
||||
opts = _.assign({}, this.options, opts)
|
||||
const scope = new Scope(ctx, opts)
|
||||
return this.renderer.renderTemplates(tpl, scope)
|
||||
}
|
||||
async parseAndRender(html: string, ctx?: object, opts?: LiquidOptions) {
|
||||
async parseAndRender (html: string, ctx?: object, opts?: LiquidOptions) {
|
||||
const tpl = await this.parse(html)
|
||||
return this.render(tpl, ctx, opts)
|
||||
}
|
||||
async getTemplate(file, root) {
|
||||
async getTemplate (file, root) {
|
||||
const filepath = await template.resolve(file, root, this.options)
|
||||
return this.respectCache(filepath, async () => {
|
||||
const str = await template.read(filepath)
|
||||
return this.parse(str, filepath)
|
||||
})
|
||||
}
|
||||
async renderFile(file, ctx?: object, opts?: LiquidOptions) {
|
||||
async renderFile (file, ctx?: object, opts?: LiquidOptions) {
|
||||
opts = _.assign({}, opts)
|
||||
const templates = await this.getTemplate(file, opts.root)
|
||||
return this.render(templates, ctx, opts)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import Token from './token'
|
||||
|
||||
export default class DelimitedToken extends Token {
|
||||
trim_left: boolean
|
||||
trim_right: boolean
|
||||
constructor(raw, pos, input, file, line) {
|
||||
trimLeft: boolean
|
||||
trimRight: boolean
|
||||
constructor (raw, pos, input, file, line) {
|
||||
super(raw, pos, input, file, line)
|
||||
this.trim_left = raw[2] === '-'
|
||||
this.trim_right = raw[raw.length - 3] === '-'
|
||||
this.value = raw.slice(this.trim_left ? 3 : 2, this.trim_right ? -3 : -2).trim()
|
||||
this.trimLeft = raw[2] === '-'
|
||||
this.trimRight = raw[raw.length - 3] === '-'
|
||||
this.value = raw.slice(this.trimLeft ? 3 : 2, this.trimRight ? -3 : -2).trim()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Token from './token'
|
||||
|
||||
export default class HTMLToken extends Token {
|
||||
constructor(str, begin, input, file, line) {
|
||||
constructor (str, begin, input, file, line) {
|
||||
super(str, begin, input, file, line)
|
||||
this.type = 'html'
|
||||
this.value = str
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import DelimitedToken from './delimited-token'
|
||||
|
||||
export default class OutputToken extends DelimitedToken {
|
||||
constructor(raw, pos, input, file, line) {
|
||||
constructor (raw, pos, input, file, line) {
|
||||
super(raw, pos, input, file, line)
|
||||
this.type = 'output'
|
||||
}
|
||||
|
||||
@@ -2,18 +2,16 @@ import { ParseError } from '../util/error'
|
||||
import Liquid from 'src/liquid'
|
||||
import ParseStream from './parse-stream'
|
||||
import Token from './token'
|
||||
import Tag from 'src/template/tag/tag'
|
||||
import HTMLToken from './html-token'
|
||||
import TagToken from './tag-token'
|
||||
import OutputToken from './output-token'
|
||||
import Tag from 'src/template/tag/tag'
|
||||
import Output from 'src/template/output'
|
||||
import HTML from 'src/template/html'
|
||||
import Value from 'src/template/value'
|
||||
|
||||
export default class Parser {
|
||||
liquid: Liquid
|
||||
|
||||
constructor(liquid: Liquid) {
|
||||
constructor (liquid: Liquid) {
|
||||
this.liquid = liquid
|
||||
}
|
||||
parse (tokens: Array<Token>) {
|
||||
@@ -27,10 +25,10 @@ export default class Parser {
|
||||
parseToken (token: Token, remainTokens: Array<Token>) {
|
||||
try {
|
||||
if (token.type === 'tag') {
|
||||
return new Tag(token, remainTokens, this.liquid)
|
||||
return new Tag(token as TagToken, remainTokens, this.liquid)
|
||||
}
|
||||
if (token.type === 'output') {
|
||||
return new Output(token, this.liquid.options.strict_filters)
|
||||
return new Output(token as OutputToken, this.liquid.options.strict_filters)
|
||||
}
|
||||
return new HTML(token)
|
||||
} catch (e) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as lexical from './lexical'
|
||||
export default class TagToken extends DelimitedToken {
|
||||
name: string
|
||||
args: string
|
||||
constructor(raw, pos, input, file, line) {
|
||||
constructor (raw, pos, input, file, line) {
|
||||
super(raw, pos, input, file, line)
|
||||
this.type = 'tag'
|
||||
const match = this.value.match(lexical.tagLine)
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ export default class Token {
|
||||
input: string
|
||||
file: string
|
||||
value: string
|
||||
constructor(raw, pos, input, file, line) {
|
||||
constructor (raw, pos, input, file, line) {
|
||||
this.line = line
|
||||
this.raw = raw
|
||||
this.input = input
|
||||
|
||||
+44
-39
@@ -2,52 +2,57 @@ import whiteSpaceCtrl from './whitespace-ctrl'
|
||||
import HTMLToken from './html-token'
|
||||
import TagToken from './tag-token'
|
||||
import OutputToken from './output-token'
|
||||
import { LiquidOptions, defaultOptions } from 'src/liquid-options'
|
||||
|
||||
enum ParseState { HTML, OUTPUT, TAG }
|
||||
|
||||
export function parse (input: string, file?: string, options?) {
|
||||
const tokens = []
|
||||
let p = 0
|
||||
let line = 1
|
||||
let state = ParseState.HTML
|
||||
let buffer = ''
|
||||
let bufferBegin = 0
|
||||
export default class Tokenizer {
|
||||
options: LiquidOptions
|
||||
constructor (options: LiquidOptions = defaultOptions) {
|
||||
this.options = options
|
||||
}
|
||||
tokenize (input: string, file?: string) {
|
||||
const tokens = []
|
||||
let p = 0
|
||||
let line = 1
|
||||
let state = ParseState.HTML
|
||||
let buffer = ''
|
||||
let bufferBegin = 0
|
||||
|
||||
while(p < input.length) {
|
||||
if (input[p] === '\n') line++
|
||||
const bin = input.substr(p, 2)
|
||||
if (state === ParseState.HTML) {
|
||||
if (bin === '{{' || bin === '{%') {
|
||||
if (buffer) tokens.push(new HTMLToken(buffer, bufferBegin, input, file, line))
|
||||
buffer = bin
|
||||
bufferBegin = p
|
||||
while (p < input.length) {
|
||||
if (input[p] === '\n') line++
|
||||
const bin = input.substr(p, 2)
|
||||
if (state === ParseState.HTML) {
|
||||
if (bin === '{{' || bin === '{%') {
|
||||
if (buffer) tokens.push(new HTMLToken(buffer, bufferBegin, input, file, line))
|
||||
buffer = bin
|
||||
bufferBegin = p
|
||||
p += 2
|
||||
state = bin === '{{' ? ParseState.OUTPUT : ParseState.TAG
|
||||
continue
|
||||
}
|
||||
} else if (state === ParseState.OUTPUT && bin === '}}') {
|
||||
buffer += '}}'
|
||||
tokens.push(new OutputToken(buffer, bufferBegin, input, file, line))
|
||||
p += 2
|
||||
state = bin === '{{' ? ParseState.OUTPUT : ParseState.TAG
|
||||
buffer = ''
|
||||
bufferBegin = p
|
||||
state = ParseState.HTML
|
||||
continue
|
||||
} else if (bin === '%}') {
|
||||
buffer += '%}'
|
||||
tokens.push(new TagToken(buffer, bufferBegin, input, file, line))
|
||||
p += 2
|
||||
buffer = ''
|
||||
bufferBegin = p
|
||||
state = ParseState.HTML
|
||||
continue
|
||||
}
|
||||
buffer += input[p++]
|
||||
}
|
||||
else if (state === ParseState.OUTPUT && bin === '}}') {
|
||||
buffer += '}}'
|
||||
tokens.push(new OutputToken(buffer, bufferBegin, input, file, line))
|
||||
p += 2
|
||||
buffer = ''
|
||||
bufferBegin = p
|
||||
state = ParseState.HTML
|
||||
continue
|
||||
}
|
||||
else if (bin === '%}') {
|
||||
buffer += '%}'
|
||||
tokens.push(new TagToken(buffer, bufferBegin, input, file, line))
|
||||
p += 2
|
||||
buffer = ''
|
||||
bufferBegin = p
|
||||
state = ParseState.HTML
|
||||
continue
|
||||
}
|
||||
buffer += input[p++]
|
||||
}
|
||||
if (buffer) tokens.push(new HTMLToken(buffer, bufferBegin, input, file, line))
|
||||
if (buffer) tokens.push(new HTMLToken(buffer, bufferBegin, input, file, line))
|
||||
|
||||
whiteSpaceCtrl(tokens, options)
|
||||
return tokens
|
||||
whiteSpaceCtrl(tokens, this.options)
|
||||
return tokens
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,47 @@
|
||||
import { assign } from 'src/util/underscore'
|
||||
import TagToken from './tag-token'
|
||||
import OutputToken from './output-token'
|
||||
import HTMLToken from './html-token'
|
||||
import DelimitedToken from 'src/parser/delimited-token'
|
||||
import Token from 'src/parser/token'
|
||||
import TagToken from 'src/parser/tag-token'
|
||||
import { LiquidOptions } from 'src/liquid-options'
|
||||
|
||||
export default function whiteSpaceCtrl (tokens, options) {
|
||||
export default function whiteSpaceCtrl (tokens: Token[], options: LiquidOptions) {
|
||||
options = assign({ greedy: true }, options)
|
||||
let inRaw = false
|
||||
|
||||
tokens.forEach((token, i) => {
|
||||
if (shouldTrimLeft(token, inRaw, options)) {
|
||||
tokens.forEach((token: Token, i: number) => {
|
||||
if (shouldTrimLeft(token as DelimitedToken, inRaw, options)) {
|
||||
trimLeft(tokens[i - 1], options.greedy)
|
||||
}
|
||||
|
||||
if (token.type === 'tag' && token.name === 'raw') inRaw = true
|
||||
if (token.type === 'tag' && token.name === 'endraw') inRaw = false
|
||||
if (token.type === 'tag' && (token as TagToken).name === 'raw') inRaw = true
|
||||
if (token.type === 'tag' && (token as TagToken).name === 'endraw') inRaw = false
|
||||
|
||||
if (shouldTrimRight(token, inRaw, options)) {
|
||||
if (shouldTrimRight(token as DelimitedToken, inRaw, options)) {
|
||||
trimRight(tokens[i + 1], options.greedy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function shouldTrimLeft (token, inRaw, options) {
|
||||
function shouldTrimLeft (token: DelimitedToken, inRaw: boolean, options) {
|
||||
if (inRaw) return false
|
||||
if (token.type === 'tag') return token.trim_left || options.trim_tag_left
|
||||
if (token.type === 'output') return token.trim_left || options.trim_value_left
|
||||
if (token.type === 'tag') return token.trimLeft || options.trim_tag_left
|
||||
if (token.type === 'output') return token.trimLeft || options.trim_value_left
|
||||
}
|
||||
|
||||
function shouldTrimRight (token, inRaw, options) {
|
||||
function shouldTrimRight (token: DelimitedToken, inRaw: boolean, options) {
|
||||
if (inRaw) return false
|
||||
if (token.type === 'tag') return token.trim_right || options.trim_tag_right
|
||||
if (token.type === 'output') return token.trim_right || options.trim_value_right
|
||||
if (token.type === 'tag') return token.trimRight || options.trim_tag_right
|
||||
if (token.type === 'output') return token.trimRight || options.trim_value_right
|
||||
}
|
||||
|
||||
function trimLeft (token, greedy) {
|
||||
function trimLeft (token: Token, greedy: boolean) {
|
||||
if (!token || token.type !== 'html') return
|
||||
|
||||
const rLeft = greedy ? /\s+$/g : /[\t\r ]*$/g
|
||||
token.value = token.value.replace(rLeft, '')
|
||||
}
|
||||
|
||||
function trimRight (token, greedy) {
|
||||
function trimRight (token: Token, greedy: boolean) {
|
||||
if (!token || token.type !== 'html') return
|
||||
|
||||
const rRight = greedy ? /^\s+/g : /^[\t\r ]*\n?/g
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { stringify, create } from 'src/util/underscore'
|
||||
import { RenderBreakError, RenderError } from 'src/util/error'
|
||||
import assert from 'src/util/assert'
|
||||
import Scope from 'src/scope/scope'
|
||||
|
||||
export default class Render {
|
||||
async renderTemplates (templates, scope) {
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ export default class Scope {
|
||||
strict_variables: false,
|
||||
strict_filters: false,
|
||||
root: []
|
||||
} , opts)
|
||||
}, opts)
|
||||
this.contexts = [ctx || {}]
|
||||
}
|
||||
getAll () {
|
||||
@@ -59,7 +59,7 @@ export default class Scope {
|
||||
}
|
||||
return this.contexts.splice(i, 1)[0]
|
||||
}
|
||||
findContextFor (key: string, filter = (arg => true)) {
|
||||
findContextFor (key: string, filter: ((conttext: object) => boolean) = () => true) {
|
||||
for (let i = this.contexts.length - 1; i >= 0; i--) {
|
||||
const candidate = this.contexts[i]
|
||||
if (!filter(candidate)) continue
|
||||
|
||||
@@ -13,21 +13,21 @@ export default class Filter {
|
||||
args: string[]
|
||||
private static impls: {[key: string]: impl} = {}
|
||||
|
||||
constructor (str: string, strict_filters: boolean = false) {
|
||||
let match = lexical.filterLine.exec(str)
|
||||
constructor (str: string, strictFilters: boolean = false) {
|
||||
const match = lexical.filterLine.exec(str)
|
||||
assert(match, 'illegal filter: ' + str)
|
||||
|
||||
const name = match[1]
|
||||
const argList = match[2] || ''
|
||||
const impl = Filter.impls[name]
|
||||
if (!impl && strict_filters) throw new TypeError(`undefined filter: ${name}`)
|
||||
if (!impl && strictFilters) throw new TypeError(`undefined filter: ${name}`)
|
||||
|
||||
this.name = name
|
||||
this.impl = impl || (x => x)
|
||||
this.args = this.parseArgs(argList)
|
||||
}
|
||||
parseArgs (argList: string): string[] {
|
||||
let match, args = []
|
||||
let match; const args = []
|
||||
while ((match = valueRE.exec(argList.trim()))) {
|
||||
const v = match[0]
|
||||
const re = new RegExp(`${v}\\s*:`, 'g')
|
||||
@@ -42,7 +42,7 @@ export default class Filter {
|
||||
args.unshift(value)
|
||||
return this.impl.apply(null, args)
|
||||
}
|
||||
static register(name, filter) {
|
||||
static register (name, filter) {
|
||||
Filter.impls[name] = filter
|
||||
}
|
||||
static clear () {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import Template from 'src/template/template'
|
||||
import Scope from 'src/scope/scope'
|
||||
import ITemplate from 'src/template/itemplate'
|
||||
import Token from 'src/parser/token'
|
||||
|
||||
export default class extends Template implements ITemplate {
|
||||
str: string
|
||||
constructor(token: Token) {
|
||||
constructor (token: Token) {
|
||||
super(token)
|
||||
this.str = token.value
|
||||
}
|
||||
async render(scope: Scope): Promise<string> {
|
||||
async render (): Promise<string> {
|
||||
return this.str
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,15 @@ import { stringify } from 'src/util/underscore'
|
||||
import Template from 'src/template/template'
|
||||
import ITemplate from 'src/template/itemplate'
|
||||
import Scope from 'src/scope/scope'
|
||||
import OutputToken from 'src/parser/output-token'
|
||||
|
||||
export default class Output extends Template implements ITemplate {
|
||||
value: Value
|
||||
constructor(token, strict_filters?) {
|
||||
constructor (token: OutputToken, strictFilters?: boolean) {
|
||||
super(token)
|
||||
this.value = new Value(token.value, strict_filters)
|
||||
this.value = new Value(token.value, strictFilters)
|
||||
}
|
||||
async render(scope: Scope) {
|
||||
async render (scope: Scope): Promise<string> {
|
||||
const html = await this.value.value(scope)
|
||||
return stringify(html)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { evalValue } from 'src/render/syntax'
|
||||
*/
|
||||
export default class Hash {
|
||||
[key: string]: any
|
||||
constructor(markup, scope) {
|
||||
constructor (markup, scope) {
|
||||
let match
|
||||
hashCapture.lastIndex = 0
|
||||
while ((match = hashCapture.exec(markup))) {
|
||||
|
||||
@@ -6,5 +6,5 @@ import ITagImpl from './itag-impl'
|
||||
|
||||
export default interface ITagImplOptions {
|
||||
parse?: (this: ITagImpl, token: TagToken, remainingTokens: Array<Token>) => void
|
||||
render?: (this: ITagImpl, scope: Scope, hash: Hash) => string | Promise<string>
|
||||
render?: (this: ITagImpl, scope: Scope, hash: Hash) => any | Promise<any>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { create } from 'src/util/underscore'
|
||||
import { stringify } from 'src/util/underscore'
|
||||
import { create, stringify } from 'src/util/underscore'
|
||||
import assert from 'src/util/assert'
|
||||
import Scope from 'src/scope/scope'
|
||||
import ITagImpl from './itag-impl'
|
||||
import ITagImplOptions from './itag-impl-options'
|
||||
import Liquid from 'src/liquid'
|
||||
@@ -8,26 +8,27 @@ import Hash from './hash'
|
||||
import Template from 'src/template/template'
|
||||
import ITemplate from 'src/template/itemplate'
|
||||
import TagToken from 'src/parser/tag-token'
|
||||
import Token from 'src/parser/token'
|
||||
|
||||
export default class Tag extends Template implements ITemplate {
|
||||
name: string
|
||||
token: TagToken
|
||||
private impl: ITagImpl
|
||||
static impls: object = {}
|
||||
static impls: { [key: string]: ITagImplOptions } = {}
|
||||
|
||||
constructor (token, tokens, liquid: Liquid) {
|
||||
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`)
|
||||
this.impl = create(impl)
|
||||
this.impl = create<ITagImplOptions, ITagImpl>(impl)
|
||||
this.impl.liquid = liquid
|
||||
if (this.impl.parse) {
|
||||
this.impl.parse(token, tokens)
|
||||
}
|
||||
}
|
||||
async render (scope) {
|
||||
async render (scope: Scope) {
|
||||
const hash = new Hash(this.token.args, scope)
|
||||
const impl = this.impl
|
||||
if (typeof impl.render !== 'function') {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Token from 'src/parser/token'
|
||||
|
||||
export default class Template {
|
||||
token: Token;
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
constructor (token) {
|
||||
this.token = token
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import Scope from 'src/scope/scope'
|
||||
export default class {
|
||||
initial: any
|
||||
filters: Array<any>
|
||||
constructor(str: string, strict_filters?: boolean) {
|
||||
constructor (str: string, strictFilters?: boolean) {
|
||||
let match = lexical.matchValue(str)
|
||||
assert(match, `illegal value string: ${str}`)
|
||||
|
||||
@@ -20,9 +20,9 @@ export default class {
|
||||
}
|
||||
|
||||
this.initial = initial
|
||||
this.filters = filters.map(str => new Filter(str, strict_filters))
|
||||
this.filters = filters.map(str => new Filter(str, strictFilters))
|
||||
}
|
||||
value(scope: Scope) {
|
||||
value (scope: Scope) {
|
||||
return this.filters.reduce(
|
||||
(prev, filter) => filter.render(prev, scope),
|
||||
evalExp(this.initial, scope))
|
||||
|
||||
+11
-11
@@ -16,14 +16,14 @@ abstract class LiquidError {
|
||||
private input: string
|
||||
private token: Token
|
||||
private originalError: Error
|
||||
constructor(err, token) {
|
||||
constructor (err, token) {
|
||||
this.input = token.input
|
||||
this.line = token.line
|
||||
this.file = token.file
|
||||
this.originalError = err
|
||||
this.token = token
|
||||
}
|
||||
captureStackTrace(obj) {
|
||||
captureStackTrace (obj) {
|
||||
this.name = obj.constructor.name
|
||||
|
||||
captureStack.call(obj)
|
||||
@@ -37,32 +37,32 @@ abstract class LiquidError {
|
||||
}
|
||||
|
||||
export class TokenizationError extends LiquidError {
|
||||
constructor(message, token) {
|
||||
super({message}, token)
|
||||
constructor (message, token) {
|
||||
super({ message }, token)
|
||||
super.captureStackTrace(this)
|
||||
}
|
||||
}
|
||||
TokenizationError.prototype = _.create(Error.prototype)
|
||||
TokenizationError.prototype = _.create(Error.prototype) as any
|
||||
TokenizationError.prototype.constructor = TokenizationError
|
||||
|
||||
export class ParseError extends LiquidError {
|
||||
constructor(err, token) {
|
||||
constructor (err, token) {
|
||||
super(err, token)
|
||||
_.assign(this, err)
|
||||
super.captureStackTrace(this)
|
||||
}
|
||||
}
|
||||
ParseError.prototype = _.create(Error.prototype)
|
||||
ParseError.prototype = _.create(Error.prototype) as any
|
||||
ParseError.prototype.constructor = ParseError
|
||||
|
||||
export class RenderError extends LiquidError {
|
||||
constructor(err, tpl) {
|
||||
constructor (err, tpl) {
|
||||
super(err, tpl.token)
|
||||
_.assign(this, err)
|
||||
super.captureStackTrace(this)
|
||||
}
|
||||
}
|
||||
RenderError.prototype = _.create(Error.prototype)
|
||||
RenderError.prototype = _.create(Error.prototype) as any
|
||||
RenderError.prototype.constructor = RenderError
|
||||
|
||||
export class RenderBreakError {
|
||||
@@ -73,7 +73,7 @@ export class RenderBreakError {
|
||||
this.message = message + ''
|
||||
}
|
||||
}
|
||||
RenderBreakError.prototype = _.create(Error.prototype)
|
||||
RenderBreakError.prototype = _.create(Error.prototype) as any
|
||||
RenderBreakError.prototype.constructor = RenderBreakError
|
||||
|
||||
export class AssertionError {
|
||||
@@ -83,7 +83,7 @@ export class AssertionError {
|
||||
this.message = message + ''
|
||||
}
|
||||
}
|
||||
AssertionError.prototype = _.create(Error.prototype)
|
||||
AssertionError.prototype = _.create(Error.prototype) as any
|
||||
AssertionError.prototype.constructor = AssertionError
|
||||
|
||||
function mkContext (input, targetLine) {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
export function anySeries (iterable, iteratee) {
|
||||
let ret: Promise<any> = Promise.reject(new Error('init'))
|
||||
iterable.forEach(function (item, idx) {
|
||||
ret = ret.catch(e => iteratee(item, idx, iterable))
|
||||
ret = ret.catch(() => iteratee(item, idx, iterable))
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ const formatCodes = {
|
||||
}
|
||||
};
|
||||
(formatCodes as any).h = formatCodes.b;
|
||||
(formatCodes as any).N = formatCodes.L;
|
||||
(formatCodes as any).N = formatCodes.L
|
||||
|
||||
export default function (d, format) {
|
||||
let output = ''
|
||||
|
||||
+18
-17
@@ -6,11 +6,11 @@ const arrToStr = Array.prototype.toString
|
||||
* @param {any} value The value to check.
|
||||
* @return {Boolean} Returns true if value is a string, else false.
|
||||
*/
|
||||
export function isString (value) {
|
||||
export function isString (value: any) {
|
||||
return toStr.call(value) === '[object String]'
|
||||
}
|
||||
|
||||
export function isFunction (value) {
|
||||
export function isFunction (value: any) {
|
||||
return typeof value === 'function'
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export function promisify (fn) {
|
||||
}
|
||||
}
|
||||
|
||||
export function stringify (value) {
|
||||
export function stringify (value: any): string {
|
||||
if (isNil(value)) return ''
|
||||
if (isFunction(value.to_liquid)) return stringify(value.to_liquid())
|
||||
if (isFunction(value.toLiquid)) return stringify(value.toLiquid())
|
||||
@@ -34,7 +34,7 @@ export function stringify (value) {
|
||||
return toStr.call(value)
|
||||
}
|
||||
|
||||
function defaultToString (value) {
|
||||
function defaultToString (value: any): string {
|
||||
const cache = []
|
||||
return JSON.stringify(value, (key, value) => {
|
||||
if (isObject(value)) {
|
||||
@@ -47,20 +47,20 @@ function defaultToString (value) {
|
||||
})
|
||||
}
|
||||
|
||||
export function create (proto) {
|
||||
export function create<T1 extends object, T2 extends T1 = T1> (proto: T1): T2 {
|
||||
return Object.create(proto)
|
||||
}
|
||||
|
||||
export function isNil (value) {
|
||||
export function isNil (value: any): boolean {
|
||||
return value === null || value === undefined
|
||||
}
|
||||
|
||||
export function isArray (value) {
|
||||
export function isArray (value: any): boolean {
|
||||
// be compatible with IE 8
|
||||
return toStr.call(value) === '[object Array]'
|
||||
}
|
||||
|
||||
export function isError (value) {
|
||||
export function isError (value: any): boolean {
|
||||
const signature = toStr.call(value)
|
||||
// [object XXXError]
|
||||
return signature.substr(-6, 5) === 'Error' ||
|
||||
@@ -75,7 +75,7 @@ export function isError (value) {
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @return {Object} Returns object.
|
||||
*/
|
||||
export function forOwn (object, iteratee) {
|
||||
export function forOwn (object, iteratee: ((val: any, key: string, obj: object) => boolean | void)) {
|
||||
object = object || {}
|
||||
for (const k in object) {
|
||||
if (object.hasOwnProperty(k)) {
|
||||
@@ -96,21 +96,22 @@ export function forOwn (object, iteratee) {
|
||||
* @param {...Object} sources The source objects.
|
||||
* @return {Object} Returns object.
|
||||
*/
|
||||
export function assign (obj, ...srcs) {
|
||||
export function assign (obj: object, ...srcs: object[]): object {
|
||||
obj = isObject(obj) ? obj : {}
|
||||
srcs.forEach(src => binaryAssign(obj, src))
|
||||
return obj
|
||||
}
|
||||
|
||||
function binaryAssign(target, src) {
|
||||
for(let key in src) if (src.hasOwnProperty(key)) target[key] = src[key]
|
||||
function binaryAssign (target: object, src: object): object {
|
||||
for (const key in src) if (src.hasOwnProperty(key)) target[key] = src[key]
|
||||
return target
|
||||
}
|
||||
|
||||
export function last (arr) {
|
||||
export function last (arr: any[]): any {
|
||||
return arr[arr.length - 1]
|
||||
}
|
||||
|
||||
export function uniq (arr) {
|
||||
export function uniq (arr: any[]): any[] {
|
||||
const u = {}
|
||||
const a = []
|
||||
for (let i = 0, l = arr.length; i < l; ++i) {
|
||||
@@ -129,7 +130,7 @@ export function uniq (arr) {
|
||||
* @param {any} value The value to check.
|
||||
* @return {Boolean} Returns true if value is an object, else false.
|
||||
*/
|
||||
export function isObject (value) {
|
||||
export function isObject (value: any): boolean {
|
||||
const type = typeof value
|
||||
return value !== null && (type === 'object' || type === 'function')
|
||||
}
|
||||
@@ -156,9 +157,9 @@ export function range (start: number, stop?: number, step?: number) {
|
||||
return arr
|
||||
}
|
||||
|
||||
export function padStart(str: any, length: number, ch: string = ' ') {
|
||||
export function padStart (str: any, length: number, ch: string = ' ') {
|
||||
str = String(str)
|
||||
let n = length - str.length
|
||||
while(n-- > 0) str = ch + str
|
||||
while (n-- > 0) str = ch + str
|
||||
return str
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user