From 124f4c4485270a5fdfca610808a56ecd98d98417 Mon Sep 17 00:00:00 2001 From: AleksandrHovhannisyan Date: Sun, 10 Oct 2021 10:27:12 -0400 Subject: [PATCH] fix: allow `{%render%}` to reassign argument, #404 --- .all-contributorsrc | 9 +++++++++ README.md | 1 + src/builtin/tags/render.ts | 7 ++++--- src/context/context.ts | 12 ++++++++++++ src/liquid-options.ts | 2 +- test/integration/builtin/tags/assign.ts | 5 +++++ test/integration/builtin/tags/capture.ts | 2 +- test/integration/builtin/tags/increment.ts | 2 +- test/integration/builtin/tags/render.ts | 10 ++++++++++ 9 files changed, 44 insertions(+), 6 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 018f96a678..8e03051d93 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -441,6 +441,15 @@ "contributions": [ "doc" ] + }, + { + "login": "AleksandrHovhannisyan", + "name": "Aleksandr Hovhannisyan", + "avatar_url": "https://avatars.githubusercontent.com/u/19352442?v=4", + "profile": "https://www.aleksandrhovhannisyan.com/", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index aaf89a5db2..d99d96d67b 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ Want to contribute? see [Contribution Guidelines][contribution]. Thanks goes to
Liam Bigelow

💻
Jason Kurian

📖
d pham (they/them)

📖 +
Aleksandr Hovhannisyan

💻 diff --git a/src/builtin/tags/render.ts b/src/builtin/tags/render.ts index 150e589cd5..06ab13df24 100644 --- a/src/builtin/tags/render.ts +++ b/src/builtin/tags/render.ts @@ -1,3 +1,4 @@ +import { __assign } from 'tslib' import { assert } from '../../util/assert' import { ForloopDrop } from '../../drop/forloop-drop' import { toEnumerable } from '../../util/collection' @@ -51,12 +52,12 @@ export default { assert(filepath, () => `illegal filename "${filepath}"`) const childCtx = new Context({}, ctx.opts, ctx.sync) - const scope = yield hash.render(ctx) + const scope = childCtx.bottom() + __assign(scope, yield hash.render(ctx)) if (this['with']) { const { value, alias } = this['with'] scope[alias || filepath] = evalToken(value, ctx) } - childCtx.push(scope) if (this['for']) { const { value, alias } = this['for'] @@ -67,7 +68,7 @@ export default { scope[alias] = item const templates = yield liquid._parsePartialFile(filepath, childCtx.sync, this['currentFile']) yield liquid.renderer.renderTemplates(templates, childCtx, emitter) - scope.forloop.next() + scope['forloop'].next() } } else { const templates = yield liquid._parsePartialFile(filepath, childCtx.sync, this['currentFile']) diff --git a/src/context/context.ts b/src/context/context.ts index 0443450114..379f75da0c 100644 --- a/src/context/context.ts +++ b/src/context/context.ts @@ -6,9 +6,21 @@ import { isArray, isNil, isString, isFunction, toLiquid } from '../util/undersco import { InternalUndefinedVariableError } from '../util/error' export class Context { + /** + * insert a Context-level empty scope, + * for tags like {% capture %} {% assign %} to operate + */ private scopes: Scope[] = [{}] private registers = {} + /** + * user passed in scope + * {% increment %}, {% decrement %} changes this scope, + * whereas {% capture %}, {% assign %} only hide this scope + */ public environments: Scope + /** + * global scope used as fallback for missing variables + */ public globals: Scope public sync: boolean public opts: NormalizedFullOptions diff --git a/src/liquid-options.ts b/src/liquid-options.ts index f87fd1c759..dd2cc377fe 100644 --- a/src/liquid-options.ts +++ b/src/liquid-options.ts @@ -55,7 +55,7 @@ export interface LiquidOptions { greedy?: boolean; /** `fs` is used to override the default file-system module with a custom implementation. */ fs?: FS; - /** the global environment passed down to all partial templates, i.e. templates included by `include`, `layout` and `render` tags. */ + /** the global scope passed down to all partial and layout templates, i.e. templates included by `include`, `layout` and `render` tags. */ globals?: object; /** Whether or not to keep value type when writing the Output, not working for streamed rendering. Defaults to `false`. */ keepOutputType?: boolean; diff --git a/test/integration/builtin/tags/assign.ts b/test/integration/builtin/tags/assign.ts index a102983eef..dcf34e9193 100644 --- a/test/integration/builtin/tags/assign.ts +++ b/test/integration/builtin/tags/assign.ts @@ -69,6 +69,11 @@ describe('tags/assign', function () { const html = await liquid.parseAndRender(src) return expect(html).to.equal('-6') }) + it('should allow reassignment', async function () { + const src = '{% assign var = 1 %}{% assign var = 2 %}{{ var }}' + const html = await liquid.parseAndRender(src) + return expect(html).to.equal('2') + }) describe('scope', function () { it('should read from parent scope', async function () { const src = '{%for a in (1..2)%}{{num}}{%endfor%}' diff --git a/test/integration/builtin/tags/capture.ts b/test/integration/builtin/tags/capture.ts index 921f9ec20b..16ae08082c 100644 --- a/test/integration/builtin/tags/capture.ts +++ b/test/integration/builtin/tags/capture.ts @@ -19,7 +19,7 @@ describe('tags/capture', function () { return expect(html).to.equal('A') }) - it('should shading rather than overwriting', async function () { + it('should not change root scope', async function () { const src = '{% capture var %}10{% endcapture %}{{var}}' const ctx = { 'var': 20 } const html = await liquid.parseAndRender(src, ctx) diff --git a/test/integration/builtin/tags/increment.ts b/test/integration/builtin/tags/increment.ts index 2aa6c0b4f9..f40ec0c525 100644 --- a/test/integration/builtin/tags/increment.ts +++ b/test/integration/builtin/tags/increment.ts @@ -39,7 +39,7 @@ describe('tags/increment', function () { return expect(html).to.equal('012 10') }) - it('should not shading capture', async function () { + it('should not hide capture', async function () { const src = '{% capture var %}10{% endcapture %}{% increment var %}{% increment var %}{% increment var %} {{var}}' const html = await liquid.parseAndRender(src) return expect(html).to.equal('012 10') diff --git a/test/integration/builtin/tags/render.ts b/test/integration/builtin/tags/render.ts index 203118509a..1bb6183ef7 100644 --- a/test/integration/builtin/tags/render.ts +++ b/test/integration/builtin/tags/render.ts @@ -86,6 +86,16 @@ describe('tags/render', function () { expect(html).to.equal('InParent: harttle InChild: ') }) + it('should allow argument reassignment', async function () { + mock({ + '/parent.html': '{% render child.html, color: "red" %}', + '/child.html': '{% assign color = "green" %}{{ color }}' + }) + const staticLiquid = new Liquid({ dynamicPartials: false, root: '/' }) + const html = await staticLiquid.renderFile('parent.html') + return expect(html).to.equal('green') + }) + it('should be able to access globals', async function () { liquid = new Liquid({ root: '/', extname: '.html', globals: { name: 'Harttle' } }) mock({