UNPKG

muban-convert-hbs

Version:

Convert muban hbs templates to htl, django, twig and others.

319 lines (243 loc) 10.2 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.DjangoTranspiler = void 0; var _handlebars = _interopRequireDefault(require("handlebars")); var _Context = _interopRequireWildcard(require("./Context")); var DjangoTranspiler = /*#__PURE__*/ function () { function DjangoTranspiler(input, context, depth) { if (depth === void 0) { depth = 0; } Object.defineProperty(this, "buffer", { configurable: true, enumerable: true, writable: true, value: void 0 }); Object.defineProperty(this, "parsed", { configurable: true, enumerable: true, writable: true, value: void 0 }); Object.defineProperty(this, "context", { configurable: true, enumerable: true, writable: true, value: void 0 }); Object.defineProperty(this, "depth", { configurable: true, enumerable: true, writable: true, value: void 0 }); this.buffer = []; this.context = context || new _Context.default(); this.depth = depth; if (input) { this.parsed = _handlebars.default.parse(input); this.parseProgram(this.parsed); } } var _proto = DjangoTranspiler.prototype; _proto.parseProgram = function parseProgram(program, isConditionalInInverse) { var _this = this; if (isConditionalInInverse === void 0) { isConditionalInInverse = false; } // console.log('\n\n -- PROGRAM -- \n'); // console.log(program); program.body.forEach(function (statement) { switch (statement.type) { case 'ContentStatement': _this.buffer.push(statement.original); break; case 'MustacheStatement': // console.log('\n\nMustacheStatement\n'); // console.log(statement); var path = statement.path; var escaped = statement.escaped ? '' : '|safe'; var variable; if (path.original === '@index') { variable = 'forloop.counter0'; } else { variable = _this.context.getScopedVariable(path); } if (path.type === 'PathExpression') { _this.buffer.push("{{ " + variable + escaped + " }}"); } else if (path.type === 'Literal') { throw new Error('not implemented'); } break; case 'CommentStatement': _this.buffer.push("{#" + statement.value + "#}"); break; case 'BlockStatement': // console.log('\n\nBlockStatement\n'); // console.log(statement); var type = statement.path.original; switch (type) { case 'if': { var condition = statement.params[0]; var scopedCondition; if (condition.type === 'SubExpression') { if (condition.path.original === 'condition') { scopedCondition = condition.params.map(function (param) { if (param.type === 'PathExpression') { return _this.context.getScopedVariable(param); } return param.value; }).join(' '); } } else { scopedCondition = _this.context.getScopedVariable(condition); } // use `else if` instead of else when this is the only if statement in an else block _this.buffer.push("{% " + (isConditionalInInverse ? 'el' : '') + "if " + scopedCondition + " %}"); var t = new DjangoTranspiler(null, _this.context, _this.depth); _this.buffer.push(t.parseProgram(statement.program).toString()); if (statement.inverse) { // else section var isInverseOnlyConditional = DjangoTranspiler.isOnlyCondition(statement.inverse); var _t = new DjangoTranspiler(null, _this.context, _this.depth); _t.parseProgram(statement.inverse, isInverseOnlyConditional); // child will render a `else if` if (!isInverseOnlyConditional) { _this.buffer.push("{% else %}"); } _this.buffer.push(_t.toString()); } // parent will close this if (!isConditionalInInverse) { _this.buffer.push("{% endif %}"); } break; } case 'each': { var _condition = _this.context.getScopedVariable(statement.params[0]); var childContext; if (statement.program.blockParams) { // {{#each foo as |key, value|} var blockParams = statement.program.blockParams; childContext = _this.context.createChildContext(blockParams); // {{#each foo as |k, v|} => has 2 variable in the same context, k and v if (blockParams.length === 2) { childContext.getCurrentScope().iterateAsObject(); } } else { // {{#each foo}} childContext = _this.context.createChildContext([_condition.split('.').pop() + "_i"]); } var _t2 = new DjangoTranspiler(null, childContext, _this.depth + 1); _t2.parseProgram(statement.program); var childScope = childContext.getCurrentScope(); // Rules: // - default = array // - when using 2 block params = object // - when using @key = object if (childScope.iterationType === _Context.IterationType.ARRAY) { // Array iteration _this.buffer.push("{% for " + childScope.value + " in " + _condition + " %}"); } else { // Object iteration var key = 'key'; var value = 'value'; if (childScope.value) { value = childScope.value; key = childScope.key || 'key'; } _this.buffer.push("{% for " + key + ", " + value + " in " + _condition + ".items %}"); } _this.buffer.push(_t2.toString()); _this.buffer.push("{% endfor %}"); break; } default: { // tslint:disable-next-line:no-console console.log('Unsupported block ', type); _this.buffer.push("{{# " + type + " }}"); var _t3 = new DjangoTranspiler(null, _this.context, _this.depth); _t3.parseProgram(statement.program); _this.buffer.push(_t3.toString()); _this.buffer.push("{{/" + type + "}}"); } } break; case 'PartialStatement': { // console.log('\nPartialStatement\n'); var name; if (statement.name.type === 'StringLiteral') { var expression = statement.name; name = "\"" + expression.value.replace('.hbs', '.html') + "\""; } else if (statement.name.type === 'SubExpression') { var _expression = statement.name; // TODO: add generic helper support, which includes lookup if (_expression.path.original === 'lookup') { // TODO: add scope support, now always assumes '.' (current scope) name = _expression.params[1].value; } } else { name = statement.name.parts.filter(function (p) { return p !== 'hbs'; }).join('/'); name = "\"" + name + ".html\""; } var context = ''; if (statement.params.length) { // TODO: django doesn't support pushing/replacing the context, only adding/replacing additional variables context = " with " + _this.context.getScopedVariable(statement.params[0]) + "=\"does-not-work\""; } var params = ''; if (statement.hash) { params = ' with ' + statement.hash.pairs.map(function (pair) { var key = pair.key + "="; if (pair.value.type === 'PathExpression') { return "" + key + _this.context.getScopedVariable(pair.value); } if (pair.value.type === 'StringLiteral') { return key + "\"" + pair.value.value + "\""; } if (pair.value.type === 'NumberLiteral') { return "" + key + pair.value.value; } if (pair.value.type === 'BooleanLiteral') { return "" + key + pair.value.value; } return ''; }).filter(function (_) { return _; }).join(' '); } _this.buffer.push("{% include " + name + context + params + " %}"); break; } default: { // tslint:disable-next-line:no-console console.log('Unsupported statements ', statement.type); } } }); return this; }; /** * Checks if this sub-program has only a condition statement. * If that's the case, and used in a inverse (else) section, the parent should render `else if` * instead of an `if` nested in an `else`. * @param {hbs.AST.Program} program * @return {boolean} */ DjangoTranspiler.isOnlyCondition = function isOnlyCondition(program) { return program.body.length === 1 && program.body[0].type === 'BlockStatement' && program.body[0].path.original === 'if'; }; _proto.toString = function toString() { return this.buffer.reduce(function (str, op) { return str + op; }, ''); }; return DjangoTranspiler; }(); exports.DjangoTranspiler = DjangoTranspiler;