mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-16 21:00:40 -07:00
feat: exported Drop interface for #107
Deprecate snake_cased options and APIs, sed #109
This commit is contained in:
+8
-3
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,2 +1,3 @@
|
||||
export { AssignScope, CaptureScope, IncrementScope, DecrementScope } from './scope/scopes'
|
||||
export { ParseError, TokenizationError, RenderBreakError, AssertionError } from './util/error'
|
||||
export { Drop } from './drop/drop'
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user