Skip to main content

Static template analysis

Instances of Template - as returned by Environment.getTemplate(), Environment.getTemplateSync(), Environment.parse() and parse() - include methods for inspecting a template's variable, tag a filter usage, without rendering the template.

By default, all of the following methods will try to load and analyze partial templates via {% include %}, {% render %} or {% extends %}. Set the includePartials option to false when calling these methods to ignore partial templates.

All variables

Template.variables() and Template.variablesSync() return an array of distinct, top-level variable names, without path segments. The resulting array will include variables that are local to the template, like those created with {% assign %}, or are in scope from {% for %} tags.

import { parse } from "liquidscript";

const template = parse(`\
Hello, {{ you }}!
{% assign x = 'foo' | upcase %}

{% for ch in x %}
- {{ ch }}
{% endfor %}

Goodbye, {{ you.first_name | capitalize }} {{ you.last_name }}
Goodbye, {{ you.first_name }} {{ you.last_name }}`);

console.log(template.variablesSync());
output
["you", "x", "ch"]

Paths

Template.variablePaths() and Template.variablePathsSync() return an array of variables, including all path segments. The resulting array will include variables that are local to the template, like those created with {% assign %}, or are in scope from {% for %} tags.

// ... continued from above
console.log(template.variablePathsSync());
output
["you", "you.first_name", "you.last_name", "x", "ch"]

Segments

Template.variableSegments() and Template.variableSegmentsSync() return an array of variables as a nested array of segments. The resulting array will include variables that are local to the template, like those created with {% assign %}, or are in scope from {% for %} tags.

// ... continued from above
console.log(template.variableSegmentsSync());
output
[["you"], ["you", "first_name"], ["you", "last_name"], ["x"], ["ch"]]

Global variables

Template.globalVariables() and Template.globalVariablesSync() return an array of top-level variable names excluding local and block scoped names.

Notice that x and ch are excluded from this result compared to variablesSync() above.

// ... continued from above
console.log(template.globalVariablesSync());
output
["you"]

Paths

Template.globalVariablePaths() and Template.globalVariablePathsSync() return an array global variables including path segments.

// ... continued from above
console.log(template.globalVariablePathsSync());
output
["you", "you.first_name", "you.last_name"]

Segments

Template.globalVariableSegments() and Template.globalVariableSegmentsSync() return an array global variables as nested arrays of segments.

// ... continued from above
console.log(template.globalVariableSegmentsSync());
output
[["you"], ["you", "first_name"], ["you", "last_name"]]

Filter names

Template.filterNames() and Template.filterNamesSync() return an array of filter names that appear in the template.

// ... continued from above
console.log(template.filterNamesSync());
output
["upcase", "capitalize"]

Tag names

Template.tagNames() and Template.tagNamesSync() return an array of tag names that appear in the template.

// ... continued from above
console.log(template.tagNamesSync());
output
james@Jamess-Mac-mini liquidscript % bun run dev.ts
[ "assign", "for" ]

Variable, tag and filter locations

Template.analyze() and Template.analyzeSync() return an instance of TemplateAnalysis containing all of the information provided by the other methods described on this page, plus the location (template name, span, line and column numbers) of every variable, tag and filter, each of which can appear many times across many templates.

Comment and doc nodes

Template.comments() and Template.docs() return an array of CommentTag | InlineCommentTag and DocTag, respectively. All of which have token and text properties.

import { parse } from "liquidscript";

const template = parse(`\
{% doc %}
some doc comment
{% enddoc %}

Hello!

{% comment %}
some comment
{% endcomment %}

{% if false %}
{% # an inline comment %}
{% endif %}`);

console.log(template.comments().map((node) => node.text));
console.log(template.docs().map((node) => node.text));
output
[ "\n some comment\n", " an inline comment " ]
[ "\n some doc comment\n" ]