BREAKING CHANGE: trim_value_* -> trim_output_*

This commit is contained in:
harttle
2019-02-21 01:07:32 +08:00
parent d7d00421e2
commit 3dbab238ae
8 changed files with 53 additions and 34 deletions
+2 -2
View File
@@ -192,9 +192,9 @@ Otherwise, undefined variables will cause an exception. Defaults to `false`.
* `trim_tag_left` is similiar to `trim_tag_right`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details. * `trim_tag_left` is similiar to `trim_tag_right`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details.
* `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_output_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). Defaults to `false`.
* `trim_value_left` is similiar to `trim_value_right`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details. * `trim_output_left` is similiar to `trim_output_right`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details.
* `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`.
+31 -11
View File
@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
import * as _ from './util/underscore' import * as _ from './util/underscore'
export interface LiquidOptions { export interface LiquidOptions {
@@ -10,17 +12,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`: 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
/** `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` 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 // eslint-disable-line strict_filters?: boolean
/** `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` 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 // eslint-disable-line strict_variables?: boolean
/** `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` 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 // eslint-disable-line trim_tag_right?: boolean
/** `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` is similar to `trim_tag_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trim_tag_left?: boolean // eslint-disable-line trim_tag_left?: boolean
/** ``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_output_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 // eslint-disable-line trim_output_right?: boolean
/** `trim_value_left` is similar to `trim_value_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */ /** `trim_output_left` is similar to `trim_output_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trim_value_left?: boolean // eslint-disable-line trim_output_left?: boolean
/** `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
} }
@@ -29,15 +31,29 @@ export interface NormalizedOptions extends LiquidOptions {
root?: string[] root?: string[]
} }
export const defaultOptions: NormalizedOptions = { export interface NormalizedFullOptions extends NormalizedOptions {
root: string[]
extname: string
cache: boolean
dynamicPartials: boolean
strict_filters: boolean
strict_variables: boolean
trim_tag_right: boolean
trim_tag_left: boolean
trim_output_right: boolean
trim_output_left: boolean
greedy: boolean
}
const defaultOptions: NormalizedFullOptions = {
root: ['.'], root: ['.'],
cache: false, cache: false,
extname: '', extname: '',
dynamicPartials: true, dynamicPartials: true,
trim_tag_right: false, trim_tag_right: false,
trim_tag_left: false, trim_tag_left: false,
trim_value_right: false, trim_output_right: false,
trim_value_left: false, trim_output_left: false,
greedy: true, greedy: true,
strict_filters: false, strict_filters: false,
strict_variables: false strict_variables: false
@@ -51,6 +67,10 @@ export function normalize (options: LiquidOptions): NormalizedOptions {
return options as NormalizedOptions return options as NormalizedOptions
} }
export function applyDefault (options: NormalizedOptions): NormalizedFullOptions {
return { ...defaultOptions, ...options }
}
function normalizeStringArray (value: string | string[]): string[] { function normalizeStringArray (value: string | string[]): string[] {
if (_.isArray(value)) return value as string[] if (_.isArray(value)) return value as string[]
if (_.isString(value)) return [value as string] if (_.isString(value)) return [value as string]
+4 -5
View File
@@ -13,21 +13,20 @@ import Value from './template/value'
import { isTruthy, isFalsy, evalExp, evalValue } from './render/syntax' import { isTruthy, isFalsy, evalExp, evalValue } from './render/syntax'
import builtinTags from './builtin/tags' import builtinTags from './builtin/tags'
import builtinFilters from './builtin/filters' import builtinFilters from './builtin/filters'
import { LiquidOptions, NormalizedOptions, defaultOptions, normalize } from './liquid-options' import { LiquidOptions, NormalizedFullOptions, applyDefault, normalize } from './liquid-options'
export default class Liquid { export default class Liquid {
public options: NormalizedOptions public options: NormalizedFullOptions
private cache: object private cache: object
private parser: Parser private parser: Parser
private renderer: Render private renderer: Render
private tokenizer: Tokenizer private tokenizer: Tokenizer
constructor (opts: LiquidOptions = {}) { constructor (opts: LiquidOptions = {}) {
const options = { ...defaultOptions, ...normalize(opts) } this.options = applyDefault(normalize(opts))
if (options.cache) { if (this.options.cache) {
this.cache = {} this.cache = {}
} }
this.options = options
this.parser = new Parser(this) this.parser = new Parser(this)
this.renderer = new Render() this.renderer = new Render()
this.tokenizer = new Tokenizer(this.options) this.tokenizer = new Tokenizer(this.options)
+4 -4
View File
@@ -4,14 +4,14 @@ import TagToken from './tag-token'
import Token from './token' import Token from './token'
import OutputToken from './output-token' import OutputToken from './output-token'
import { TokenizationError } from 'src/util/error' import { TokenizationError } from 'src/util/error'
import { LiquidOptions, defaultOptions } from 'src/liquid-options' import { NormalizedFullOptions, applyDefault } from '../liquid-options'
enum ParseState { HTML, OUTPUT, TAG } enum ParseState { HTML, OUTPUT, TAG }
export default class Tokenizer { export default class Tokenizer {
options: LiquidOptions options: NormalizedFullOptions
constructor (options: LiquidOptions = defaultOptions) { constructor (options?: NormalizedFullOptions) {
this.options = options this.options = applyDefault(options)
} }
tokenize (input: string, file?: string) { tokenize (input: string, file?: string) {
const tokens = [] const tokens = []
+2 -2
View File
@@ -24,13 +24,13 @@ export default function whiteSpaceCtrl (tokens: Token[], options: LiquidOptions)
function shouldTrimLeft (token: DelimitedToken, inRaw: boolean, options) { function shouldTrimLeft (token: DelimitedToken, inRaw: boolean, options) {
if (inRaw) return false if (inRaw) return false
if (token.type === 'tag') return token.trimLeft || options.trim_tag_left if (token.type === 'tag') return token.trimLeft || options.trim_tag_left
if (token.type === 'output') return token.trimLeft || options.trim_value_left if (token.type === 'output') return token.trimLeft || options.trim_output_left
} }
function shouldTrimRight (token: DelimitedToken, inRaw: boolean, options) { function shouldTrimRight (token: DelimitedToken, inRaw: boolean, options) {
if (inRaw) return false if (inRaw) return false
if (token.type === 'tag') return token.trimRight || options.trim_tag_right if (token.type === 'tag') return token.trimRight || options.trim_tag_right
if (token.type === 'output') return token.trimRight || options.trim_value_right if (token.type === 'output') return token.trimRight || options.trim_output_right
} }
function trimLeft (token: Token, greedy: boolean) { function trimLeft (token: Token, greedy: boolean) {
+4 -4
View File
@@ -1,16 +1,16 @@
import * as _ from '../util/underscore' import * as _ from '../util/underscore'
import * as lexical from '../parser/lexical' import * as lexical from '../parser/lexical'
import assert from '../util/assert' import assert from '../util/assert'
import { NormalizedOptions, defaultOptions } from '../liquid-options' import { NormalizedFullOptions, applyDefault } from '../liquid-options'
import BlockMode from './block-mode' import BlockMode from './block-mode'
export default class Scope { export default class Scope {
opts: NormalizedOptions opts: NormalizedFullOptions
contexts: Array<object> contexts: Array<object>
blocks: object = {} blocks: object = {}
blockMode: BlockMode = BlockMode.OUTPUT blockMode: BlockMode = BlockMode.OUTPUT
constructor (ctx: object = {}, opts: NormalizedOptions = defaultOptions) { constructor (ctx: object = {}, opts?: NormalizedFullOptions) {
this.opts = { ...defaultOptions, ...opts } this.opts = applyDefault(opts)
this.contexts = [ctx || {}] this.contexts = [ctx || {}]
} }
getAll () { getAll () {
+5 -5
View File
@@ -22,18 +22,18 @@ describe('LiquidOptions#trimming', function () {
}) })
}) })
describe('value trimming', function () { describe('value trimming', function () {
it('should respect trim_value_left', async function () { it('should respect trim_output_left', async function () {
const engine = new Liquid({ trim_value_left: true }) const engine = new Liquid({ trim_output_left: true })
const html = await engine.parseAndRender(' \n \t{{name}} ', ctx) const html = await engine.parseAndRender(' \n \t{{name}} ', ctx)
return expect(html).to.equal('harttle ') return expect(html).to.equal('harttle ')
}) })
it('should respect trim_value_right', async function () { it('should respect trim_output_right', async function () {
const engine = new Liquid({ trim_value_right: true }) const engine = new Liquid({ trim_output_right: true })
const html = await engine.parseAndRender(' \n \t{{name}} ', ctx) const html = await engine.parseAndRender(' \n \t{{name}} ', ctx)
return expect(html).to.equal(' \n \tharttle') return expect(html).to.equal(' \n \tharttle')
}) })
it('should respect not trim tag', async function () { it('should respect not trim tag', async function () {
const engine = new Liquid({ trim_value_left: true, trim_value_right: true }) const engine = new Liquid({ trim_output_left: true, trim_output_right: true })
const html = await engine.parseAndRender('\t{% if true %} aha {%endif%}\t') const html = await engine.parseAndRender('\t{% if true %} aha {%endif%}\t')
return expect(html).to.equal('\t aha \t') return expect(html).to.equal('\t aha \t')
}) })
+1 -1
View File
@@ -173,7 +173,7 @@ describe('scope', function () {
beforeEach(function () { beforeEach(function () {
scope = new Scope(ctx, { scope = new Scope(ctx, {
strict_variables: true strict_variables: true
}) } as any)
}) })
it('should throw when variable not defined', function () { it('should throw when variable not defined', function () {
function fn () { function fn () {