@adobe/htlengine
Version:
Javascript Based HTL (Sightly) parser
200 lines (173 loc) • 5.77 kB
JavaScript
/*
* Copyright 2019 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
const OutputVariable = require('../parser/commands/OutputVariable');
const ExpressionFormatter = require('./ExpressionFormatter');
module.exports = class DomHandler {
constructor(generator) {
this._gen = generator;
this._out = generator.out.bind(generator);
this._globalTemplates = {};
this._currentTemplate = {
id: 'global',
name: 'global',
stack: [new Set()],
};
}
beginDocument() {
this._out('let $t, $n = $.dom.start();');
}
endDocument() {
this._out('return $.dom.end();');
}
outText(cmd) {
this._out(`$.dom.text($n,${JSON.stringify(cmd.text)});`);
}
doctype(cmd) {
this._out(`$n = $.dom.doctype($n,'${cmd.name}');`);
}
comment(cmd) {
if (cmd.text instanceof OutputVariable) {
this._out(`$.dom.rem($n,${cmd.text.variableName});`);
} else {
this._out(`$.dom.rem($n,${JSON.stringify(cmd.text)});`);
}
}
outVariable(variableName) {
this._out(`$.dom.append($n, ${variableName});`);
}
createElement(cmd) {
const name = cmd.name instanceof OutputVariable
? cmd.name.variableName
: JSON.stringify(cmd.name);
this._out(`$t = $.dom.create(${name},${cmd.isEmpty},${cmd.isVoid});`);
}
pushElement() {
this._out('$n = $.dom.push($n,$t);');
}
popElement() {
this._out('$n = $.dom.pop($n);');
}
addAttribute(cmd) {
const { value } = cmd;
const name = cmd.name instanceof OutputVariable ? cmd.name.variableName : `'${cmd.name}'`;
if (value instanceof OutputVariable) {
this._out(`$.dom.attr($t, ${name}, ${value.variableName}, '${cmd.context}');`);
} else {
this._out(`$.dom.attr($t, ${name}, ${value === null ? 'null' : JSON.stringify(value)}, '${cmd.context}');`);
}
}
setVariable(cmd) {
const exp = ExpressionFormatter.format(cmd.expression);
const name = ExpressionFormatter.escapeVariable(cmd.variableName);
if (this._isVarDefined(name)) {
this._out(`${name} = ${exp};`);
} else {
this._defineVar(name);
this._out(`const ${name} = ${exp};`);
}
}
conditionStart(cmd) {
const exp = ExpressionFormatter.format(cmd.expression);
const neg = cmd.negate ? '!' : '';
this._out(`if (${neg}${exp}) {`);
this._pushBlock();
}
conditionEnd() {
this._popBlock();
this._out('}');
}
loopInit(cmd) {
const exp = ExpressionFormatter.format(cmd.expression);
if (cmd.options && Object.keys(cmd.options).length) {
const opts = {};
Object.entries(cmd.options).forEach(([key, value]) => {
opts[key] = ExpressionFormatter.format(value);
});
this._out(`const ${cmd.variableName} = $.col.init(${exp},${JSON.stringify(opts)});`);
} else {
this._out(`const ${cmd.variableName} = $.col.init(${exp});`);
}
}
loopStart(cmd) {
this._out(`for (const ${cmd.indexVariable} of $.col.keys(${cmd.listVariable})) {`);
this._out(` const ${cmd.itemVariable} = $.col.get(${cmd.listVariable}, ${cmd.indexVariable});`);
this._pushBlock();
}
loopEnd() {
this._popBlock();
this._out('}');
}
bindFunction(cmd) {
if (this._isVarDefined(cmd.name)) {
this._out(`${cmd.name} = $.template('${cmd.id}');`);
} else {
this._defineVar(cmd.name);
this._out(`let ${cmd.name} = $.template('${cmd.id}');`);
}
}
functionStart(cmd) {
const name = ExpressionFormatter.escapeVariable(ExpressionFormatter.format(cmd.expression));
const varName = name.toLowerCase();
const id = cmd.id || this._gen.scriptId;
const functionName = `_template_${id.replace(/[^\w]/g, '_')}_${name.replace(/\./g, '_')}`;
// this._out(`${exp} = $.template('${id}', '${exp}', function* ${functionName}(args) { `);
this._out(`${varName} = function* ${functionName}(args) { `);
this._gen.indent();
const vars = new Set();
cmd.args.forEach((arg) => {
const argName = ExpressionFormatter.escapeVariable(arg).toLowerCase();
vars.add(argName);
this._out(`let ${argName} = args[1]['${arg}'] || '';`);
});
this._out('let $t, $n = args[0];');
this._globalTemplates[name] = id;
this._currentTemplate = {
id,
name,
varName,
functionName,
stack: [vars],
};
}
functionEnd() {
this._gen.outdent();
this._out('};');
const { id, name, varName } = this._currentTemplate;
this._out(`$.template('${id}', '${name}', ${varName});`);
}
functionCall(cmd) {
const funcName = ExpressionFormatter.format(cmd.functionName);
const args = ExpressionFormatter.format(cmd.args);
this._out(`yield $.call(${funcName}, [$n, ${args}]);`);
}
_isVarDefined(name) {
if (!this._currentTemplate) {
return false;
}
return !!this._currentTemplate.stack.find((s) => s.has(name));
}
_defineVar(name) {
if (this._currentTemplate) {
this._currentTemplate.stack[0].add(name);
}
}
_pushBlock() {
if (this._currentTemplate) {
this._currentTemplate.stack.unshift(new Set());
}
}
_popBlock() {
if (this._currentTemplate) {
this._currentTemplate.stack.shift();
}
}
};