fix: case should render multiple when statements

This commit is contained in:
Jun Yang
2022-12-03 00:14:47 +08:00
parent 46ffe036a8
commit d17813ef52
3 changed files with 45 additions and 14 deletions
+20 -14
View File
@@ -2,7 +2,7 @@ import { ValueToken, Liquid, Tokenizer, toValue, evalToken, Value, Emitter, TagT
export default class extends Tag { export default class extends Tag {
value: Value value: Value
branches: { value?: ValueToken, templates: Template[] }[] = [] branches: { values: ValueToken[], templates: Template[] }[] = []
elseTemplates: Template[] = [] elseTemplates: Template[] = []
constructor (tagToken: TagToken, remainTokens: TopLevelToken[], liquid: Liquid) { constructor (tagToken: TagToken, remainTokens: TopLevelToken[], liquid: Liquid) {
super(tagToken, remainTokens, liquid) super(tagToken, remainTokens, liquid)
@@ -15,15 +15,15 @@ export default class extends Tag {
p = [] p = []
const tokenizer = new Tokenizer(token.args, this.liquid.options.operators) const tokenizer = new Tokenizer(token.args, this.liquid.options.operators)
const values: ValueToken[] = []
while (!tokenizer.end()) { while (!tokenizer.end()) {
const value = tokenizer.readValue() values.push(tokenizer.readValueOrThrow())
this.branches.push({
value: value,
templates: p
})
tokenizer.readTo(',') tokenizer.readTo(',')
} }
this.branches.push({
values,
templates: p
})
}) })
.on('tag:else', () => (p = this.elseTemplates)) .on('tag:else', () => (p = this.elseTemplates))
.on('tag:endcase', () => stream.stop()) .on('tag:endcase', () => stream.stop())
@@ -35,16 +35,22 @@ export default class extends Tag {
stream.start() stream.start()
} }
* render (ctx: Context, emitter: Emitter): Generator<unknown, unknown, unknown> { * render (ctx: Context, emitter: Emitter): Generator<unknown, void, unknown> {
const r = this.liquid.renderer const r = this.liquid.renderer
const value = toValue(yield this.value.value(ctx, ctx.opts.lenientIf)) const target = toValue(yield this.value.value(ctx, ctx.opts.lenientIf))
let branchHit = false
for (const branch of this.branches) { for (const branch of this.branches) {
const target = yield evalToken(branch.value, ctx, ctx.opts.lenientIf) for (const valueToken of branch.values) {
if (target === value) { const value = yield evalToken(valueToken, ctx, ctx.opts.lenientIf)
yield r.renderTemplates(branch.templates, ctx, emitter) if (target === value) {
return yield r.renderTemplates(branch.templates, ctx, emitter)
branchHit = true
break
}
} }
} }
yield r.renderTemplates(this.elseTemplates, ctx, emitter) if (!branchHit) {
yield r.renderTemplates(this.elseTemplates, ctx, emitter)
}
} }
} }
+17
View File
@@ -329,4 +329,21 @@ describe('Issues', function () {
expect(await liquid.parseAndRender('{{i.i}}', context)).to.equal('1') expect(await liquid.parseAndRender('{{i.i}}', context)).to.equal('1')
expect(await liquid.parseAndRender('{{j.j}}', context)).to.equal('1') expect(await liquid.parseAndRender('{{j.j}}', context)).to.equal('1')
}) })
it('#559 Case/When should evaluate multiple When statements', async () => {
const liquid = new Liquid()
const tpl = `
{% assign tag = 'Love' %}
{% case tag %}
{% when 'Love' or 'Luck' %}
This is a love or luck potion.
{% when 'Strength','Health', 'Love' %}
This is a strength or health or love potion.
{% else %}
This is a potion.
{% endcase %}
`
const html = await liquid.parseAndRender(tpl)
expect(html).to.match(/^\s*This is a love or luck potion.\s+This is a strength or health or love potion.\s*$/)
})
}) })
+8
View File
@@ -71,4 +71,12 @@ describe('tags/case', function () {
const html = await liquid.parseAndRender(src) const html = await liquid.parseAndRender(src)
return expect(html).to.equal('foo') return expect(html).to.equal('foo')
}) })
it('should render multiple matching branches', async function () {
const src = '{% case "b" %}' +
'{% when "a", "b" %}first' +
'{% when "b" %}second' +
'{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('firstsecond')
})
}) })