harttle / liquidjs

A simple, expressive, safe and Shopify compatible template engine in pure JavaScript.
https://liquidjs.com
MIT License
1.5k stars 237 forks source link

Method to get an array of variable names used in a parsed template #706

Closed amit777 closed 2 months ago

amit777 commented 3 months ago

Hi, we need to do some validation in our code regarding the names of parameters within a liquid template. Ideally I would like to do something like

const { Liquid } = require('liquidjs');
async function main() {
    const engine = new Liquid();
    const template = `
        Hello, {{ name }}!  You like {{ pet }}
    `;

    const parsedTemplate = engine.parse(template);
    const variables = parsedTemplate.extractVariables(parsedTemplate);
// variables should be ['name', 'pet']
}

Is there an easy way to do this?

harttle commented 3 months ago

AFAIK, no. I assume you need top level names. But names can be nested in scopes and builtin drops like in for tag. And can be dynamic.

I would like to implement one if it can be clearly defined and still useful.

amit777 commented 3 months ago

yes, just top level static variable names would be sufficient for my use case. I see your point about dynamic variables though. I wrote this very hacky method:

const _extractTemplateVars = function (parsedTemplate) {
  const variables = new Set();

  function traverseTokens (tokens) {
      for (const token of tokens) {
            if (token.token.constructor.name === 'OutputToken') {
        for (let p of token.value?.initial?.postfix) {
          let prop = p.props[0];
          if (prop.constructor.name === 'IdentifierToken') {
            variables.add(prop.content);
          }
        }
      }
      else if (token.token.constructor.name === 'TagToken') {
        for (let branch of token.branches) {
          traverseTokens(branch.templates);
        }
      }
    }
  }

  traverseTokens(parsedTemplate);
  return variables ;
}