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({