我正在使用 Handlebars 库并开发一个函数来检索所有嵌入的变量。该功能适用于简单的非逻辑文本。但是,当有 if 语句时,函数只返回变量的一个子集。
import Handlebars from "handlebars";
function getHandlebarsVariables(input){
const ast = Handlebars.parseWithoutProcessing(input);
return ast.body
.filter(({ type }) => type === 'MustacheStatement')
.map((statement) => statement.params[0]?.original || statement.path?.original);
};
const text1 = '{{name}} {{age}} {{#if isAdult}} {{ Adult }} {{/if}}';
const variables = getHandlebarsVariables(text1);
console.log(variables); // currently returns ['name', 'age'], I want to return ['name', 'age', 'Adult']
我期望函数返回的内容:['name', 'age', 'Adult'] 目前我得到:['name', 'age']
我认为编译器的功能比您认为的要多。如果解析的 Handlebars 模板是一个简单的平面数组,您的过滤器和映射逻辑就足够了;但是这样的语法树不是那样的——它有很多层次,必须使用递归来解析。
我提供下面的代码,不是作为一个功能齐全的可交付程序,而是作为一个如何递归遍历语法树的示例。此示例适用于您帖子中的
text1
输入,但我 不会 指望它适用于所有 Handlebars 模板。
import Handlebars from "handlebars";
function getVariablesFromStatementsRecursive(statements) {
return statements.reduce((acc, statement) => {
const { type } = statement;
if ("BlockStatement" === type) {
const { inverse, program } = statement;
if (program?.body) {
acc = acc.concat(getVariablesFromStatementsRecursive(program.body));
}
if (inverse?.body) {
acc = acc.concat(getVariablesFromStatementsRecursive(inverse.body));
}
} else if ("MustacheStatement" === type) {
const { path } = statement;
if (path?.original) {
acc.push(path.original);
}
}
return acc;
}, []);
}
function getHandlebarsVariables(input) {
const ast = Handlebars.parseWithoutProcessing(input);
return getVariablesFromStatementsRecursive(ast.body);
}
const text1 = "{{name}} {{age}} {{#if isAdult}} {{ Adult }} {{/if}}";
const variables = getHandlebarsVariables(text1);
console.log(variables); // [ 'name', 'age', 'Adult' ]