UNPKG

@glimmer/compiler

Version:
1,344 lines (1,098 loc) 350 kB
define('@glimmer/compiler', ['exports', '@glimmer/util', '@glimmer/wire-format', '@glimmer/syntax'], function (exports, util, wireFormat, syntax) { 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var SymbolTable = function () { function SymbolTable() { _classCallCheck(this, SymbolTable); } SymbolTable.top = function top() { return new ProgramSymbolTable(); }; SymbolTable.prototype.child = function child(locals) { var _this = this; var symbols = locals.map(function (name) { return _this.allocate(name); }); return new BlockSymbolTable(this, locals, symbols); }; return SymbolTable; }(); var ProgramSymbolTable = function (_SymbolTable) { _inherits(ProgramSymbolTable, _SymbolTable); function ProgramSymbolTable() { _classCallCheck(this, ProgramSymbolTable); var _this2 = _possibleConstructorReturn(this, _SymbolTable.apply(this, arguments)); _this2.symbols = []; _this2.freeVariables = []; _this2.size = 1; _this2.named = util.dict(); _this2.blocks = util.dict(); return _this2; } ProgramSymbolTable.prototype.has = function has(_name) { return false; }; ProgramSymbolTable.prototype.get = function get(_name) { throw util.unreachable(); }; ProgramSymbolTable.prototype.getLocalsMap = function getLocalsMap() { return {}; }; ProgramSymbolTable.prototype.getEvalInfo = function getEvalInfo() { return []; }; ProgramSymbolTable.prototype.allocateFree = function allocateFree(name) { var index = this.freeVariables.indexOf(name); if (index !== -1) { return index; } index = this.freeVariables.length; this.freeVariables.push(name); return index; }; ProgramSymbolTable.prototype.allocateNamed = function allocateNamed(name) { var named = this.named[name]; if (!named) { named = this.named[name] = this.allocate(name); } return named; }; ProgramSymbolTable.prototype.allocateBlock = function allocateBlock(name) { if (name === 'inverse') { name = 'else'; } var block = this.blocks[name]; if (!block) { block = this.blocks[name] = this.allocate('&' + name); } return block; }; ProgramSymbolTable.prototype.allocate = function allocate(identifier) { this.symbols.push(identifier); return this.size++; }; return ProgramSymbolTable; }(SymbolTable); var BlockSymbolTable = function (_SymbolTable2) { _inherits(BlockSymbolTable, _SymbolTable2); function BlockSymbolTable(parent, symbols, slots) { _classCallCheck(this, BlockSymbolTable); var _this3 = _possibleConstructorReturn(this, _SymbolTable2.call(this)); _this3.parent = parent; _this3.symbols = symbols; _this3.slots = slots; return _this3; } BlockSymbolTable.prototype.has = function has(name) { return this.symbols.indexOf(name) !== -1 || this.parent.has(name); }; BlockSymbolTable.prototype.get = function get(name) { var slot = this.symbols.indexOf(name); return slot === -1 ? this.parent.get(name) : this.slots[slot]; }; BlockSymbolTable.prototype.getLocalsMap = function getLocalsMap() { var _this4 = this; var dict = this.parent.getLocalsMap(); this.symbols.forEach(function (symbol) { return dict[symbol] = _this4.get(symbol); }); return dict; }; BlockSymbolTable.prototype.getEvalInfo = function getEvalInfo() { var locals = this.getLocalsMap(); return Object.keys(locals).map(function (symbol) { return locals[symbol]; }); }; BlockSymbolTable.prototype.allocateFree = function allocateFree(name) { return this.parent.allocateFree(name); }; BlockSymbolTable.prototype.allocateNamed = function allocateNamed(name) { return this.parent.allocateNamed(name); }; BlockSymbolTable.prototype.allocateBlock = function allocateBlock(name) { return this.parent.allocateBlock(name); }; BlockSymbolTable.prototype.allocate = function allocate(identifier) { return this.parent.allocate(identifier); }; return BlockSymbolTable; }(SymbolTable); /** * Takes in an AST and outputs a list of actions to be consumed * by a compiler. For example, the template * * foo{{bar}}<div>baz</div> * * produces the actions * * [['startProgram', [programNode, 0]], * ['text', [textNode, 0, 3]], * ['mustache', [mustacheNode, 1, 3]], * ['openElement', [elementNode, 2, 3, 0]], * ['text', [textNode, 0, 1]], * ['closeElement', [elementNode, 2, 3], * ['endProgram', [programNode]]] * * This visitor walks the AST depth first and backwards. As * a result the bottom-most child template will appear at the * top of the actions list whereas the root template will appear * at the bottom of the list. For example, * * <div>{{#if}}foo{{else}}bar<b></b>{{/if}}</div> * * produces the actions * * [['startProgram', [programNode, 0]], * ['text', [textNode, 0, 2, 0]], * ['openElement', [elementNode, 1, 2, 0]], * ['closeElement', [elementNode, 1, 2]], * ['endProgram', [programNode]], * ['startProgram', [programNode, 0]], * ['text', [textNode, 0, 1]], * ['endProgram', [programNode]], * ['startProgram', [programNode, 2]], * ['openElement', [elementNode, 0, 1, 1]], * ['block', [blockNode, 0, 1]], * ['closeElement', [elementNode, 0, 1]], * ['endProgram', [programNode]]] * * The state of the traversal is maintained by a stack of frames. * Whenever a node with children is entered (either a ProgramNode * or an ElementNode) a frame is pushed onto the stack. The frame * contains information about the state of the traversal of that * node. For example, * * - index of the current child node being visited * - the number of mustaches contained within its child nodes * - the list of actions generated by its child nodes */ var Frame = function Frame() { _classCallCheck(this, Frame); this.parentNode = null; this.children = null; this.childIndex = null; this.childCount = null; this.childTemplateCount = 0; this.mustacheCount = 0; this.actions = []; this.blankChildTextNodes = null; this.symbols = null; }; var TemplateVisitor = function () { function TemplateVisitor() { _classCallCheck(this, TemplateVisitor); this.frameStack = []; this.actions = []; this.programDepth = -1; } TemplateVisitor.prototype.visit = function visit(node) { this[node.type](node); }; // Traversal methods TemplateVisitor.prototype.Block = function Block(program) { return this.anyBlock(program); }; TemplateVisitor.prototype.Template = function Template(program) { return this.anyBlock(program); }; TemplateVisitor.prototype.anyBlock = function anyBlock(program) { var _actions; this.programDepth++; var parentFrame = this.getCurrentFrame(); var programFrame = this.pushFrame(); if (!parentFrame) { program.symbols = SymbolTable.top(); } else { program.symbols = parentFrame.symbols.child(program.blockParams); } var startType = void 0, endType = void 0; if (this.programDepth === 0) { startType = 'startProgram'; endType = 'endProgram'; } else { startType = 'startBlock'; endType = 'endBlock'; } programFrame.parentNode = program; programFrame.children = program.body; programFrame.childCount = program.body.length; programFrame.blankChildTextNodes = []; programFrame.actions.push([endType, [program, this.programDepth]]); programFrame.symbols = program['symbols']; for (var i = program.body.length - 1; i >= 0; i--) { programFrame.childIndex = i; this.visit(program.body[i]); } programFrame.actions.push([startType, [program, programFrame.childTemplateCount, programFrame.blankChildTextNodes.reverse()]]); this.popFrame(); this.programDepth--; // Push the completed template into the global actions list if (parentFrame) { parentFrame.childTemplateCount++; } (_actions = this.actions).push.apply(_actions, programFrame.actions.reverse()); }; TemplateVisitor.prototype.ElementNode = function ElementNode(element) { var _parentFrame$actions; var parentFrame = this.currentFrame; var elementFrame = this.pushFrame(); elementFrame.parentNode = element; elementFrame.children = element.children; elementFrame.childCount = element.children.length; elementFrame.mustacheCount += element.modifiers.length; elementFrame.blankChildTextNodes = []; elementFrame.symbols = element.symbols = parentFrame.symbols.child(element.blockParams); var actionArgs = [element, parentFrame.childIndex, parentFrame.childCount]; elementFrame.actions.push(['closeElement', actionArgs]); for (var i = element.attributes.length - 1; i >= 0; i--) { this.visit(element.attributes[i]); } for (var _i = element.children.length - 1; _i >= 0; _i--) { elementFrame.childIndex = _i; this.visit(element.children[_i]); } var open = ['openElement', [].concat(actionArgs, [elementFrame.mustacheCount, elementFrame.blankChildTextNodes.reverse()])]; elementFrame.actions.push(open); this.popFrame(); // Propagate the element's frame state to the parent frame if (elementFrame.mustacheCount > 0) { parentFrame.mustacheCount++; } parentFrame.childTemplateCount += elementFrame.childTemplateCount; (_parentFrame$actions = parentFrame.actions).push.apply(_parentFrame$actions, elementFrame.actions); }; TemplateVisitor.prototype.AttrNode = function AttrNode(attr) { if (attr.value.type !== 'TextNode') { this.currentFrame.mustacheCount++; } }; TemplateVisitor.prototype.TextNode = function TextNode(text) { var frame = this.currentFrame; if (text.chars === '') { frame.blankChildTextNodes.push(domIndexOf(frame.children, text)); } frame.actions.push(['text', [text, frame.childIndex, frame.childCount]]); }; TemplateVisitor.prototype.BlockStatement = function BlockStatement(node) { var frame = this.currentFrame; frame.mustacheCount++; frame.actions.push(['block', [node, frame.childIndex, frame.childCount]]); if (node.inverse) { this.visit(node.inverse); } if (node.program) { this.visit(node.program); } }; TemplateVisitor.prototype.PartialStatement = function PartialStatement(node) { var frame = this.currentFrame; frame.mustacheCount++; frame.actions.push(['mustache', [node, frame.childIndex, frame.childCount]]); }; TemplateVisitor.prototype.CommentStatement = function CommentStatement(text) { var frame = this.currentFrame; frame.actions.push(['comment', [text, frame.childIndex, frame.childCount]]); }; TemplateVisitor.prototype.MustacheCommentStatement = function MustacheCommentStatement() { // Intentional empty: Handlebars comments should not affect output. }; TemplateVisitor.prototype.MustacheStatement = function MustacheStatement(mustache) { var frame = this.currentFrame; frame.mustacheCount++; frame.actions.push(['mustache', [mustache, frame.childIndex, frame.childCount]]); }; // Frame helpers TemplateVisitor.prototype.getCurrentFrame = function getCurrentFrame() { return this.frameStack[this.frameStack.length - 1]; }; TemplateVisitor.prototype.pushFrame = function pushFrame() { var frame = new Frame(); this.frameStack.push(frame); return frame; }; TemplateVisitor.prototype.popFrame = function popFrame() { return this.frameStack.pop(); }; _createClass(TemplateVisitor, [{ key: 'currentFrame', get: function get() { return this.getCurrentFrame(); } }]); return TemplateVisitor; }(); function domIndexOf(nodes, domNode) { var index = -1; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.type !== 'TextNode' && node.type !== 'ElementNode') { continue; } else { index++; } if (node === domNode) { return index; } } return -1; } var _createClass$1 = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _defaults$1(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } function _possibleConstructorReturn$1(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits$1(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults$1(subClass, superClass); } function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Block = function () { function Block() { _classCallCheck$1(this, Block); this.statements = []; } Block.prototype.push = function push(statement) { this.statements.push(statement); }; return Block; }(); var InlineBlock = function (_Block) { _inherits$1(InlineBlock, _Block); function InlineBlock(table) { _classCallCheck$1(this, InlineBlock); var _this = _possibleConstructorReturn$1(this, _Block.call(this)); _this.table = table; return _this; } InlineBlock.prototype.toJSON = function toJSON() { return { statements: this.statements, parameters: this.table.slots }; }; return InlineBlock; }(Block); var NamedBlock = function (_InlineBlock) { _inherits$1(NamedBlock, _InlineBlock); function NamedBlock(name, table) { _classCallCheck$1(this, NamedBlock); var _this2 = _possibleConstructorReturn$1(this, _InlineBlock.call(this, table)); _this2.name = name; return _this2; } return NamedBlock; }(InlineBlock); var TemplateBlock = function (_Block2) { _inherits$1(TemplateBlock, _Block2); function TemplateBlock(symbolTable) { _classCallCheck$1(this, TemplateBlock); var _this3 = _possibleConstructorReturn$1(this, _Block2.call(this)); _this3.symbolTable = symbolTable; _this3.type = 'template'; _this3.yields = new util.DictSet(); _this3.named = new util.DictSet(); _this3.blocks = []; _this3.hasEval = false; return _this3; } TemplateBlock.prototype.push = function push(statement) { this.statements.push(statement); }; TemplateBlock.prototype.toJSON = function toJSON() { return { symbols: this.symbolTable.symbols, statements: this.statements, hasEval: this.hasEval, upvars: this.symbolTable.freeVariables }; }; return TemplateBlock; }(Block); var ComponentBlock = function (_Block3) { _inherits$1(ComponentBlock, _Block3); function ComponentBlock(tag, table, selfClosing) { _classCallCheck$1(this, ComponentBlock); var _this4 = _possibleConstructorReturn$1(this, _Block3.call(this)); _this4.tag = tag; _this4.table = table; _this4.selfClosing = selfClosing; _this4.attributes = []; _this4.arguments = []; _this4.inParams = true; _this4.positionals = []; _this4.blocks = []; return _this4; } ComponentBlock.prototype.push = function push(statement) { if (this.inParams) { if (wireFormat.isFlushElement(statement)) { this.inParams = false; } else if (wireFormat.isArgument(statement)) { this.arguments.push(statement); } else if (wireFormat.isAttribute(statement)) { this.attributes.push(statement); } else { throw new Error('Compile Error: only parameters allowed before flush-element'); } } else { this.statements.push(statement); } }; ComponentBlock.prototype.pushBlock = function pushBlock(name, block) { this.blocks.push([name, block]); }; ComponentBlock.prototype.toJSON = function toJSON() { var blocks = void 0; var args = this.arguments; var keys = args.map(function (arg) { return arg[1]; }); var values = args.map(function (arg) { return arg[2]; }); if (this.selfClosing) { blocks = null; } else if (this.blocks.length > 0) { var _keys = []; var _values = []; for (var i = 0; i < this.blocks.length; i++) { var _blocks$i = this.blocks[i], key = _blocks$i[0], value = _blocks$i[1]; _keys.push(key.slice(1)); _values.push(value); } blocks = [_keys, _values]; } else { blocks = [['default'], [{ statements: this.statements, parameters: this.table.slots }]]; } return [this.tag, this.attributes, [keys, values], blocks]; }; return ComponentBlock; }(Block); var Template = function () { function Template(symbols) { _classCallCheck$1(this, Template); this.block = new TemplateBlock(symbols); } Template.prototype.toJSON = function toJSON() { return this.block.toJSON(); }; return Template; }(); var JavaScriptCompiler = function () { function JavaScriptCompiler(opcodes, symbols, locations, options) { _classCallCheck$1(this, JavaScriptCompiler); this.locations = locations; this.blocks = new util.Stack(); this.values = []; this.location = null; this.locationStack = []; this.opcodes = opcodes; this.template = new Template(symbols); this.options = options; } JavaScriptCompiler.process = function process(opcodes, locations, symbols, options) { var compiler = new JavaScriptCompiler(opcodes, symbols, locations, options); return compiler.process(); }; JavaScriptCompiler.prototype.process = function process() { var _this5 = this; this.opcodes.forEach(function (op, i) { var opcode = op[0]; _this5.location = _this5.locations[i]; var arg = op[1]; if (!_this5[opcode]) { throw new Error('unimplemented ' + opcode + ' on JavaScriptCompiler'); } _this5[opcode](arg); }); return this.template; }; /// Nesting JavaScriptCompiler.prototype.startBlock = function startBlock(program) { this.startInlineBlock(program.symbols); }; JavaScriptCompiler.prototype.endBlock = function endBlock() { var block = this.endInlineBlock(); this.template.block.blocks.push(block); }; JavaScriptCompiler.prototype.startProgram = function startProgram() { this.blocks.push(this.template.block); }; JavaScriptCompiler.prototype.endProgram = function endProgram() {}; /// Statements JavaScriptCompiler.prototype.text = function text(content) { this.push([1 /* Append */, 1, 0, 0, content]); }; JavaScriptCompiler.prototype.append = function append(trusted) { this.push([1 /* Append */, +trusted, 0, 0, this.popValue()]); }; JavaScriptCompiler.prototype.comment = function comment(value) { this.push([2 /* Comment */, value]); }; JavaScriptCompiler.prototype.modifier = function modifier() { var name = this.popValue(); var params = this.popValue(); var hash = this.popValue(); this.push([3 /* Modifier */, 0, 0, name, params, hash]); }; JavaScriptCompiler.prototype.block = function block(_ref) { var template = _ref[0], inverse = _ref[1]; var head = this.popValue(); var params = this.popValue(); var hash = this.popValue(); var blocks = this.template.block.blocks; var namedBlocks = void 0; if (template === null && inverse === null) { namedBlocks = null; } else if (inverse === null) { namedBlocks = [['default'], [blocks[template]]]; } else { namedBlocks = [['default', 'else'], [blocks[template], blocks[inverse]]]; } // assert(head[]); this.push([5 /* Block */, head, params, hash, namedBlocks]); }; JavaScriptCompiler.prototype.openComponent = function openComponent(element) { var tag = this.options && this.options.customizeComponentName ? this.options.customizeComponentName(element.tag) : element.tag; var component = new ComponentBlock(tag, element.symbols, element.selfClosing); this.blocks.push(component); }; JavaScriptCompiler.prototype.openNamedBlock = function openNamedBlock(element) { var block = new NamedBlock(element.tag, element.symbols); this.blocks.push(block); }; JavaScriptCompiler.prototype.openElement = function openElement(_ref2) { var element = _ref2[0], simple = _ref2[1]; var tag = element.tag; if (element.blockParams.length > 0) { throw new Error('Compile Error: <' + element.tag + '> is not a component and doesn\'t support block parameters'); } else { this.push([9 /* OpenElement */, tag, simple]); } }; JavaScriptCompiler.prototype.flushElement = function flushElement() { this.push([10 /* FlushElement */]); }; JavaScriptCompiler.prototype.closeComponent = function closeComponent(_element) { var _endComponent = this.endComponent(), tag = _endComponent[0], attrs = _endComponent[1], args = _endComponent[2], blocks = _endComponent[3]; this.push([7 /* Component */, tag, attrs, args, blocks]); }; JavaScriptCompiler.prototype.closeNamedBlock = function closeNamedBlock(_element) { var blocks = this.blocks; var block = blocks.pop(); this.currentComponent.pushBlock(block.name, block.toJSON()); }; JavaScriptCompiler.prototype.closeDynamicComponent = function closeDynamicComponent(_element) { var _endComponent2 = this.endComponent(), attrs = _endComponent2[1], args = _endComponent2[2], block = _endComponent2[3]; this.push([7 /* Component */, this.popValue(), attrs, args, block]); }; JavaScriptCompiler.prototype.closeElement = function closeElement(_element) { this.push([11 /* CloseElement */]); }; JavaScriptCompiler.prototype.staticAttr = function staticAttr(_ref3) { var name = _ref3[0], namespace = _ref3[1]; var value = this.popValue(); this.push([12 /* StaticAttr */, name, value, namespace]); }; JavaScriptCompiler.prototype.dynamicAttr = function dynamicAttr(_ref4) { var name = _ref4[0], namespace = _ref4[1]; var value = this.popValue(); this.push([13 /* DynamicAttr */, name, value, namespace]); }; JavaScriptCompiler.prototype.componentAttr = function componentAttr(_ref5) { var name = _ref5[0], namespace = _ref5[1]; var value = this.popValue(); this.push([14 /* ComponentAttr */, name, value, namespace]); }; JavaScriptCompiler.prototype.trustingAttr = function trustingAttr(_ref6) { var name = _ref6[0], namespace = _ref6[1]; var value = this.popValue(); this.push([20 /* TrustingDynamicAttr */, name, value, namespace]); }; JavaScriptCompiler.prototype.trustingComponentAttr = function trustingComponentAttr(_ref7) { var name = _ref7[0], namespace = _ref7[1]; var value = this.popValue(); this.push([21 /* TrustingComponentAttr */, name, value, namespace]); }; JavaScriptCompiler.prototype.staticArg = function staticArg(name) { var value = this.popValue(); this.push([19 /* StaticArg */, name, value]); }; JavaScriptCompiler.prototype.dynamicArg = function dynamicArg(name) { var value = this.popValue(); this.push([18 /* DynamicArg */, name, value]); }; JavaScriptCompiler.prototype.yield = function _yield(to) { var params = this.popValue(); this.push([16 /* Yield */, to, params]); }; JavaScriptCompiler.prototype.attrSplat = function attrSplat(to) { // consume (and disregard) the value pushed for the // ...attributes attribute this.popValue(); this.push([15 /* AttrSplat */, to]); }; JavaScriptCompiler.prototype.debugger = function _debugger(evalInfo) { this.push([22 /* Debugger */, evalInfo]); this.template.block.hasEval = true; }; JavaScriptCompiler.prototype.hasBlock = function hasBlock(name) { this.pushValue([28 /* HasBlock */, [24 /* GetSymbol */, name]]); }; JavaScriptCompiler.prototype.hasBlockParams = function hasBlockParams(name) { this.pushValue([29 /* HasBlockParams */ , [24 /* GetSymbol */, name]]); }; JavaScriptCompiler.prototype.partial = function partial(evalInfo) { var params = this.popValue(); this.push([17 /* Partial */, params[0], evalInfo]); this.template.block.hasEval = true; }; /// Expressions JavaScriptCompiler.prototype.literal = function literal(value) { if (value === undefined) { this.pushValue([30 /* Undefined */]); } else { this.pushValue(value); } }; JavaScriptCompiler.prototype.getPath = function getPath(rest) { var head = this.popValue(); this.pushValue([27 /* GetPath */, head, rest]); }; JavaScriptCompiler.prototype.getSymbol = function getSymbol(head) { this.pushValue([24 /* GetSymbol */, head]); }; JavaScriptCompiler.prototype.getFree = function getFree(head) { this.pushValue([25 /* GetFree */, head]); }; JavaScriptCompiler.prototype.getFreeWithContext = function getFreeWithContext(_ref8) { var head = _ref8[0], context = _ref8[1]; this.pushValue([26 /* GetContextualFree */, head, context]); }; JavaScriptCompiler.prototype.concat = function concat() { this.pushValue([32 /* Concat */, this.popValue()]); }; JavaScriptCompiler.prototype.helper = function helper() { var _popLocatedValue = this.popLocatedValue(), head = _popLocatedValue.value, location = _popLocatedValue.location; var params = this.popValue(); var hash = this.popValue(); this.pushValue([31 /* Call */ , start(location), end(location), head, params, hash]); }; /// Stack Management Opcodes JavaScriptCompiler.prototype.prepareArray = function prepareArray(size) { var values = []; for (var i = 0; i < size; i++) { values.push(this.popValue()); } this.pushValue(values); }; JavaScriptCompiler.prototype.prepareObject = function prepareObject(size) { var keys = new Array(size); var values = new Array(size); for (var i = 0; i < size; i++) { keys[i] = this.popValue(); values[i] = this.popValue(); } this.pushValue([keys, values]); }; /// Utilities JavaScriptCompiler.prototype.endComponent = function endComponent() { var component = this.blocks.pop(); return component.toJSON(); }; JavaScriptCompiler.prototype.startInlineBlock = function startInlineBlock(symbols) { var block = new InlineBlock(symbols); this.blocks.push(block); }; JavaScriptCompiler.prototype.endInlineBlock = function endInlineBlock() { var blocks = this.blocks; var block = blocks.pop(); return block.toJSON(); }; JavaScriptCompiler.prototype.push = function push(args) { this.currentBlock.push(args); }; JavaScriptCompiler.prototype.pushValue = function pushValue(val) { this.values.push(val); this.locationStack.push(this.location); }; JavaScriptCompiler.prototype.popLocatedValue = function popLocatedValue() { var value = this.values.pop(); var location = this.locationStack.pop(); if (location === undefined) { throw new Error('Unbalanced location push and pop'); } return { value: value, location: location }; }; JavaScriptCompiler.prototype.popValue = function popValue() { return this.popLocatedValue().value; }; _createClass$1(JavaScriptCompiler, [{ key: 'currentBlock', get: function get() { return this.blocks.current; } }, { key: 'currentComponent', get: function get() { var block = this.currentBlock; if (block instanceof ComponentBlock) { return block; } else { throw new Error('Expected ComponentBlock on stack, found ' + block.constructor.name); } } }]); return JavaScriptCompiler; }(); function start(location) { if (location) { return location.start; } else { return -1; } } function end(location) { if (location) { return location.end - location.start; } else { return -1; } } // There is a small whitelist of namespaced attributes specially // enumerated in // https://www.w3.org/TR/html/syntax.html#attributes-0 // // > When a foreign element has one of the namespaced attributes given by // > the local name and namespace of the first and second cells of a row // > from the following table, it must be written using the name given by // > the third cell from the same row. // // In all other cases, colons are interpreted as a regular character // with no special meaning: // // > No other namespaced attribute can be expressed in the HTML syntax. var XLINK = 'http://www.w3.org/1999/xlink'; var XML = 'http://www.w3.org/XML/1998/namespace'; var XMLNS = 'http://www.w3.org/2000/xmlns/'; var WHITELIST = { 'xlink:actuate': XLINK, 'xlink:arcrole': XLINK, 'xlink:href': XLINK, 'xlink:role': XLINK, 'xlink:show': XLINK, 'xlink:title': XLINK, 'xlink:type': XLINK, 'xml:base': XML, 'xml:lang': XML, 'xml:space': XML, xmlns: XMLNS, 'xmlns:xlink': XMLNS }; function getAttrNamespace(attrName) { return WHITELIST[attrName] || null; } var _createClass$2 = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck$2(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var SymbolAllocator = function () { function SymbolAllocator(ops, locations) { _classCallCheck$2(this, SymbolAllocator); this.ops = ops; this.locations = locations; this.symbolStack = new util.Stack(); } SymbolAllocator.prototype.process = function process() { var out = []; var locations = []; var ops = this.ops; for (var i = 0; i < ops.length; i++) { var op = ops[i]; var location = this.locations[i]; var result = this.dispatch(op); out.push(result); locations.push(location); } return { ops: out, locations: locations }; }; SymbolAllocator.prototype.dispatch = function dispatch(op) { var name = op[0]; var operand = op[1]; return this[name](operand) || op; }; SymbolAllocator.prototype.startProgram = function startProgram(op) { this.symbolStack.push(op.symbols); }; SymbolAllocator.prototype.endProgram = function endProgram() { this.symbolStack.pop(); }; SymbolAllocator.prototype.startBlock = function startBlock(op) { this.symbolStack.push(op.symbols); }; SymbolAllocator.prototype.endBlock = function endBlock() { this.symbolStack.pop(); }; SymbolAllocator.prototype.openNamedBlock = function openNamedBlock(op) { this.symbolStack.push(op.symbols); }; SymbolAllocator.prototype.closeNamedBlock = function closeNamedBlock(_op) { this.symbolStack.pop(); }; SymbolAllocator.prototype.flushElement = function flushElement(op) { this.symbolStack.push(op.symbols); }; SymbolAllocator.prototype.closeElement = function closeElement(_op) { this.symbolStack.pop(); }; SymbolAllocator.prototype.closeComponent = function closeComponent(_op) { this.symbolStack.pop(); }; SymbolAllocator.prototype.closeDynamicComponent = function closeDynamicComponent(_op) { this.symbolStack.pop(); }; SymbolAllocator.prototype.attrSplat = function attrSplat() { return ['attrSplat', this.symbols.allocateBlock('attrs')]; }; SymbolAllocator.prototype.getFree = function getFree(name) { var symbol = this.symbols.allocateFree(name); return ['getFree', symbol]; }; SymbolAllocator.prototype.getArg = function getArg(name) { var symbol = this.symbols.allocateNamed(name); return ['getSymbol', symbol]; }; SymbolAllocator.prototype.getThis = function getThis() { return ['getSymbol', 0]; }; SymbolAllocator.prototype.getVar = function getVar(_ref) { var name = _ref[0], context = _ref[1]; if (this.symbols.has(name)) { var symbol = this.symbols.get(name); return ['getSymbol', symbol]; } else { var _symbol = this.symbols.allocateFree(name); return ['getFreeWithContext', [_symbol, context]]; } }; SymbolAllocator.prototype.getPath = function getPath(rest) { return ['getPath', rest]; }; SymbolAllocator.prototype.yield = function _yield(op) { return ['yield', this.symbols.allocateBlock(op)]; }; SymbolAllocator.prototype.debugger = function _debugger(_op) { return ['debugger', this.symbols.getEvalInfo()]; }; SymbolAllocator.prototype.hasBlock = function hasBlock(op) { if (op === 0) { throw new Error('Cannot hasBlock this'); } return ['hasBlock', this.symbols.allocateBlock(op)]; }; SymbolAllocator.prototype.hasBlockParams = function hasBlockParams(op) { if (op === 0) { throw new Error('Cannot hasBlockParams this'); } return ['hasBlockParams', this.symbols.allocateBlock(op)]; }; SymbolAllocator.prototype.partial = function partial() { return ['partial', this.symbols.getEvalInfo()]; }; SymbolAllocator.prototype.block = function block(_ref2) { var template = _ref2[0], inverse = _ref2[1]; return ['block', [template, inverse]]; }; SymbolAllocator.prototype.modifier = function modifier() { return ['modifier']; }; SymbolAllocator.prototype.helper = function helper() { return ['helper']; }; SymbolAllocator.prototype.text = function text(content) { return ['text', content]; }; SymbolAllocator.prototype.comment = function comment(_comment) { return ['comment', _comment]; }; SymbolAllocator.prototype.openComponent = function openComponent(element) { return ['openComponent', element]; }; SymbolAllocator.prototype.openElement = function openElement(_ref3) { var element = _ref3[0], simple = _ref3[1]; return ['openElement', [element, simple]]; }; SymbolAllocator.prototype.staticArg = function staticArg(name) { return ['staticArg', name]; }; SymbolAllocator.prototype.dynamicArg = function dynamicArg(name) { return ['dynamicArg', name]; }; SymbolAllocator.prototype.staticAttr = function staticAttr(_ref4) { var name = _ref4[0], ns = _ref4[1]; return ['staticAttr', [name, ns]]; }; SymbolAllocator.prototype.trustingAttr = function trustingAttr(_ref5) { var name = _ref5[0], ns = _ref5[1]; return ['trustingAttr', [name, ns]]; }; SymbolAllocator.prototype.dynamicAttr = function dynamicAttr(_ref6) { var name = _ref6[0], ns = _ref6[1]; return ['dynamicAttr', [name, ns]]; }; SymbolAllocator.prototype.componentAttr = function componentAttr(_ref7) { var name = _ref7[0], ns = _ref7[1]; return ['componentAttr', [name, ns]]; }; SymbolAllocator.prototype.trustingComponentAttr = function trustingComponentAttr(_ref8) { var name = _ref8[0], ns = _ref8[1]; return ['trustedComponentAttr', [name, ns]]; }; SymbolAllocator.prototype.append = function append(trusted) { return ['append', trusted]; }; SymbolAllocator.prototype.literal = function literal(value) { return ['literal', value]; }; SymbolAllocator.prototype.prepareArray = function prepareArray(count) { return ['prepareArray', count]; }; SymbolAllocator.prototype.prepareObject = function prepareObject(count) { return ['prepareObject', count]; }; SymbolAllocator.prototype.concat = function concat() { return ['concat']; }; _createClass$2(SymbolAllocator, [{ key: 'symbols', get: function get() { return this.symbolStack.current; } }]); return SymbolAllocator; }(); function locationToOffset(source, line, column) { var seenLines = 0; var seenChars = 0; while (true) { if (seenChars === source.length) return null; var nextLine = source.indexOf('\n', seenChars); if (nextLine === -1) nextLine = source.length; if (seenLines === line) { if (seenChars + column > nextLine) return null; return seenChars + column; } else if (nextLine === -1) { return null; } else { seenLines += 1; seenChars = nextLine + 1; } } } function offsetToLocation(source, offset) { var seenLines = 0; var seenChars = 0; if (offset > source.length) { return null; } while (true) { var nextLine = source.indexOf('\n', seenChars); if (offset <= nextLine || nextLine === -1) { return { line: seenLines, column: offset - seenChars }; } else { seenLines += 1; seenChars = nextLine + 1; } } } function _classCallCheck$3(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function isTrustedValue(value) { return value.escaped !== undefined && !value.escaped; } var TemplateCompiler = function () { function TemplateCompiler(source) { _classCallCheck$3(this, TemplateCompiler); this.source = source; this.templateId = 0; this.templateIds = []; this.opcodes = []; this.locations = []; this.includeMeta = true; } TemplateCompiler.compile = function compile(ast, source, options) { var templateVisitor = new TemplateVisitor(); templateVisitor.visit(ast); var compiler = new TemplateCompiler(source); var _compiler$process = compiler.process(templateVisitor.actions), opcodes = _compiler$process.opcodes, templateLocations = _compiler$process.locations; var _process = new SymbolAllocator(opcodes, templateLocations).process(), ops = _process.ops, allocationLocations = _process.locations; var out = JavaScriptCompiler.process(ops, allocationLocations, ast.symbols, options); return out; }; TemplateCompiler.prototype.process = function process(actions) { var _this = this; actions.forEach(function (_ref) { var name = _ref[0], args = _ref[1]; if (!_this[name]) { throw new Error('Unimplemented ' + name + ' on TemplateCompiler'); } _this[name](args); }); return { opcodes: this.opcodes, locations: this.locations }; }; TemplateCompiler.prototype.startProgram = function startProgram(_ref2) { var program = _ref2[0]; this.opcode(['startProgram', program], program); }; TemplateCompiler.prototype.endProgram = function endProgram() { this.opcode(['endProgram'], null); }; TemplateCompiler.prototype.startBlock = function startBlock(_ref3) { var program = _ref3[0]; this.templateId++; this.opcode(['startBlock', program], program); }; TemplateCompiler.prototype.endBlock = function endBlock() { this.templateIds.push(this.templateId - 1); this.opcode(['endBlock'], null); }; TemplateCompiler.prototype.text = function text(_ref4) { var action = _ref4[0]; this.opcode(['tex