mikser-io-render-liquid 2.0.0 → 3.0.0
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/README.md +11 -6
- package/index.js +61 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -14,16 +14,21 @@ npm install mikser-io-render-liquid
|
|
|
14
14
|
|
|
15
15
|
```js
|
|
16
16
|
// mikser.config.js
|
|
17
|
+
import { layouts } from 'mikser-io'
|
|
18
|
+
import { renderLiquid } from 'mikser-io-render-liquid'
|
|
19
|
+
|
|
17
20
|
export default {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
plugins: [
|
|
22
|
+
layouts(),
|
|
23
|
+
renderLiquid({
|
|
24
|
+
jsTruthy: true,
|
|
25
|
+
strictFilters: false
|
|
26
|
+
}),
|
|
27
|
+
]
|
|
23
28
|
}
|
|
24
29
|
```
|
|
25
30
|
|
|
26
|
-
The
|
|
31
|
+
The options object is passed through to the `Liquid` constructor — see [LiquidJS options](https://liquidjs.com/api/interfaces/LiquidOptions.html). Defaults applied by the plugin:
|
|
27
32
|
|
|
28
33
|
- `root: options.layoutsFolder`
|
|
29
34
|
- `extname: '.liquid'`
|
package/index.js
CHANGED
|
@@ -1,37 +1,80 @@
|
|
|
1
1
|
import { Liquid } from 'liquidjs'
|
|
2
|
-
import
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
3
3
|
|
|
4
4
|
let engine
|
|
5
5
|
|
|
6
|
+
// Per-render context propagated through LiquidJS's async chain via
|
|
7
|
+
// Node's AsyncLocalStorage. The render() function below sets the
|
|
8
|
+
// context; the wrapped _parsePartialFile / _parseLayoutFile (called
|
|
9
|
+
// by IncludeTag.render, RenderTag.render, LayoutTag.render for each
|
|
10
|
+
// include/render/layout invocation) read it back to report partial
|
|
11
|
+
// usage to the engine.
|
|
12
|
+
const renderContext = new AsyncLocalStorage()
|
|
13
|
+
|
|
14
|
+
function trackPartial(name) {
|
|
15
|
+
const ctx = renderContext.getStore()
|
|
16
|
+
if (!ctx?.track || !ctx.layouts || !name) return
|
|
17
|
+
const layout = ctx.layouts[name]
|
|
18
|
+
if (layout?.id) ctx.track.partial(layout.id)
|
|
19
|
+
}
|
|
20
|
+
|
|
6
21
|
export function load({ runtime, options, config }) {
|
|
7
22
|
if (!engine) {
|
|
23
|
+
// `root` still points at the layouts folder so LiquidJS's own
|
|
24
|
+
// `{% include 'partial' %}` / `{% layout 'wrapper' %}`
|
|
25
|
+
// directives can resolve from disk. The top-level layout body
|
|
26
|
+
// is rendered from `entity.layout.content` (populated by the
|
|
27
|
+
// layouts plugin and stripped of YAML by front-matter) —
|
|
28
|
+
// single source of truth for layout bodies.
|
|
8
29
|
engine = new Liquid({
|
|
9
30
|
root: options.layoutsFolder,
|
|
10
31
|
extname: '.liquid',
|
|
11
32
|
cache: !options.watch,
|
|
12
33
|
...config,
|
|
13
34
|
})
|
|
35
|
+
|
|
36
|
+
// Wrap LiquidJS's per-invocation partial/layout loaders.
|
|
37
|
+
// IncludeTag.render and RenderTag.render call
|
|
38
|
+
// engine._parsePartialFile(filepath, …) for each `{% include %}` /
|
|
39
|
+
// `{% render %}`; LayoutTag.render calls
|
|
40
|
+
// engine._parseLayoutFile(filepath, …) for `{% layout %}`.
|
|
41
|
+
// These fire on every invocation — even when the partial's
|
|
42
|
+
// parse is cache-hit — so they're the right granularity for
|
|
43
|
+
// tracking per-render usage.
|
|
44
|
+
const _parsePartialFile = engine._parsePartialFile.bind(engine)
|
|
45
|
+
engine._parsePartialFile = function (file, sync, currentFile) {
|
|
46
|
+
trackPartial(file)
|
|
47
|
+
return _parsePartialFile(file, sync, currentFile)
|
|
48
|
+
}
|
|
49
|
+
const _parseLayoutFile = engine._parseLayoutFile.bind(engine)
|
|
50
|
+
engine._parseLayoutFile = function (file, sync, currentFile) {
|
|
51
|
+
trackPartial(file)
|
|
52
|
+
return _parseLayoutFile(file, sync, currentFile)
|
|
53
|
+
}
|
|
14
54
|
}
|
|
15
|
-
runtime.liquid = (
|
|
55
|
+
runtime.liquid = (source, data) => engine.parseAndRender(source, data)
|
|
16
56
|
}
|
|
17
57
|
|
|
18
|
-
export async function render({ entity,
|
|
19
|
-
// Expose every function on runtime as a Liquid filter,
|
|
20
|
-
//
|
|
58
|
+
export async function render({ entity, runtime, state, track }) {
|
|
59
|
+
// Expose every function on runtime as a Liquid filter, so render-
|
|
60
|
+
// helper plugins (markdown, href, ...) keep working without per-
|
|
61
|
+
// plugin glue.
|
|
21
62
|
for (let key in runtime) {
|
|
22
63
|
if (typeof runtime[key] === 'function') {
|
|
23
64
|
engine.registerFilter(key, (input, ...args) => runtime[key](input, ...args))
|
|
24
65
|
}
|
|
25
66
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// file-ish extension — and `path.extname('foo.html-pdf')` is
|
|
29
|
-
// `.html-pdf`, which Liquid treats as "extension already present".
|
|
30
|
-
// Stripping would make multi-segment layout names (e.g.
|
|
31
|
-
// `franchises.html-pdf.liquid`) fail with ENOENT.
|
|
32
|
-
const name = path.relative(options.layoutsFolder, entity.layout.uri)
|
|
67
|
+
const source = entity.layout.content ?? ''
|
|
68
|
+
const layouts = state?.layouts?.layouts ?? {}
|
|
33
69
|
try {
|
|
34
|
-
|
|
70
|
+
// Establish the render context BEFORE parsing/rendering. Any
|
|
71
|
+
// internal partial or layout resolution inherits it through
|
|
72
|
+
// the async chain and reports the resolved name to the
|
|
73
|
+
// engine's track via the wrapped methods above.
|
|
74
|
+
return await renderContext.run(
|
|
75
|
+
{ track, layouts },
|
|
76
|
+
() => runtime.liquid(source, runtime),
|
|
77
|
+
)
|
|
35
78
|
} catch (err) {
|
|
36
79
|
// LiquidJS RenderError/ParseError carry a `token` with file/line/col.
|
|
37
80
|
const token = err?.token
|
|
@@ -41,3 +84,8 @@ export async function render({ entity, options, runtime }) {
|
|
|
41
84
|
throw err
|
|
42
85
|
}
|
|
43
86
|
}
|
|
87
|
+
|
|
88
|
+
// v9 factory — ADR-0010.
|
|
89
|
+
export function renderLiquid(options = {}) {
|
|
90
|
+
return { name: options.name ?? 'liquid', options, load, render }
|
|
91
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikser-io-render-liquid",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
},
|
|
17
17
|
"homepage": "https://github.com/almero-digital-marketing/mikser-io-render-liquid#readme",
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"mikser-io": "^
|
|
19
|
+
"mikser-io": "^9.0.0"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"liquidjs": "^10.
|
|
22
|
+
"liquidjs": "^10.27.0"
|
|
23
23
|
}
|
|
24
24
|
}
|