Skip to content

Commit cd0b1e4

Browse files
committed
feat: allow context access in liquidMethodMissing, #808
1 parent 31eb8ea commit cd0b1e4

3 files changed

Lines changed: 45 additions & 31 deletions

File tree

src/context/context.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class Context {
8686
public * _getFromScope (scope: unknown, paths: (PropertyKey | Drop)[] | string, strictVariables = this.strictVariables): IterableIterator<unknown> {
8787
if (isString(paths)) paths = paths.split('.')
8888
for (let i = 0; i < paths.length; i++) {
89-
scope = yield readProperty(scope as object, paths[i], this.ownPropertyOnly)
89+
scope = yield this.readProperty(scope as object, paths[i])
9090
if (strictVariables && isUndefined(scope)) {
9191
throw new InternalUndefinedVariableError((paths as string[]).slice(0, i + 1).join!('.'))
9292
}
@@ -120,21 +120,21 @@ export class Context {
120120
if (key in this.environments) return this.environments
121121
return this.globals
122122
}
123+
readProperty (obj: Scope, key: (PropertyKey | Drop)) {
124+
obj = toLiquid(obj)
125+
key = toValue(key) as PropertyKey
126+
if (isNil(obj)) return obj
127+
if (isArray(obj) && (key as number) < 0) return obj[obj.length + +key]
128+
const value = readJSProperty(obj, key, this.ownPropertyOnly)
129+
if (value === undefined && obj instanceof Drop) return obj.liquidMethodMissing(key, this)
130+
if (isFunction(value)) return value.call(obj)
131+
if (key === 'size') return readSize(obj)
132+
else if (key === 'first') return readFirst(obj)
133+
else if (key === 'last') return readLast(obj)
134+
return value
135+
}
123136
}
124137

125-
export function readProperty (obj: Scope, key: (PropertyKey | Drop), ownPropertyOnly: boolean) {
126-
obj = toLiquid(obj)
127-
key = toValue(key) as PropertyKey
128-
if (isNil(obj)) return obj
129-
if (isArray(obj) && (key as number) < 0) return obj[obj.length + +key]
130-
const value = readJSProperty(obj, key, ownPropertyOnly)
131-
if (value === undefined && obj instanceof Drop) return obj.liquidMethodMissing(key)
132-
if (isFunction(value)) return value.call(obj)
133-
if (key === 'size') return readSize(obj)
134-
else if (key === 'first') return readFirst(obj)
135-
else if (key === 'last') return readLast(obj)
136-
return value
137-
}
138138
export function readJSProperty (obj: Scope, key: PropertyKey, ownPropertyOnly: boolean) {
139139
if (ownPropertyOnly && !hasOwnProperty.call(obj, key) && !(obj instanceof Drop)) return undefined
140140
return obj[key]

src/drop/drop.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { Context } from '../context'
2+
13
export abstract class Drop {
2-
public liquidMethodMissing (key: string | number): Promise<any> | any {
4+
public liquidMethodMissing (key: string | number, context: Context): Promise<any> | any {
35
return undefined
46
}
57
}

test/e2e/drop.spec.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
1-
import { Drop, Liquid } from '../..'
2-
3-
class SettingsDrop extends Drop {
4-
public foo = 'FOO'
5-
public bar () {
6-
return 'BAR'
7-
}
8-
public liquidMethodMissing (key: string) {
9-
return key.toUpperCase()
10-
}
11-
}
1+
import { Context, Drop, Liquid } from '../..'
122

133
describe('drop', function () {
14-
const settings = new SettingsDrop()
154
let engine: Liquid
165
beforeEach(function () {
176
engine = new Liquid()
187
})
19-
it('should support liquidMethodMissing', async function () {
20-
const src = `{{settings.foo}},{{settings.bar}},{{settings.coo}}`
21-
const html = await engine.parseAndRender(src, { settings })
22-
return expect(html).toBe('FOO,BAR,COO')
8+
9+
describe('liquidMethodMissing', () => {
10+
it('should support liquidMethodMissing', async function () {
11+
class SettingsDrop extends Drop {
12+
public foo = 'FOO'
13+
public bar () {
14+
return 'BAR'
15+
}
16+
public liquidMethodMissing (key: string) {
17+
return key.toUpperCase()
18+
}
19+
}
20+
const src = `{{settings.foo}},{{settings.bar}},{{settings.coo}}`
21+
const html = await engine.parseAndRender(src, { settings: new SettingsDrop() })
22+
return expect(html).toBe('FOO,BAR,COO')
23+
})
24+
25+
it('should expose context', async function () {
26+
class SettingsDrop extends Drop {
27+
public liquidMethodMissing (key: string, context: Context) {
28+
return key + ':' + context.getSync([key])
29+
}
30+
}
31+
const src = `{{settings.foo}}`
32+
const html = await engine.parseAndRender(src, { settings: new SettingsDrop(), foo: 'FOO' })
33+
return expect(html).toBe('foo:FOO')
34+
})
2335
})
2436

2537
describe('BlandDrop', function () {

0 commit comments

Comments
 (0)