mikser-io-render-liquid 4.2.2 → 4.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +15 -2
- package/package.json +1 -1
- package/test/references.test.js +44 -0
package/index.js
CHANGED
|
@@ -319,10 +319,23 @@ export function parseReferences(source) {
|
|
|
319
319
|
const raw = [...found][0] ?? null
|
|
320
320
|
const from = raw ? record(raw, scope, guarded) : null
|
|
321
321
|
if (node.key) {
|
|
322
|
-
|
|
322
|
+
// `derived` travels with it: the closure walker applies
|
|
323
|
+
// these assigns as bindings too, and it has no other way
|
|
324
|
+
// to know the value went through a filter.
|
|
325
|
+
const derived = !!(node.value?.filters ?? []).length
|
|
326
|
+
assigns.push({ key: node.key, from, ...(derived ? { derived } : {}) })
|
|
323
327
|
// Bound for the REST of this template, which is what
|
|
324
328
|
// `assign` means — everything after it sees the alias.
|
|
325
|
-
|
|
329
|
+
//
|
|
330
|
+
// NOT bound when the value passed through a filter: the
|
|
331
|
+
// result is DERIVED, so a read on it says nothing about
|
|
332
|
+
// the source. `{% assign rows = c.specs | split: '|' %}`
|
|
333
|
+
// turns a string into a list, and binding it would let a
|
|
334
|
+
// loop over `rows` report `specs[]` — a key the document
|
|
335
|
+
// does not have and cannot be given, since specs is the
|
|
336
|
+
// string being split. The source itself is still
|
|
337
|
+
// recorded above, which is the true dependency.
|
|
338
|
+
if (from && !derived) scope[node.key] = from
|
|
326
339
|
}
|
|
327
340
|
break
|
|
328
341
|
}
|
package/package.json
CHANGED
package/test/references.test.js
CHANGED
|
@@ -213,3 +213,47 @@ describe('liquid parseReferences: default: as a guard', () => {
|
|
|
213
213
|
`optional: ${r.optional.join(', ')}`)
|
|
214
214
|
})
|
|
215
215
|
})
|
|
216
|
+
|
|
217
|
+
// A filtered value is DERIVED, not an alias.
|
|
218
|
+
//
|
|
219
|
+
// `{% assign rows = c.specs | split: '|' %}` turns a string into a list, so a
|
|
220
|
+
// read of `rows[0]` says nothing about `specs` having members. Treating it as an
|
|
221
|
+
// alias reports `specs[]` as a required key of a document whose `specs` IS the
|
|
222
|
+
// string being split — a key no document can ever satisfy, on a page that
|
|
223
|
+
// renders correctly.
|
|
224
|
+
describe('liquid parseReferences: derived values are not aliases', () => {
|
|
225
|
+
it('records the source but does not extend paths under it', () => {
|
|
226
|
+
const r = parseReferences(
|
|
227
|
+
"{% assign rows = data.meta.specs | split: '|' %}"
|
|
228
|
+
+ '{% for row in rows %}{{ row.name }}{% endfor %}')
|
|
229
|
+
assert.ok(r.variables.includes('data.meta.specs'), 'the real dependency is still recorded')
|
|
230
|
+
assert.ok(!r.variables.some(v => v.startsWith('data.meta.specs[')),
|
|
231
|
+
`fabricated a member of a string: ${r.variables.join(', ')}`)
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('marks the assign derived so a closure walker knows too', () => {
|
|
235
|
+
// The walker applies these as bindings as well, and has no other way to
|
|
236
|
+
// know the value went through a filter.
|
|
237
|
+
const r = parseReferences("{% assign rows = data.meta.specs | split: '|' %}")
|
|
238
|
+
assert.equal(r.assigns.find(a => a.key === 'rows')?.derived, true)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('leaves an UNFILTERED alias working', () => {
|
|
242
|
+
const r = parseReferences('{% assign hero = data.meta.hero %}{{ hero.title }}')
|
|
243
|
+
assert.ok(r.variables.includes('data.meta.hero.title'))
|
|
244
|
+
assert.ok(!r.assigns.find(a => a.key === 'hero')?.derived)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('handles the real shape: split, loop, split again', () => {
|
|
248
|
+
// Verbatim from the project that surfaced this.
|
|
249
|
+
const r = parseReferences(
|
|
250
|
+
"{% assign rows = data.meta.results.cases | split: '|' %}"
|
|
251
|
+
+ '{% for row in rows %}'
|
|
252
|
+
+ "{% assign kv = row | split: ':' %}"
|
|
253
|
+
+ '<dt>{{ kv[0] }}</dt>'
|
|
254
|
+
+ '{% endfor %}')
|
|
255
|
+
assert.ok(r.variables.includes('data.meta.results.cases'))
|
|
256
|
+
assert.ok(!r.variables.some(v => /results\.cases\[/.test(v)),
|
|
257
|
+
`fabricated: ${r.variables.filter(v => v.includes('cases')).join(', ')}`)
|
|
258
|
+
})
|
|
259
|
+
})
|