feat: exported Drop interface for #107

Deprecate snake_cased options and APIs, sed #109
This commit is contained in:
harttle
2019-02-28 00:05:08 +08:00
parent b69c3a3203
commit 7bee9fc92d
26 changed files with 227 additions and 179 deletions
+8 -3
View File
@@ -1,6 +1,11 @@
export abstract class Drop {
abstract valueOf(): any;
import { deprecate } from '../util/deprecate'
liquid_method_missing (name: string) { // eslint-disable-line
export abstract class Drop {
valueOf(): any {
return undefined
}
liquidMethodMissing (key: string): string | undefined {
return undefined
}
}
+47 -41
View File
@@ -1,5 +1,4 @@
/* eslint-disable camelcase */
import { deprecate } from './util/deprecate'
import * as _ from './util/underscore'
export interface LiquidOptions {
@@ -11,25 +10,25 @@ export interface LiquidOptions {
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?: 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_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
/** `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_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_output_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?: boolean
/** `trim_output_left` is similar to `trim_output_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trim_output_left?: boolean
/** `tag_delimiter_left` and `tag_delimiter_right` are used to override the delimiter for liquid tags **/
tag_delimiter_left?: string,
tag_delimiter_right?: string,
/** `output_delimiter_left` and `output_delimiter_right` are used to override the delimiter for liquid outputs **/
output_delimiter_left?: string,
output_delimiter_right?: 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`. */
/** `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
/** `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
/** `trimTagRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`. */
trimTagRight?: boolean
/** `trimTagLeft` is similar to `trimTagRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
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?: boolean
/** `trimOutputLeft` is similar to `trimOutputRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trimOutputLeft?: boolean
/** `tagDelimiterLeft` and `tagDelimiterRight` are used to override the delimiter for liquid tags **/
tagDelimiterLeft?: string,
tagDelimiterRight?: string,
/** `outputDelimiterLeft` and `outputDelimiterRight` are used to override the delimiter for liquid outputs **/
outputDelimiterLeft?: 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?: boolean
}
@@ -42,16 +41,16 @@ export interface NormalizedFullOptions extends NormalizedOptions {
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
tag_delimiter_left: string,
tag_delimiter_right: string,
output_delimiter_left: string,
output_delimiter_right: string,
strictFilters: boolean
strictVariables: boolean
trimTagRight: boolean
trimTagLeft: boolean
trimOutputRight: boolean
trimOutputLeft: boolean
tagDelimiterLeft: string,
tagDelimiterRight: string,
outputDelimiterLeft: string,
outputDelimiterRight: string,
greedy: boolean
}
@@ -60,17 +59,17 @@ const defaultOptions: NormalizedFullOptions = {
cache: false,
extname: '',
dynamicPartials: true,
trim_tag_right: false,
trim_tag_left: false,
trim_output_right: false,
trim_output_left: false,
trimTagRight: false,
trimTagLeft: false,
trimOutputRight: false,
trimOutputLeft: false,
greedy: true,
tag_delimiter_left: '{%',
tag_delimiter_right: '%}',
output_delimiter_left: '{{',
output_delimiter_right: '}}',
strict_filters: false,
strict_variables: false
tagDelimiterLeft: '{%',
tagDelimiterRight: '%}',
outputDelimiterLeft: '{{',
outputDelimiterRight: '}}',
strictFilters: false,
strictVariables: false
}
export function normalize (options?: LiquidOptions): NormalizedOptions {
@@ -78,6 +77,13 @@ export function normalize (options?: LiquidOptions): NormalizedOptions {
if (options.hasOwnProperty('root')) {
options.root = normalizeStringArray(options.root)
}
for (const key of Object.keys(options)) {
if (key.indexOf('_') > -1) {
const newKey = key.replace(/_([a-z])/g, (_, ch) => ch.toUpperCase())
deprecate(`${key} is deprecated, use ${newKey} instead.`, 109)
options[newKey] = options[key]
}
}
return options as NormalizedOptions
}
+1 -1
View File
@@ -70,7 +70,7 @@ export default class Liquid {
return this.render(templates, ctx, opts)
}
evalValue (str: string, scope: Scope) {
return new Value(str, this.options.strict_filters).value(scope)
return new Value(str, this.options.strictFilters).value(scope)
}
registerFilter (name: string, filter: FilterImpl) {
return Filter.register(name, filter)
+1 -1
View File
@@ -29,7 +29,7 @@ export default class Parser {
return new Tag(token as TagToken, remainTokens, this.liquid)
}
if (token.type === 'output') {
return new Output(token as OutputToken, this.liquid.options.strict_filters)
return new Output(token as OutputToken, this.liquid.options.strictFilters)
}
return new HTML(token)
} catch (e) {
+4 -4
View File
@@ -15,10 +15,10 @@ export default class Tokenizer {
}
tokenize (input: string, file?: string) {
const tokens: Token[] = []
const tagL = this.options.tag_delimiter_left
const tagR = this.options.tag_delimiter_right
const outputL = this.options.output_delimiter_left
const outputR = this.options.output_delimiter_right
const tagL = this.options.tagDelimiterLeft
const tagR = this.options.tagDelimiterRight
const outputL = this.options.outputDelimiterLeft
const outputR = this.options.outputDelimiterRight
let p = 0
let curLine = 1
let state = ParseState.HTML
+4 -4
View File
@@ -23,14 +23,14 @@ export default function whiteSpaceCtrl (tokens: Token[], options: NormalizedFull
function shouldTrimLeft (token: DelimitedToken, inRaw: boolean, options: NormalizedFullOptions) {
if (inRaw) return false
if (token.type === 'tag') return token.trimLeft || options.trim_tag_left
if (token.type === 'output') return token.trimLeft || options.trim_output_left
if (token.type === 'tag') return token.trimLeft || options.trimTagLeft
if (token.type === 'output') return token.trimLeft || options.trimOutputLeft
}
function shouldTrimRight (token: DelimitedToken, inRaw: boolean, options: NormalizedFullOptions) {
if (inRaw) return false
if (token.type === 'tag') return token.trimRight || options.trim_tag_right
if (token.type === 'output') return token.trimRight || options.trim_output_right
if (token.type === 'tag') return token.trimRight || options.trimTagRight
if (token.type === 'output') return token.trimRight || options.trimOutputRight
}
function trimLeft (token: Token, greedy: boolean) {
+16 -25
View File
@@ -1,4 +1,5 @@
import * as _ from '../util/underscore'
import { Drop } from '../drop/drop'
import { __assign } from 'tslib'
import assert from '../util/assert'
import { NormalizedFullOptions, applyDefault } from '../liquid-options'
@@ -27,7 +28,13 @@ export default class Scope {
get (path: string): any {
const paths = this.propertyAccessSeq(path)
const scope = this.findContextFor(paths[0]) || _.last(this.contexts)
return paths.reduce((value, key) => this.readProperty(value, key), scope)
return paths.reduce((value, key) => {
const val = this.readProperty(value, key)
if (_.isNil(val) && this.opts.strictVariables) {
throw new TypeError(`undefined variable: ${key}`)
}
return val
}, scope)
}
set (path: string, v: any): void {
const paths = this.propertyAccessSeq(path)
@@ -74,26 +81,20 @@ export default class Scope {
return null
}
private readProperty (obj: Context, key: string) {
let val
if (_.isNil(obj)) {
val = obj
} else {
obj = toLiquid(obj)
val = key === 'size' ? readSize(obj) : obj[key]
if (_.isFunction(obj.liquid_method_missing)) {
val = obj.liquid_method_missing!(key)
}
if (_.isNil(obj)) return obj
obj = _.toLiquid(obj)
if (obj instanceof Drop) {
if (_.isFunction(obj[key])) return obj[key]()
if (obj.hasOwnProperty(key)) return obj[key]
return obj.liquidMethodMissing(key)
}
if (_.isNil(val) && this.opts.strict_variables) {
throw new TypeError(`undefined variable: ${key}`)
}
return val
return key === 'size' ? readSize(obj) : obj[key]
}
/*
* Parse property access sequence from access string
* @example
* accessSeq("foo.bar") // ['foo', 'bar']
* accessSeq("foo.bar") // ['foo', 'bar']
* accessSeq("foo['bar']") // ['foo', 'bar']
* accessSeq("foo['b]r']") // ['foo', 'b]r']
* accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar'
@@ -150,16 +151,6 @@ export default class Scope {
}
}
function toLiquid (obj: Context) {
if (_.isFunction(obj.to_liquid)) {
return obj.to_liquid()
}
if (_.isFunction(obj.toLiquid)) {
return obj.toLiquid()
}
return obj
}
function readSize (obj: Context) {
if (!_.isNil(obj.size)) return obj.size
if (_.isArray(obj) || _.isString(obj)) return obj.length
+1
View File
@@ -1,2 +1,3 @@
export { AssignScope, CaptureScope, IncrementScope, DecrementScope } from './scope/scopes'
export { ParseError, TokenizationError, RenderBreakError, AssertionError } from './util/error'
export { Drop } from './drop/drop'
+7
View File
@@ -0,0 +1,7 @@
const reported:{[key: string]: boolean} = {}
export function deprecate(msg: string, issue: number) {
if (reported[msg]) return
console.warn(msg + ` See: https://github.com/harttle/liquidjs/issues/${issue}`)
reported[msg] = true
}
+14 -18
View File
@@ -1,5 +1,5 @@
import { deprecate } from './deprecate'
const toStr = Object.prototype.toString
const arrToStr = Array.prototype.toString
/*
* Checks if value is classified as a String primitive or object.
@@ -28,25 +28,21 @@ export function promisify (fn: any) {
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())
if (isFunction(value.to_s)) return value.to_s()
if ([toStr, arrToStr].indexOf(value.toString) > -1) return defaultToString(value)
if (isFunction(value.toString)) return value.toString()
return toStr.call(value)
value = toLiquid(value)
if (isFunction(value.to_s)) {
deprecate('to_s is deprecated, use toString instead.', 109)
return value.to_s()
}
return String(value)
}
function defaultToString (value: any): string {
const cache: any[] = []
return JSON.stringify(value, (key, value) => {
if (isObject(value)) {
if (cache.indexOf(value) !== -1) {
return
}
cache.push(value)
}
return value
})
export function toLiquid (value: any): any {
if (isFunction(value.to_liquid)) {
deprecate('to_liquid is deprecated, use toLiquid instead.', 109)
return toLiquid(value.to_liquid())
}
if (isFunction(value.toLiquid)) return toLiquid(value.toLiquid())
return value
}
export function create<T1 extends object, T2 extends T1 = T1> (proto: T1): T2 {