style: introduce @typescript-eslint/recommended

This commit is contained in:
harttle
2019-07-06 14:33:34 +08:00
parent e6f5f1cd85
commit 88c89fe3b3
48 changed files with 260 additions and 235 deletions
+9 -1
View File
@@ -1,5 +1,5 @@
{ {
"extends": "standard", "extends": ["standard", "plugin:@typescript-eslint/recommended"],
"env": { "env": {
"mocha": true, "mocha": true,
"es6": true, "es6": true,
@@ -17,6 +17,14 @@
"no-var": 2, "no-var": 2,
"prefer-const": 2, "prefer-const": 2,
"no-unused-vars": "off", "no-unused-vars": "off",
"indent": "off",
"@typescript-eslint/indent": ["error", 2],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-object-literal-type-assertion": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"import/export": "off", "import/export": "off",
"@typescript-eslint/no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }] "@typescript-eslint/no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }]
} }
+36 -23
View File
@@ -448,6 +448,12 @@
"integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==", "integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==",
"dev": true "dev": true
}, },
"@types/eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
"integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
"dev": true
},
"@types/estree": { "@types/estree": {
"version": "0.0.39", "version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
@@ -568,31 +574,44 @@
"dev": true "dev": true
}, },
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "1.3.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz",
"integrity": "sha512-s+vjO9+PvYS2A6FnQC/imyEDOkrEKIzSpPf2OEGnkKqa5+1d0cuXgCi/oROtuBht2/u/iK22nrYcO/Ei4R8F/g==", "integrity": "sha512-mXv9ccCou89C8/4avKHuPB2WkSZyY/XcTQUXd5LFZAcLw1I3mWYVjUu6eS9Ja0QkP/ClolbcW9tb3Ov/pMdcqw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/parser": "1.3.0", "@typescript-eslint/experimental-utils": "1.11.0",
"requireindex": "^1.2.0", "eslint-utils": "^1.3.1",
"functional-red-black-tree": "^1.0.1",
"regexpp": "^2.0.1",
"tsutils": "^3.7.0" "tsutils": "^3.7.0"
} }
}, },
"@typescript-eslint/parser": { "@typescript-eslint/experimental-utils": {
"version": "1.3.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.11.0.tgz",
"integrity": "sha512-Q5cz9nyEQyRrtItRElvQXdNs0Xja1xvOdphDQR7N6MqUdi4juWVNxHKypdHQCx9OcEBev6pWHOda8lwg/2W9/g==", "integrity": "sha512-7LbfaqF6B8oa8cp/315zxKk8FFzosRzzhF8Kn/ZRsRsnpm7Qcu25cR/9RnAQo5utZ2KIWVgaALr+ZmcbG47ruw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/typescript-estree": "1.3.0", "@typescript-eslint/typescript-estree": "1.11.0",
"eslint-scope": "^4.0.0", "eslint-scope": "^4.0.0"
}
},
"@typescript-eslint/parser": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.11.0.tgz",
"integrity": "sha512-5xBExyXaxVyczrZvbRKEXvaTUFFq7gIM9BynXukXZE0zF3IQP/FxF4mPmmh3gJ9egafZFqByCpPTFm3dk4SY7Q==",
"dev": true,
"requires": {
"@types/eslint-visitor-keys": "^1.0.0",
"@typescript-eslint/experimental-utils": "1.11.0",
"@typescript-eslint/typescript-estree": "1.11.0",
"eslint-visitor-keys": "^1.0.0" "eslint-visitor-keys": "^1.0.0"
} }
}, },
"@typescript-eslint/typescript-estree": { "@typescript-eslint/typescript-estree": {
"version": "1.3.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.11.0.tgz",
"integrity": "sha512-h6UxHSmBUopFcxHg/eryrA+GwHMbh7PxotMbkq9p2f3nX60CKm5Zc0VN8krBD3IS5KqsK0iOz24VpEWrP+JZ2Q==", "integrity": "sha512-fquUHF5tAx1sM2OeRCC7wVxFd1iMELWMGCzOSmJ3pLzArj9+kRixdlC4d5MncuzXpjEqc6045p3KwM0o/3FuUA==",
"dev": true, "dev": true,
"requires": { "requires": {
"lodash.unescape": "4.0.1", "lodash.unescape": "4.0.1",
@@ -9316,12 +9335,6 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true "dev": true
}, },
"requireindex": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz",
"integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==",
"dev": true
},
"resolve": { "resolve": {
"version": "1.10.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
@@ -10475,9 +10488,9 @@
"dev": true "dev": true
}, },
"tsutils": { "tsutils": {
"version": "3.8.0", "version": "3.14.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.8.0.tgz", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz",
"integrity": "sha512-XQdPhgcoTbCD8baXC38PQ0vpTZ8T3YrE+vR66YIj/xvDt1//8iAhafpIT/4DmvzzC1QFapEImERu48Pa01dIUA==", "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==",
"dev": true, "dev": true,
"requires": { "requires": {
"tslib": "^1.8.1" "tslib": "^1.8.1"
+2 -1
View File
@@ -57,7 +57,8 @@
"@types/sinon": "^7.0.6", "@types/sinon": "^7.0.6",
"@types/sinon-chai": "^3.2.2", "@types/sinon-chai": "^3.2.2",
"@types/supertest": "^2.0.7", "@types/supertest": "^2.0.7",
"@typescript-eslint/eslint-plugin": "^1.3.0", "@typescript-eslint/eslint-plugin": "^1.11.0",
"@typescript-eslint/parser": "^1.11.0",
"benchmark": "^2.1.4", "benchmark": "^2.1.4",
"chai": "^4.2.0", "chai": "^4.2.0",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
+1 -1
View File
@@ -9,7 +9,7 @@ export default {
'reverse': (v: any[]) => [...v].reverse(), 'reverse': (v: any[]) => [...v].reverse(),
'sort': <T>(v: T[], arg: (lhs: T, rhs: T) => number) => v.sort(arg), 'sort': <T>(v: T[], arg: (lhs: T, rhs: T) => number) => v.sort(arg),
'size': (v: string | any[]) => v.length, 'size': (v: string | any[]) => v.length,
'concat': <T1, T2>(v: T1[], arg: T2[] | T2): Array<T1 | T2> => Array.prototype.concat.call(v, arg), 'concat': <T1, T2>(v: T1[], arg: T2[] | T2): (T1 | T2)[] => Array.prototype.concat.call(v, arg),
'slice': <T>(v: T[], begin: number, length: number = 1): T[] => { 'slice': <T>(v: T[], begin: number, length: number = 1): T[] => {
begin = begin < 0 ? v.length + begin : begin begin = begin < 0 ? v.length + begin : begin
return v.slice(begin, begin + length) return v.slice(begin, begin + length)
+1 -1
View File
@@ -18,7 +18,7 @@ export default {
'times': (v: number, arg: number) => v * arg 'times': (v: number, arg: number) => v * arg
} }
function caseInsensitiveCmp (a, b) { function caseInsensitiveCmp (a: any, b: any) {
if (!b) return -1 if (!b) return -1
if (!a) return 1 if (!a) return 1
a = toLowerCase.call(a) a = toLowerCase.call(a)
+2 -2
View File
@@ -8,7 +8,7 @@ import ITagImplOptions from '../../template/tag/itag-impl-options'
const groupRE = new RegExp(`^(?:(${rValue.source})\\s*:\\s*)?(.*)$`) const groupRE = new RegExp(`^(?:(${rValue.source})\\s*:\\s*)?(.*)$`)
const candidatesRE = new RegExp(rValue.source, 'g') const candidatesRE = new RegExp(rValue.source, 'g')
export default <ITagImplOptions>{ export default {
parse: function (tagToken: TagToken) { parse: function (tagToken: TagToken) {
let match: RegExpExecArray | null = groupRE.exec(tagToken.args) as RegExpExecArray let match: RegExpExecArray | null = groupRE.exec(tagToken.args) as RegExpExecArray
assert(match, `illegal tag: ${tagToken.raw}`) assert(match, `illegal tag: ${tagToken.raw}`)
@@ -40,4 +40,4 @@ export default <ITagImplOptions>{
return evalValue(candidate, ctx) return evalValue(candidate, ctx)
} }
} } as ITagImplOptions
+2 -2
View File
@@ -17,7 +17,7 @@ const re = new RegExp(`^(${identifier.source})\\s+in\\s+` +
`(?:\\s+(reversed))?` + `(?:\\s+(reversed))?` +
`(?:\\s+${hash.source})*$`) `(?:\\s+${hash.source})*$`)
export default <ITagImplOptions>{ export default {
type: 'block', type: 'block',
parse: function (tagToken: TagToken, remainTokens: Token[]) { parse: function (tagToken: TagToken, remainTokens: Token[]) {
const match = re.exec(tagToken.args) as RegExpExecArray const match = re.exec(tagToken.args) as RegExpExecArray
@@ -79,4 +79,4 @@ export default <ITagImplOptions>{
ctx.pop() ctx.pop()
return html return html
} }
} } as ITagImplOptions
+2 -2
View File
@@ -10,7 +10,7 @@ import ITagImplOptions from '../../template/tag/itag-impl-options'
const staticFileRE = /[^\s,]+/ const staticFileRE = /[^\s,]+/
const withRE = new RegExp(`with\\s+(${value.source})`) const withRE = new RegExp(`with\\s+(${value.source})`)
export default <ITagImplOptions>{ export default {
parse: function (token: TagToken) { parse: function (token: TagToken) {
let match = staticFileRE.exec(token.args) let match = staticFileRE.exec(token.args)
if (match) this.staticValue = match[0] if (match) this.staticValue = match[0]
@@ -51,4 +51,4 @@ export default <ITagImplOptions>{
ctx.setRegister('blockMode', originBlockMode) ctx.setRegister('blockMode', originBlockMode)
return html return html
} }
} } as ITagImplOptions
+2 -2
View File
@@ -2,7 +2,7 @@ import TagToken from '../../parser/tag-token'
import Token from '../../parser/token' import Token from '../../parser/token'
import ITagImplOptions from '../../template/tag/itag-impl-options' import ITagImplOptions from '../../template/tag/itag-impl-options'
export default <ITagImplOptions>{ export default {
parse: function (tagToken: TagToken, remainTokens: Token[]) { parse: function (tagToken: TagToken, remainTokens: Token[]) {
this.tokens = [] this.tokens = []
@@ -20,4 +20,4 @@ export default <ITagImplOptions>{
render: function () { render: function () {
return this.tokens.map((token: Token) => token.raw).join('') return this.tokens.map((token: Token) => token.raw).join('')
} }
} } as ITagImplOptions
+11 -11
View File
@@ -6,25 +6,25 @@ import { NormalizedFullOptions, applyDefault } from '../liquid-options'
import { Scope } from './scope' import { Scope } from './scope'
export default class Context { export default class Context {
opts: NormalizedFullOptions private scopes: Scope[] = [{}]
environments: Scope
private scopes: Array<Scope> = [{}]
private registers = {} private registers = {}
constructor (ctx: object = {}, opts?: NormalizedFullOptions) { public environments: Scope
public opts: NormalizedFullOptions
public constructor (ctx: object = {}, opts?: NormalizedFullOptions) {
this.opts = applyDefault(opts) this.opts = applyDefault(opts)
this.environments = ctx this.environments = ctx
} }
getRegister (key: string, defaultValue = {}) { public getRegister (key: string, defaultValue = {}) {
return (this.registers[key] = this.registers[key] || defaultValue) return (this.registers[key] = this.registers[key] || defaultValue)
} }
setRegister (key: string, value: any) { public setRegister (key: string, value: any) {
return (this.registers[key] = value) return (this.registers[key] = value)
} }
getAll () { public getAll () {
return [this.environments, ...this.scopes] return [this.environments, ...this.scopes]
.reduce((ctx, val) => __assign(ctx, val), {}) .reduce((ctx, val) => __assign(ctx, val), {})
} }
async get (path: string) { public async get (path: string) {
const paths = await this.parseProp(path) const paths = await this.parseProp(path)
let ctx = this.findScope(paths[0]) || this.environments let ctx = this.findScope(paths[0]) || this.environments
for (const path of paths) { for (const path of paths) {
@@ -35,13 +35,13 @@ export default class Context {
} }
return ctx return ctx
} }
push (ctx: object) { public push (ctx: object) {
return this.scopes.push(ctx) return this.scopes.push(ctx)
} }
pop () { public pop () {
return this.scopes.pop() return this.scopes.pop()
} }
front () { public front () {
return this.scopes[0] return this.scopes[0]
} }
private findScope (key: string) { private findScope (key: string) {
+3 -3
View File
@@ -1,8 +1,8 @@
import { Drop } from '../drop/drop' import { Drop } from '../drop/drop'
type PlainObject = { interface PlainObject {
[key: string]: any [key: string]: any;
toLiquid?: () => any toLiquid?: () => any;
} }
export type Scope = PlainObject | Drop export type Scope = PlainObject | Drop
+1 -1
View File
@@ -2,7 +2,7 @@ import { isNil, isString, toValue } from '../util/underscore'
import { EmptyDrop } from '../drop/empty-drop' import { EmptyDrop } from '../drop/empty-drop'
export class BlankDrop extends EmptyDrop { export class BlankDrop extends EmptyDrop {
equals (value: any) { public equals (value: any) {
if (value === false) return true if (value === false) return true
if (isNil(toValue(value))) return true if (isNil(toValue(value))) return true
if (isString(value)) return /^\s*$/.test(value) if (isString(value)) return /^\s*$/.test(value)
+2 -2
View File
@@ -1,9 +1,9 @@
export abstract class Drop { export abstract class Drop {
valueOf (): any { public valueOf (): any {
return undefined return undefined
} }
liquidMethodMissing (key: string): Promise<string | undefined> | string | undefined { public liquidMethodMissing (key: string): Promise<string | undefined> | string | undefined {
return undefined return undefined
} }
} }
+6 -6
View File
@@ -3,24 +3,24 @@ import { IComparable } from './icomparable'
import { isObject, isString, isArray } from '../util/underscore' import { isObject, isString, isArray } from '../util/underscore'
export class EmptyDrop extends Drop implements IComparable { export class EmptyDrop extends Drop implements IComparable {
equals (value: any) { public equals (value: any) {
if (isString(value) || isArray(value)) return value.length === 0 if (isString(value) || isArray(value)) return value.length === 0
if (isObject(value)) return Object.keys(value).length === 0 if (isObject(value)) return Object.keys(value).length === 0
return false return false
} }
gt () { public gt () {
return false return false
} }
geq () { public geq () {
return false return false
} }
lt () { public lt () {
return false return false
} }
leq () { public leq () {
return false return false
} }
valueOf () { public valueOf () {
return '' return ''
} }
} }
+10 -10
View File
@@ -2,33 +2,33 @@ import { Drop } from './drop'
export class ForloopDrop extends Drop { export class ForloopDrop extends Drop {
protected i: number = 0 protected i: number = 0
length: number public length: number
constructor (length: number) { public constructor (length: number) {
super() super()
this.length = length this.length = length
} }
next () { public next () {
this.i++ this.i++
} }
index0 () { public index0 () {
return this.i return this.i
} }
index () { public index () {
return this.i + 1 return this.i + 1
} }
first () { public first () {
return this.i === 0 return this.i === 0
} }
last () { public last () {
return this.i === this.length - 1 return this.i === this.length - 1
} }
rindex () { public rindex () {
return this.length - this.i return this.length - this.i
} }
rindex0 () { public rindex0 () {
return this.length - this.i - 1 return this.length - this.i - 1
} }
valueOf () { public valueOf () {
return JSON.stringify(this) return JSON.stringify(this)
} }
} }
+5 -5
View File
@@ -1,11 +1,11 @@
import { isFunction } from '../util/underscore' import { isFunction } from '../util/underscore'
export interface IComparable { export interface IComparable {
equals: (rhs: any) => boolean equals: (rhs: any) => boolean;
gt: (rhs: any) => boolean gt: (rhs: any) => boolean;
geq: (rhs: any) => boolean geq: (rhs: any) => boolean;
lt: (rhs: any) => boolean lt: (rhs: any) => boolean;
leq: (rhs: any) => boolean leq: (rhs: any) => boolean;
} }
export function isComparable (arg: any): arg is IComparable { export function isComparable (arg: any): arg is IComparable {
+6 -6
View File
@@ -4,22 +4,22 @@ import { isNil, toValue } from '../util/underscore'
import { BlankDrop } from '../drop/blank-drop' import { BlankDrop } from '../drop/blank-drop'
export class NullDrop extends Drop implements IComparable { export class NullDrop extends Drop implements IComparable {
equals (value: any) { public equals (value: any) {
return isNil(toValue(value)) || value instanceof BlankDrop return isNil(toValue(value)) || value instanceof BlankDrop
} }
gt () { public gt () {
return false return false
} }
geq () { public geq () {
return false return false
} }
lt () { public lt () {
return false return false
} }
leq () { public leq () {
return false return false
} }
valueOf () { public valueOf () {
return null return null
} }
} }
+6 -6
View File
@@ -2,24 +2,24 @@ import { ForloopDrop } from './forloop-drop'
export class TablerowloopDrop extends ForloopDrop { export class TablerowloopDrop extends ForloopDrop {
private cols: number private cols: number
constructor (length: number, cols: number) { public constructor (length: number, cols: number) {
super(length) super(length)
this.length = length this.length = length
this.cols = cols this.cols = cols
} }
row () { public row () {
return Math.floor(this.i / this.cols) + 1 return Math.floor(this.i / this.cols) + 1
} }
col0 () { public col0 () {
return (this.i % this.cols) return (this.i % this.cols)
} }
col () { public col () {
return this.col0() + 1 return this.col0() + 1
} }
col_first () { // eslint-disable-line public col_first () { // eslint-disable-line
return this.col0() === 0 return this.col0() === 0
} }
col_last () { // eslint-disable-line public col_last () { // eslint-disable-line
return this.col() === this.cols return this.col() === this.cols
} }
} }
+3 -3
View File
@@ -1,5 +1,5 @@
export default interface IFS { export default interface IFS {
exists: (filepath: string) => Promise<boolean> exists: (filepath: string) => Promise<boolean>;
readFile: (filepath:string) => Promise<string> readFile: (filepath: string) => Promise<string>;
resolve: (root: string, file: string, ext: string) => string resolve: (root: string, file: string, ext: string) => string;
} }
+32 -32
View File
@@ -3,57 +3,57 @@ import IFS from './fs/ifs'
export interface LiquidOptions { 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[] 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` 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 extname?: string;
/** `cache` indicates whether or not to cache resolved templates. Defaults to `false`. */ /** `cache` indicates whether or not to cache resolved templates. Defaults to `false`. */
cache?: boolean cache?: boolean;
/** `dynamicPartials`: if set, treat `<filepath>` parameter in `{%include filepath %}`, `{%layout filepath%}` as a variable, otherwise as a literal value. Defaults to `true`. */ /** `dynamicPartials`: if set, treat `<filepath>` parameter in `{%include filepath %}`, `{%layout filepath%}` as a variable, otherwise as a literal value. Defaults to `true`. */
dynamicPartials?: boolean dynamicPartials?: boolean;
/** `strictFilters` 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`. */ /** `strictFilters` 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`. */
strictFilters?: boolean strictFilters?: boolean;
/** `strictVariables` 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`. */ /** `strictVariables` 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`. */
strictVariables?: boolean strictVariables?: boolean;
/** `trimTagRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`. */ /** `trimTagRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`. */
trimTagRight?: boolean trimTagRight?: boolean;
/** `trimTagLeft` is similar to `trimTagRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */ /** `trimTagLeft` is similar to `trimTagRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trimTagLeft?: boolean trimTagLeft?: boolean;
/** ``trimOutputRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). Defaults to `false`. */ /** ``trimOutputRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). Defaults to `false`. */
trimOutputRight?: boolean trimOutputRight?: boolean;
/** `trimOutputLeft` is similar to `trimOutputRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */ /** `trimOutputLeft` is similar to `trimOutputRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trimOutputLeft?: boolean trimOutputLeft?: boolean;
/** `tagDelimiterLeft` and `tagDelimiterRight` are used to override the delimiter for liquid tags **/ /** `tagDelimiterLeft` and `tagDelimiterRight` are used to override the delimiter for liquid tags **/
tagDelimiterLeft?: string, tagDelimiterLeft?: string;
tagDelimiterRight?: string, tagDelimiterRight?: string;
/** `outputDelimiterLeft` and `outputDelimiterRight` are used to override the delimiter for liquid outputs **/ /** `outputDelimiterLeft` and `outputDelimiterRight` are used to override the delimiter for liquid outputs **/
outputDelimiterLeft?: string, outputDelimiterLeft?: string;
outputDelimiterRight?: string, outputDelimiterRight?: string;
/** `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` 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, greedy?: boolean;
/** `fs` is used to override the default file-system module with a custom implementation */ /** `fs` is used to override the default file-system module with a custom implementation */
fs?: IFS fs?: IFS;
} }
interface NormalizedOptions extends LiquidOptions { interface NormalizedOptions extends LiquidOptions {
root?: string[] root?: string[];
} }
export interface NormalizedFullOptions extends NormalizedOptions { export interface NormalizedFullOptions extends NormalizedOptions {
root: string[] root: string[];
extname: string extname: string;
cache: boolean cache: boolean;
dynamicPartials: boolean dynamicPartials: boolean;
strictFilters: boolean strictFilters: boolean;
strictVariables: boolean strictVariables: boolean;
trimTagRight: boolean trimTagRight: boolean;
trimTagLeft: boolean trimTagLeft: boolean;
trimOutputRight: boolean trimOutputRight: boolean;
trimOutputLeft: boolean trimOutputLeft: boolean;
tagDelimiterLeft: string, tagDelimiterLeft: string;
tagDelimiterRight: string, tagDelimiterRight: string;
outputDelimiterLeft: string, outputDelimiterLeft: string;
outputDelimiterRight: string, outputDelimiterRight: string;
greedy: boolean greedy: boolean;
} }
const defaultOptions: NormalizedFullOptions = { const defaultOptions: NormalizedFullOptions = {
+17 -17
View File
@@ -25,7 +25,7 @@ export default class Liquid {
private tokenizer: Tokenizer private tokenizer: Tokenizer
private fs: IFS private fs: IFS
constructor (opts: LiquidOptions = {}) { public constructor (opts: LiquidOptions = {}) {
this.options = applyDefault(normalize(opts)) this.options = applyDefault(normalize(opts))
this.parser = new Parser(this) this.parser = new Parser(this)
this.renderer = new Render() this.renderer = new Render()
@@ -35,20 +35,20 @@ export default class Liquid {
_.forOwn(builtinTags, (conf, name) => this.registerTag(name, conf)) _.forOwn(builtinTags, (conf, name) => this.registerTag(name, conf))
_.forOwn(builtinFilters, (handler, name) => this.registerFilter(name, handler)) _.forOwn(builtinFilters, (handler, name) => this.registerFilter(name, handler))
} }
parse (html: string, filepath?: string) { public parse (html: string, filepath?: string) {
const tokens = this.tokenizer.tokenize(html, filepath) const tokens = this.tokenizer.tokenize(html, filepath)
return this.parser.parse(tokens) return this.parser.parse(tokens)
} }
render (tpl: Array<ITemplate>, ctx?: object, opts?: LiquidOptions) { public render (tpl: ITemplate[], ctx?: object, opts?: LiquidOptions) {
const options = { ...this.options, ...normalize(opts) } const options = { ...this.options, ...normalize(opts) }
const scope = new Context(ctx, options) const scope = new Context(ctx, options)
return this.renderer.renderTemplates(tpl, scope) return this.renderer.renderTemplates(tpl, scope)
} }
async parseAndRender (html: string, ctx?: object, opts?: LiquidOptions) { public async parseAndRender (html: string, ctx?: object, opts?: LiquidOptions) {
const tpl = await this.parse(html) const tpl = await this.parse(html)
return this.render(tpl, ctx, opts) return this.render(tpl, ctx, opts)
} }
async getTemplate (file: string, opts?: LiquidOptions) { public async getTemplate (file: string, opts?: LiquidOptions) {
const options = normalize(opts) const options = normalize(opts)
const roots = options.root ? [...options.root, ...this.options.root] : this.options.root const roots = options.root ? [...options.root, ...this.options.root] : this.options.root
const paths = roots.map(root => this.fs.resolve(root, file, this.options.extname)) const paths = roots.map(root => this.fs.resolve(root, file, this.options.extname))
@@ -68,34 +68,34 @@ export default class Liquid {
err.code = 'ENOENT' err.code = 'ENOENT'
throw err throw err
} }
async renderFile (file: string, ctx?: object, opts?: LiquidOptions) { public async renderFile (file: string, ctx?: object, opts?: LiquidOptions) {
const options = normalize(opts) const options = normalize(opts)
const templates = await this.getTemplate(file, options) const templates = await this.getTemplate(file, options)
return this.render(templates, ctx, opts) return this.render(templates, ctx, opts)
} }
evalValue (str: string, ctx: Context) { public evalValue (str: string, ctx: Context) {
return new Value(str, this.options.strictFilters).value(ctx) return new Value(str, this.options.strictFilters).value(ctx)
} }
registerFilter (name: string, filter: FilterImplOptions) { public registerFilter (name: string, filter: FilterImplOptions) {
return Filter.register(name, filter) return Filter.register(name, filter)
} }
registerTag (name: string, tag: ITagImplOptions) { public registerTag (name: string, tag: ITagImplOptions) {
return Tag.register(name, tag) return Tag.register(name, tag)
} }
plugin (plugin: (this: Liquid, L: typeof Liquid) => void) { public plugin (plugin: (this: Liquid, L: typeof Liquid) => void) {
return plugin.call(this, Liquid) return plugin.call(this, Liquid)
} }
express () { public express () {
const self = this const self = this
return function (this: any, filePath: string, ctx: object, cb: (err: Error | null, html?: string) => void) { return function (this: any, filePath: string, ctx: object, cb: (err: Error | null, html?: string) => void) {
const opts = { root: this.root } const opts = { root: this.root }
self.renderFile(filePath, ctx, opts).then(html => cb(null, html), cb) self.renderFile(filePath, ctx, opts).then(html => cb(null, html), cb)
} }
} }
static default = Liquid public static default = Liquid
static isTruthy = isTruthy public static isTruthy = isTruthy
static isFalsy = isFalsy public static isFalsy = isFalsy
static evalExp = evalExp public static evalExp = evalExp
static evalValue = evalValue public static evalValue = evalValue
static Types = Types public static Types = Types
} }
+1 -1
View File
@@ -2,7 +2,7 @@ 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 {
constructor ( public constructor (
raw: string, raw: string,
value: string, value: string,
input: string, input: string,
+2 -2
View File
@@ -1,12 +1,12 @@
import Token from './token' import Token from './token'
export default class HTMLToken extends Token { export default class HTMLToken extends Token {
constructor (str: string, input: string, line: number, col: number, file?: string) { public constructor (str: string, input: string, line: number, col: number, file?: string) {
super(str, input, line, col, file) super(str, input, line, col, file)
this.type = 'html' this.type = 'html'
this.value = str this.value = str
} }
static is (token: Token): token is HTMLToken { public static is (token: Token): token is HTMLToken {
return token.type === 'html' return token.type === 'html'
} }
} }
+2 -2
View File
@@ -3,7 +3,7 @@ import Token from './token'
import { NormalizedFullOptions } from '../liquid-options' import { NormalizedFullOptions } from '../liquid-options'
export default class OutputToken extends DelimitedToken { export default class OutputToken extends DelimitedToken {
constructor ( public constructor (
raw: string, raw: string,
value: string, value: string,
input: string, input: string,
@@ -15,7 +15,7 @@ export default class OutputToken extends DelimitedToken {
super(raw, value, input, line, pos, options.trimOutputLeft, options.trimOutputRight, file) super(raw, value, input, line, pos, options.trimOutputLeft, options.trimOutputRight, file)
this.type = 'output' this.type = 'output'
} }
static is (token: Token): token is OutputToken { public static is (token: Token): token is OutputToken {
return token.type === 'output' return token.type === 'output'
} }
} }
+6 -6
View File
@@ -2,19 +2,19 @@ import Token from '../parser/token'
import ITemplate from '../template/itemplate' import ITemplate from '../template/itemplate'
import TagToken from './tag-token' import TagToken from './tag-token'
type ParseToken = ((token: Token, remainTokens: Array<Token>) => ITemplate) type ParseToken = ((token: Token, remainTokens: Token[]) => ITemplate)
export default class ParseStream { export default class ParseStream {
private tokens: Array<Token> private tokens: Token[]
private handlers: {[key: string]: (arg: any) => void} = {} private handlers: {[key: string]: (arg: any) => void} = {}
private stopRequested: boolean = false private stopRequested: boolean = false
private parseToken: ParseToken private parseToken: ParseToken
constructor (tokens: Array<Token>, parseToken: ParseToken) { public constructor (tokens: Token[], parseToken: ParseToken) {
this.tokens = tokens this.tokens = tokens
this.parseToken = parseToken this.parseToken = parseToken
} }
on<T extends ITemplate | Token | undefined> (name: string, cb: (arg: T) => void): ParseStream { public on<T extends ITemplate | Token | undefined> (name: string, cb: (arg: T) => void): ParseStream {
this.handlers[name] = cb this.handlers[name] = cb
return this return this
} }
@@ -22,7 +22,7 @@ export default class ParseStream {
const h = this.handlers[event] const h = this.handlers[event]
return h ? (h(arg), true) : false return h ? (h(arg), true) : false
} }
start () { public 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())) {
@@ -36,7 +36,7 @@ export default class ParseStream {
if (!this.stopRequested) this.trigger('end') if (!this.stopRequested) this.trigger('end')
return this return this
} }
stop () { public stop () {
this.stopRequested = true this.stopRequested = true
return this return this
} }
+5 -5
View File
@@ -10,12 +10,12 @@ import HTML from '../template/html'
import ITemplate from '../template/itemplate' import ITemplate from '../template/itemplate'
export default class Parser { export default class Parser {
liquid: Liquid private liquid: Liquid
constructor (liquid: Liquid) { public constructor (liquid: Liquid) {
this.liquid = liquid this.liquid = liquid
} }
parse (tokens: Array<Token>) { public parse (tokens: Token[]) {
let token let token
const templates: ITemplate[] = [] const templates: ITemplate[] = []
while ((token = tokens.shift())) { while ((token = tokens.shift())) {
@@ -23,7 +23,7 @@ export default class Parser {
} }
return templates return templates
} }
parseToken (token: Token, remainTokens: Array<Token>) { public parseToken (token: Token, remainTokens: Token[]) {
try { try {
if (TagToken.is(token)) { if (TagToken.is(token)) {
return new Tag(token, remainTokens, this.liquid) return new Tag(token, remainTokens, this.liquid)
@@ -36,7 +36,7 @@ export default class Parser {
throw new ParseError(e, token) throw new ParseError(e, token)
} }
} }
parseStream (tokens: Array<Token>) { public parseStream (tokens: Token[]) {
return new ParseStream(tokens, (token, tokens) => this.parseToken(token, tokens)) return new ParseStream(tokens, (token, tokens) => this.parseToken(token, tokens))
} }
} }
+4 -4
View File
@@ -5,9 +5,9 @@ import * as lexical from './lexical'
import { NormalizedFullOptions } from '../liquid-options' import { NormalizedFullOptions } from '../liquid-options'
export default class TagToken extends DelimitedToken { export default class TagToken extends DelimitedToken {
name: string public name: string
args: string public args: string
constructor ( public constructor (
raw: string, raw: string,
value: string, value: string,
input: string, input: string,
@@ -25,7 +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 { public static is (token: Token): token is TagToken {
return token.type === 'tag' return token.type === 'tag'
} }
} }
+10 -10
View File
@@ -1,14 +1,14 @@
export default class Token { export default class Token {
trimLeft: boolean = false public trimLeft: boolean = false
trimRight: boolean = false public trimRight: boolean = false
type: string = 'notset' public type: string = 'notset'
line: number public line: number
col: number public col: number
raw: string public raw: string
input: string public input: string
file?: string public file?: string
value: string public value: string
constructor (raw: string, input: string, line: number, col: number, file?: string) { public constructor (raw: string, input: string, line: number, col: number, file?: string) {
this.col = col this.col = col
this.line = line this.line = line
this.raw = raw this.raw = raw
+2 -2
View File
@@ -10,10 +10,10 @@ enum ParseState { HTML, OUTPUT, TAG }
export default class Tokenizer { export default class Tokenizer {
private options: NormalizedFullOptions private options: NormalizedFullOptions
constructor (options?: NormalizedFullOptions) { public constructor (options?: NormalizedFullOptions) {
this.options = applyDefault(options) this.options = applyDefault(options)
} }
tokenize (input: string, file?: string) { public tokenize (input: string, file?: string) {
const tokens: Token[] = [] const tokens: Token[] = []
const { const {
tagDelimiterLeft, tagDelimiterLeft,
+1 -1
View File
@@ -4,7 +4,7 @@ import Context from '../context/context'
import ITemplate from '../template/itemplate' import ITemplate from '../template/itemplate'
export default class Render { export default class Render {
async renderTemplates (templates: ITemplate[], ctx: Context) { public async renderTemplates (templates: ITemplate[], ctx: Context) {
assert(ctx, 'unable to evalTemplates: context undefined') assert(ctx, 'unable to evalTemplates: context undefined')
let html = '' let html = ''
+1 -1
View File
@@ -1,5 +1,5 @@
import Context from '../../context/context' import Context from '../../context/context'
export interface FilterImpl { export interface FilterImpl {
context: Context context: Context;
} }
+8 -8
View File
@@ -5,15 +5,15 @@ import { FilterImplOptions } from './filter-impl-options'
type KeyValuePair = [string?, string?] type KeyValuePair = [string?, string?]
type FilterArg = string|KeyValuePair type FilterArg = string|KeyValuePair
export type FilterArgs = Array<FilterArg> export type FilterArgs = FilterArg[]
export class Filter { export class Filter {
name: string private name: string
impl: FilterImplOptions private impl: FilterImplOptions
args: FilterArgs private args: FilterArgs
private static impls: {[key: string]: FilterImplOptions} = {} private static impls: {[key: string]: FilterImplOptions} = {}
constructor (name: string, args: FilterArgs, strictFilters: boolean) { public constructor (name: string, args: FilterArgs, strictFilters: boolean) {
const impl = Filter.impls[name] const impl = Filter.impls[name]
if (!impl && strictFilters) throw new TypeError(`undefined filter: ${name}`) if (!impl && strictFilters) throw new TypeError(`undefined filter: ${name}`)
@@ -21,7 +21,7 @@ export class Filter {
this.impl = impl || (x => x) this.impl = impl || (x => x)
this.args = args this.args = args
} }
async render (value: any, context: Context) { public async render (value: any, context: Context) {
const argv: any[] = [] const argv: any[] = []
for (const arg of this.args) { for (const arg of this.args) {
if (isKeyValuePair(arg)) argv.push([arg[0], await parseValue(arg[1], context)]) if (isKeyValuePair(arg)) argv.push([arg[0], await parseValue(arg[1], context)])
@@ -29,10 +29,10 @@ export class Filter {
} }
return this.impl.apply({ context }, [value, ...argv]) return this.impl.apply({ context }, [value, ...argv])
} }
static register (name: string, filter: FilterImplOptions) { public static register (name: string, filter: FilterImplOptions) {
Filter.impls[name] = filter Filter.impls[name] = filter
} }
static clear () { public static clear () {
Filter.impls = {} Filter.impls = {}
} }
} }
+3 -3
View File
@@ -3,12 +3,12 @@ import ITemplate from '../template/itemplate'
import HTMLToken from '../parser/html-token' import HTMLToken from '../parser/html-token'
export default class extends Template<HTMLToken> implements ITemplate { export default class extends Template<HTMLToken> implements ITemplate {
str: string private str: string
constructor (token: HTMLToken) { public constructor (token: HTMLToken) {
super(token) super(token)
this.str = token.value this.str = token.value
} }
async render (): Promise<string> { public async render (): Promise<string> {
return this.str return this.str
} }
} }
+3 -3
View File
@@ -6,12 +6,12 @@ import Context from '../context/context'
import OutputToken from '../parser/output-token' import OutputToken from '../parser/output-token'
export default class Output extends Template<OutputToken> implements ITemplate { export default class Output extends Template<OutputToken> implements ITemplate {
value: Value private value: Value
constructor (token: OutputToken, strictFilters: boolean) { public constructor (token: OutputToken, strictFilters: boolean) {
super(token) super(token)
this.value = new Value(token.value, strictFilters) this.value = new Value(token.value, strictFilters)
} }
async render (ctx: Context): Promise<string> { public async render (ctx: Context): Promise<string> {
const val = await this.value.value(ctx) const val = await this.value.value(ctx)
return stringify(toValue(val)) return stringify(toValue(val))
} }
+1 -1
View File
@@ -10,7 +10,7 @@ import Context from '../../context/context'
*/ */
export default class Hash { export default class Hash {
[key: string]: any [key: string]: any
static async create (markup: string, ctx: Context) { public static async create (markup: string, ctx: Context) {
const instance = new Hash() const instance = new Hash()
let match let match
hashCapture.lastIndex = 0 hashCapture.lastIndex = 0
+2 -2
View File
@@ -5,6 +5,6 @@ import Hash from '../../template/tag/hash'
import ITagImpl from './itag-impl' import ITagImpl from './itag-impl'
export default interface ITagImplOptions { export default interface ITagImplOptions {
parse?: (this: ITagImpl, token: TagToken, remainingTokens: Array<Token>) => void parse?: (this: ITagImpl, token: TagToken, remainingTokens: Token[]) => void;
render?: (this: ITagImpl, ctx: Context, hash: Hash) => any | Promise<any> render?: (this: ITagImpl, ctx: Context, hash: Hash) => any | Promise<any>;
} }
+2 -2
View File
@@ -2,6 +2,6 @@ import Liquid from '../../liquid'
import ITagImplOptions from './itag-impl-options' import ITagImplOptions from './itag-impl-options'
export default interface ITagImpl extends ITagImplOptions { export default interface ITagImpl extends ITagImplOptions {
liquid: Liquid, liquid: Liquid;
[key: string]: any [key: string]: any;
} }
+6 -6
View File
@@ -11,11 +11,11 @@ import TagToken from '../../parser/tag-token'
import Token from '../../parser/token' import Token from '../../parser/token'
export default class Tag extends Template<TagToken> implements ITemplate { export default class Tag extends Template<TagToken> implements ITemplate {
name: string public name: string
private impl: ITagImpl private impl: ITagImpl
static impls: { [key: string]: ITagImplOptions } = {} private static impls: { [key: string]: ITagImplOptions } = {}
constructor (token: TagToken, tokens: Token[], liquid: Liquid) { public constructor (token: TagToken, tokens: Token[], liquid: Liquid) {
super(token) super(token)
this.name = token.name this.name = token.name
@@ -28,15 +28,15 @@ export default class Tag extends Template<TagToken> implements ITemplate {
this.impl.parse(token, tokens) this.impl.parse(token, tokens)
} }
} }
async render (ctx: Context) { public 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
return isFunction(impl.render) ? stringify(await impl.render(ctx, hash)) : '' return isFunction(impl.render) ? stringify(await impl.render(ctx, hash)) : ''
} }
static register (name: string, tag: ITagImplOptions) { public static register (name: string, tag: ITagImplOptions) {
Tag.impls[name] = tag Tag.impls[name] = tag
} }
static clear () { public static clear () {
Tag.impls = {} Tag.impls = {}
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
export default abstract class Template<T> { export default abstract class Template<T> {
token: T; public token: T;
constructor (token: T) { public constructor (token: T) {
this.token = token this.token = token
} }
} }
+5 -5
View File
@@ -5,12 +5,12 @@ import Context from '../context/context'
export default class Value { export default class Value {
private strictFilters: boolean private strictFilters: boolean
private initial: string private initial: string
private filters: Array<Filter> = [] private filters: Filter[] = []
/** /**
* @param str value string, like: "i have a dream | truncate: 3 * @param str value string, like: "i have a dream | truncate: 3
*/ */
constructor (str: string, strictFilters: boolean) { public constructor (str: string, strictFilters: boolean) {
const tokens = Value.tokenize(str) const tokens = Value.tokenize(str)
this.strictFilters = strictFilters this.strictFilters = strictFilters
this.initial = tokens[0] this.initial = tokens[0]
@@ -35,7 +35,7 @@ export default class Value {
for (let i = begin + 1; i < end + 1; i++) { for (let i = begin + 1; i < end + 1; i++) {
if (i === end || tokens[i] === ',') { if (i === end || tokens[i] === ',') {
if (argName || argValue) { if (argName || argValue) {
args.push(argName ? [argName, argValue] : <string>argValue) args.push(argName ? [argName, argValue] : argValue as string)
} }
argValue = argName = undefined argValue = argName = undefined
} else if (tokens[i] === ':') { } else if (tokens[i] === ':') {
@@ -47,14 +47,14 @@ export default class Value {
} }
this.filters.push(new Filter(name, args, this.strictFilters)) this.filters.push(new Filter(name, args, this.strictFilters))
} }
async value (ctx: Context) { public async value (ctx: Context) {
let val = await parseExp(this.initial, ctx) let val = await parseExp(this.initial, ctx)
for (const filter of this.filters) { for (const filter of this.filters) {
val = await filter.render(val, ctx) val = await filter.render(val, ctx)
} }
return val return val
} }
static tokenize (str: string): Array<'|' | ',' | ':' | string> { public static tokenize (str: string): ('|' | ',' | ':' | string)[] {
const tokens = [] const tokens = []
let i = 0 let i = 0
while (i < str.length) { while (i < str.length) {
+7 -7
View File
@@ -5,7 +5,7 @@ import ITemplate from '../template/itemplate'
abstract class LiquidError extends Error { abstract class LiquidError extends Error {
private token: Token private token: Token
private originalError: Error private originalError: Error
constructor (err: Error, token: Token) { public constructor (err: Error, token: Token) {
super(err.message) super(err.message)
this.originalError = err this.originalError = err
this.token = token this.token = token
@@ -20,7 +20,7 @@ abstract class LiquidError extends Error {
} }
export class TokenizationError extends LiquidError { export class TokenizationError extends LiquidError {
constructor (message: string, token: Token) { public constructor (message: string, token: Token) {
super(new Error(message), token) super(new Error(message), token)
this.name = 'TokenizationError' this.name = 'TokenizationError'
super.update() super.update()
@@ -28,7 +28,7 @@ export class TokenizationError extends LiquidError {
} }
export class ParseError extends LiquidError { export class ParseError extends LiquidError {
constructor (err: Error, token: Token) { public constructor (err: Error, token: Token) {
super(err, token) super(err, token)
this.name = 'ParseError' this.name = 'ParseError'
this.message = err.message this.message = err.message
@@ -37,7 +37,7 @@ export class ParseError extends LiquidError {
} }
export class RenderError extends LiquidError { export class RenderError extends LiquidError {
constructor (err: Error, tpl: ITemplate) { public constructor (err: Error, tpl: ITemplate) {
super(err, tpl.token) super(err, tpl.token)
this.name = 'RenderError' this.name = 'RenderError'
this.message = err.message this.message = err.message
@@ -46,8 +46,8 @@ export class RenderError extends LiquidError {
} }
export class RenderBreakError extends Error { export class RenderBreakError extends Error {
resolvedHTML: string = '' public resolvedHTML: string = ''
constructor (message: string) { public constructor (message: string) {
super(message) super(message)
this.name = 'RenderBreakError' this.name = 'RenderBreakError'
this.message = message + '' this.message = message + ''
@@ -55,7 +55,7 @@ export class RenderBreakError extends Error {
} }
export class AssertionError extends Error { export class AssertionError extends Error {
constructor (message: string) { public constructor (message: string) {
super(message) super(message)
this.name = 'AssertionError' this.name = 'AssertionError'
this.message = message + '' this.message = message + ''
+1 -1
View File
@@ -16,7 +16,7 @@ export function isFunction (value: any): value is Function {
} }
export function promisify<T1, T2> (fn: (arg1: T1, cb: (err: Error | null, result: T2) => void) => void): (arg1: T1) => Promise<T2>; export function promisify<T1, T2> (fn: (arg1: T1, cb: (err: Error | null, result: T2) => void) => void): (arg1: T1) => Promise<T2>;
export function promisify<T1, T2, T3> (fn: (arg1: T1, arg2: T2, cb: (err: Error | null, result: T3) => void) => void):(arg1: T1, arg2: T2) => Promise<T3>; export function promisify<T1, T2, T3> (fn: (arg1: T1, arg2: T2, cb: (err: Error | null, result: T3) => void) => void): (arg1: T1, arg2: T2) => Promise<T3>;
export function promisify (fn: any) { export function promisify (fn: any) {
return function (...args: any[]) { return function (...args: any[]) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
+6 -6
View File
@@ -5,11 +5,11 @@ import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised) use(chaiAsPromised)
class SettingsDrop extends Liquid.Types.Drop { class SettingsDrop extends Liquid.Types.Drop {
foo: string = 'FOO' private foo: string = 'FOO'
bar () { public bar () {
return 'BAR' return 'BAR'
} }
liquidMethodMissing (key: string) { public liquidMethodMissing (key: string) {
return key.toUpperCase() return key.toUpperCase()
} }
} }
@@ -29,10 +29,10 @@ describe('drop', function () {
describe('BlandDrop', function () { describe('BlandDrop', function () {
it('should test blank strings', async function () { it('should test blank strings', async function () {
const src = ` const src = `
{% unless settings.fp_heading == blank %} {% unless settings.fpHeading == blank %}
<h1>{{ settings.fp_heading }}</h1> <h1>{{ settings.fpHeading }}</h1>
{% endunless %}` {% endunless %}`
var ctx = { settings: { fp_heading: '' } } var ctx = { settings: { fpHeading: '' } }
const html = await engine.parseAndRender(src, ctx) const html = await engine.parseAndRender(src, ctx)
return expect(html).to.match(/^\s+$/) return expect(html).to.match(/^\s+$/)
}) })
+2 -2
View File
@@ -136,7 +136,7 @@ describe('xhr', () => {
[200, { 'Content-Type': 'text/plain' }, 'foo2']) [200, { 'Content-Type': 'text/plain' }, 'foo2'])
return engine.renderFile('foo.html') return engine.renderFile('foo.html')
}) })
.then((html:string) => expect(html).to.equal('foo2')) .then((html: string) => expect(html).to.equal('foo2'))
}) })
it('should respect cache=true option', () => { it('should respect cache=true option', () => {
engine = new Liquid({ engine = new Liquid({
@@ -153,7 +153,7 @@ describe('xhr', () => {
[200, { 'Content-Type': 'text/plain' }, 'foo2']) [200, { 'Content-Type': 'text/plain' }, 'foo2'])
return engine.renderFile('foo.html') return engine.renderFile('foo.html')
}) })
.then((html:string) => expect(html).to.equal('foo1')) .then((html: string) => expect(html).to.equal('foo1'))
}) })
}) })
}) })
+2 -2
View File
@@ -85,7 +85,7 @@ describe('tags/include', function () {
}) })
it('should support include: with as Liquid Drop', async function () { it('should support include: with as Liquid Drop', async function () {
class ColorDrop extends Liquid.Types.Drop { class ColorDrop extends Liquid.Types.Drop {
valueOf (): string { public valueOf (): string {
return 'red!' return 'red!'
} }
} }
@@ -98,7 +98,7 @@ describe('tags/include', function () {
}) })
it('should support include: with passed as Liquid Drop', async function () { it('should support include: with passed as Liquid Drop', async function () {
class ColorDrop extends Liquid.Types.Drop { class ColorDrop extends Liquid.Types.Drop {
valueOf (): string { public valueOf (): string {
return 'red!' return 'red!'
} }
} }
+6 -6
View File
@@ -6,22 +6,22 @@ describe('drop/drop', function () {
before(() => (liquid = new Liquid())) before(() => (liquid = new Liquid()))
class CustomDrop extends Liquid.Types.Drop { class CustomDrop extends Liquid.Types.Drop {
name: string = 'NAME' private name: string = 'NAME'
getName () { public getName () {
return 'GET NAME' return 'GET NAME'
} }
} }
class CustomDropWithMethodMissing extends CustomDrop { class CustomDropWithMethodMissing extends CustomDrop {
liquidMethodMissing (key: string) { public liquidMethodMissing (key: string) {
return key.toUpperCase() return key.toUpperCase()
} }
} }
class PromiseDrop extends Liquid.Types.Drop { class PromiseDrop extends Liquid.Types.Drop {
name = Promise.resolve('NAME') private name = Promise.resolve('NAME')
async getName () { public async getName () {
return 'GET NAME' return 'GET NAME'
} }
async liquidMethodMissing (key: string) { public async liquidMethodMissing (key: string) {
return key.toUpperCase() return key.toUpperCase()
} }
} }
+7 -4
View File
@@ -2,17 +2,20 @@ import { isString, forOwn } from '../../src/util/underscore'
import fs from '../../src/fs/node' import fs from '../../src/fs/node'
import { resolve } from 'path' import { resolve } from 'path'
type fileDescriptor = { mode: string, content: string } interface FileDescriptor {
mode: string;
content: string;
}
let files: { [path: string]: fileDescriptor } = {} let files: { [path: string]: FileDescriptor } = {}
const readFile = fs.readFile const readFile = fs.readFile
const exists = fs.exists const exists = fs.exists
export function mock (options: { [path: string]: (string | fileDescriptor) }) { export function mock (options: { [path: string]: (string | FileDescriptor) }) {
forOwn(options, (val, key) => { forOwn(options, (val, key) => {
files[resolve(key)] = isString(val) files[resolve(key)] = isString(val)
? { mode: '33188', content: val } ? { mode: '33188', content: val }
: val as fileDescriptor : val as FileDescriptor
}) })
fs.readFile = async function (path) { fs.readFile = async function (path) {
const file = files[path] const file = files[path]
+4 -4
View File
@@ -1,12 +1,12 @@
import * as chai from 'chai' import * as chai from 'chai'
import { isRange } from '../../../src/parser/lexical'
const expect = chai.expect const expect = chai.expect
const lexical = require('../../../src/parser/lexical')
describe('lexical', function () { describe('lexical', function () {
it('should test range literal', function () { it('should test range literal', function () {
expect(lexical.isRange('(12..32)')).to.equal(true) expect(isRange('(12..32)')).to.equal(true)
expect(lexical.isRange('(12..foo)')).to.equal(true) expect(isRange('(12..foo)')).to.equal(true)
expect(lexical.isRange('(foo.bar..foo)')).to.equal(true) expect(isRange('(foo.bar..foo)')).to.equal(true)
}) })
}) })