mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 04:10:40 -07:00
feat: allow drops in property access (#769)
This commit is contained in:
@@ -3,7 +3,7 @@ import { Drop } from '../drop/drop'
|
|||||||
import { __assign } from 'tslib'
|
import { __assign } from 'tslib'
|
||||||
import { NormalizedFullOptions, defaultOptions, RenderOptions } from '../liquid-options'
|
import { NormalizedFullOptions, defaultOptions, RenderOptions } from '../liquid-options'
|
||||||
import { Scope } from './scope'
|
import { Scope } from './scope'
|
||||||
import { hasOwnProperty, isArray, isNil, isUndefined, isString, isFunction, toLiquid, InternalUndefinedVariableError, toValueSync, isObject, Limiter } from '../util'
|
import { hasOwnProperty, isArray, isNil, isUndefined, isString, isFunction, toLiquid, InternalUndefinedVariableError, toValueSync, isObject, Limiter, toValue } from '../util'
|
||||||
|
|
||||||
type PropertyKey = string | number;
|
type PropertyKey = string | number;
|
||||||
|
|
||||||
@@ -71,8 +71,8 @@ export class Context {
|
|||||||
public getSync (paths: PropertyKey[]): unknown {
|
public getSync (paths: PropertyKey[]): unknown {
|
||||||
return toValueSync(this._get(paths))
|
return toValueSync(this._get(paths))
|
||||||
}
|
}
|
||||||
public * _get (paths: PropertyKey[]): IterableIterator<unknown> {
|
public * _get (paths: (PropertyKey | Drop)[]): IterableIterator<unknown> {
|
||||||
const scope = this.findScope(paths[0])
|
const scope = this.findScope(paths[0] as string) // first prop should always be a string
|
||||||
return yield this._getFromScope(scope, paths)
|
return yield this._getFromScope(scope, paths)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -81,7 +81,7 @@ export class Context {
|
|||||||
public getFromScope (scope: unknown, paths: PropertyKey[] | string): IterableIterator<unknown> {
|
public getFromScope (scope: unknown, paths: PropertyKey[] | string): IterableIterator<unknown> {
|
||||||
return toValueSync(this._getFromScope(scope, paths))
|
return toValueSync(this._getFromScope(scope, paths))
|
||||||
}
|
}
|
||||||
public * _getFromScope (scope: unknown, paths: PropertyKey[] | string, strictVariables = this.strictVariables): IterableIterator<unknown> {
|
public * _getFromScope (scope: unknown, paths: (PropertyKey | Drop)[] | string, strictVariables = this.strictVariables): IterableIterator<unknown> {
|
||||||
if (isString(paths)) paths = paths.split('.')
|
if (isString(paths)) paths = paths.split('.')
|
||||||
for (let i = 0; i < paths.length; i++) {
|
for (let i = 0; i < paths.length; i++) {
|
||||||
scope = yield readProperty(scope as object, paths[i], this.ownPropertyOnly)
|
scope = yield readProperty(scope as object, paths[i], this.ownPropertyOnly)
|
||||||
@@ -120,8 +120,9 @@ export class Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readProperty (obj: Scope, key: PropertyKey, ownPropertyOnly: boolean) {
|
export function readProperty (obj: Scope, key: (PropertyKey | Drop), ownPropertyOnly: boolean) {
|
||||||
obj = toLiquid(obj)
|
obj = toLiquid(obj)
|
||||||
|
key = toValue(key) as PropertyKey
|
||||||
if (isNil(obj)) return obj
|
if (isNil(obj)) return obj
|
||||||
if (isArray(obj) && (key as number) < 0) return obj[obj.length + +key]
|
if (isArray(obj) && (key as number) < 0) return obj[obj.length + +key]
|
||||||
const value = readJSProperty(obj, key, ownPropertyOnly)
|
const value = readJSProperty(obj, key, ownPropertyOnly)
|
||||||
|
|||||||
@@ -50,6 +50,16 @@ describe('Expression', function () {
|
|||||||
expect(await toPromise(create('foo[doo["foo"]]').evaluate(ctx, false))).toBe('BAR')
|
expect(await toPromise(create('foo[doo["foo"]]').evaluate(ctx, false))).toBe('BAR')
|
||||||
expect(await toPromise(create('doo[coo].foo').evaluate(ctx, false))).toBe('bar')
|
expect(await toPromise(create('doo[coo].foo').evaluate(ctx, false))).toBe('bar')
|
||||||
})
|
})
|
||||||
|
it('should support drops in property access', async function () {
|
||||||
|
class TemplateDrop extends Drop {
|
||||||
|
valueOf () { return 'bar' }
|
||||||
|
}
|
||||||
|
const ctx = new Context({
|
||||||
|
foo: { bar: 'BAR' },
|
||||||
|
coo: new TemplateDrop()
|
||||||
|
})
|
||||||
|
expect(await toPromise(create('foo[coo]').evaluate(ctx, false))).toBe('BAR')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('simple expression', function () {
|
describe('simple expression', function () {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { QuotedToken, RangeToken, OperatorToken, Token, PropertyAccessToken, Ope
|
|||||||
import { isRangeToken, isPropertyAccessToken, UndefinedVariableError, range, isOperatorToken, assert } from '../util'
|
import { isRangeToken, isPropertyAccessToken, UndefinedVariableError, range, isOperatorToken, assert } from '../util'
|
||||||
import type { Context } from '../context'
|
import type { Context } from '../context'
|
||||||
import type { UnaryOperatorHandler } from '../render'
|
import type { UnaryOperatorHandler } from '../render'
|
||||||
|
import { Drop } from '../drop'
|
||||||
|
|
||||||
export class Expression {
|
export class Expression {
|
||||||
private postfix: Token[]
|
private postfix: Token[]
|
||||||
@@ -42,9 +43,9 @@ export function * evalToken (token: Token | undefined, ctx: Context, lenient = f
|
|||||||
}
|
}
|
||||||
|
|
||||||
function * evalPropertyAccessToken (token: PropertyAccessToken, ctx: Context, lenient: boolean): IterableIterator<unknown> {
|
function * evalPropertyAccessToken (token: PropertyAccessToken, ctx: Context, lenient: boolean): IterableIterator<unknown> {
|
||||||
const props: string[] = []
|
const props: (string | number | Drop)[] = []
|
||||||
for (const prop of token.props) {
|
for (const prop of token.props) {
|
||||||
props.push((yield evalToken(prop, ctx, false)) as unknown as string)
|
props.push((yield evalToken(prop, ctx, false)) as unknown as string | number | Drop)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (token.variable) {
|
if (token.variable) {
|
||||||
|
|||||||
Reference in New Issue
Block a user