mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 04:10:40 -07:00
feat: ownPropertyOnly option to protect prototype, #454
This commit is contained in:
+11
-6
@@ -59,11 +59,11 @@ export class Context {
|
||||
return this.getFromScope(scope, paths)
|
||||
}
|
||||
public getFromScope (scope: object, paths: string[] | string) {
|
||||
if (typeof paths === 'string') paths = paths.split('.')
|
||||
return paths.reduce((scope, path) => {
|
||||
scope = readProperty(scope, path)
|
||||
if (isString(paths)) paths = paths.split('.')
|
||||
return paths.reduce((scope, path, i) => {
|
||||
scope = readProperty(scope, path, this.opts.ownPropertyOnly)
|
||||
if (isNil(scope) && this.strictVariables) {
|
||||
throw new InternalUndefinedVariableError(path)
|
||||
throw new InternalUndefinedVariableError((paths as string[]).slice(0, i + 1).join!('.'))
|
||||
}
|
||||
return scope
|
||||
}, scope)
|
||||
@@ -87,10 +87,11 @@ export class Context {
|
||||
}
|
||||
}
|
||||
|
||||
export function readProperty (obj: Scope, key: string) {
|
||||
export function readProperty (obj: Scope, key: string, ownPropertyOnly: boolean) {
|
||||
if (isNil(obj)) return obj
|
||||
obj = toLiquid(obj)
|
||||
if (isFunction(obj[key])) return obj[key]()
|
||||
const jsProperty = readJSProperty(obj, key, ownPropertyOnly)
|
||||
if (isFunction(jsProperty)) return jsProperty.call(obj)
|
||||
if (obj instanceof Drop) {
|
||||
if (obj.hasOwnProperty(key)) return obj[key]
|
||||
return obj.liquidMethodMissing(key)
|
||||
@@ -98,6 +99,10 @@ export function readProperty (obj: Scope, key: string) {
|
||||
if (key === 'size') return readSize(obj)
|
||||
if (key === 'first') return readFirst(obj)
|
||||
if (key === 'last') return readLast(obj)
|
||||
return jsProperty
|
||||
}
|
||||
export function readJSProperty (obj: Scope, key: string, ownPropertyOnly: boolean) {
|
||||
if (ownPropertyOnly && !Object.hasOwnProperty.call(obj, key)) return undefined
|
||||
return obj[key]
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ export interface LiquidOptions {
|
||||
strictFilters?: boolean;
|
||||
/** Whether or not to assert variable existence. If set to `false`, undefined variables will be rendered as empty string. Otherwise, undefined variables will cause an exception. Defaults to `false`. */
|
||||
strictVariables?: boolean;
|
||||
/** Hide scope variables from prototypes, useful when you're passing a not sanitized object into LiquidJS or need to hide prototypes from templates. */
|
||||
ownPropertyOnly?: boolean;
|
||||
/** Modifies the behavior of `strictVariables`. If set, a single undefined variable will *not* cause an exception in the context of the `if`/`elsif`/`unless` tag and the `default` filter. Instead, it will evaluate to `false` and `null`, respectively. Irrelevant if `strictVariables` is not set. Defaults to `false`. **/
|
||||
lenientIf?: boolean;
|
||||
/** JavaScript timezoneOffset for `date` filter, default to local time. That means if you're in Australia (UTC+10), it'll default to -600 */
|
||||
@@ -80,6 +82,10 @@ export interface RenderOptions {
|
||||
* Same as `strictVariables` on LiquidOptions, but only for current render() call
|
||||
*/
|
||||
strictVariables?: boolean;
|
||||
/**
|
||||
* Same as `ownPropertyOnly` on LiquidOptions, but only for current render() call
|
||||
*/
|
||||
ownPropertyOnly?: boolean;
|
||||
}
|
||||
|
||||
interface NormalizedOptions extends LiquidOptions {
|
||||
@@ -103,6 +109,7 @@ export interface NormalizedFullOptions extends NormalizedOptions {
|
||||
fs: FS;
|
||||
strictFilters: boolean;
|
||||
strictVariables: boolean;
|
||||
ownPropertyOnly: boolean;
|
||||
lenientIf: boolean;
|
||||
trimTagRight: boolean;
|
||||
trimTagLeft: boolean;
|
||||
@@ -143,6 +150,7 @@ export const defaultOptions: NormalizedFullOptions = {
|
||||
preserveTimezones: false,
|
||||
strictFilters: false,
|
||||
strictVariables: false,
|
||||
ownPropertyOnly: false,
|
||||
lenientIf: false,
|
||||
globals: {},
|
||||
keepOutputType: false,
|
||||
|
||||
Reference in New Issue
Block a user