ember-legacy-class-transform
Version:
The default blueprint for ember-cli addons.
1,393 lines (1,289 loc) • 53.6 kB
JavaScript
define('@glimmer/syntax', ['exports', 'simple-html-tokenizer', '@glimmer/util', 'handlebars'], function (exports, simpleHtmlTokenizer, _glimmer_util, handlebars) { 'use strict';
function isCall(node) {
return node.type === 'SubExpression' || node.type === 'MustacheStatement' && node.path.type === 'PathExpression';
}
function isLiteral(input) {
return !!(typeof input === 'object' && input.type.match(/Literal$/));
}
var nodes = Object.freeze({
isCall: isCall,
isLiteral: isLiteral
});
function buildMustache(path, params, hash, raw, loc) {
if (!isLiteral(path)) {
path = buildPath(path);
}
return {
type: "MustacheStatement",
path: path,
params: params || [],
hash: hash || buildHash([]),
escaped: !raw,
loc: buildLoc(loc || null)
};
}
function buildBlock(path, params, hash, program, inverse, loc) {
return {
type: "BlockStatement",
path: buildPath(path),
params: params || [],
hash: hash || buildHash([]),
program: program || null,
inverse: inverse || null,
loc: buildLoc(loc || null)
};
}
function buildElementModifier(path, params, hash, loc) {
return {
type: "ElementModifierStatement",
path: buildPath(path),
params: params || [],
hash: hash || buildHash([]),
loc: buildLoc(loc || null)
};
}
function buildPartial(name, params, hash, indent, loc) {
return {
type: "PartialStatement",
name: name,
params: params || [],
hash: hash || buildHash([]),
indent: indent || '',
strip: { open: false, close: false },
loc: buildLoc(loc || null)
};
}
function buildComment(value, loc) {
return {
type: "CommentStatement",
value: value,
loc: buildLoc(loc || null)
};
}
function buildMustacheComment(value, loc) {
return {
type: "MustacheCommentStatement",
value: value,
loc: buildLoc(loc || null)
};
}
function buildConcat(parts, loc) {
return {
type: "ConcatStatement",
parts: parts || [],
loc: buildLoc(loc || null)
};
}
function buildElement(tag, attributes, modifiers, children, comments, loc) {
// this is used for backwards compat prior to `comments` being added to the AST
if (!Array.isArray(comments)) {
loc = comments;
comments = [];
}
return {
type: "ElementNode",
tag: tag || "",
attributes: attributes || [],
blockParams: [],
modifiers: modifiers || [],
comments: comments || [],
children: children || [],
loc: buildLoc(loc || null)
};
}
function buildAttr(name, value, loc) {
return {
type: "AttrNode",
name: name,
value: value,
loc: buildLoc(loc || null)
};
}
function buildText(chars, loc) {
return {
type: "TextNode",
chars: chars || "",
loc: buildLoc(loc || null)
};
}
// Expressions
function buildSexpr(path, params, hash, loc) {
return {
type: "SubExpression",
path: buildPath(path),
params: params || [],
hash: hash || buildHash([]),
loc: buildLoc(loc || null)
};
}
function buildPath(original, loc) {
if (typeof original !== 'string') return original;
var parts = original.split('.');
var thisHead = false;
if (parts[0] === 'this') {
thisHead = true;
parts = parts.slice(1);
}
return {
type: "PathExpression",
original: original,
this: thisHead,
parts: parts,
data: false,
loc: buildLoc(loc || null)
};
}
function buildLiteral(type, value, loc) {
return {
type: type,
value: value,
original: value,
loc: buildLoc(loc || null)
};
}
// Miscellaneous
function buildHash(pairs, loc) {
return {
type: "Hash",
pairs: pairs || [],
loc: buildLoc(loc || null)
};
}
function buildPair(key, value, loc) {
return {
type: "HashPair",
key: key,
value: value,
loc: buildLoc(loc || null)
};
}
function buildProgram(body, blockParams, loc) {
return {
type: "Program",
body: body || [],
blockParams: blockParams || [],
loc: buildLoc(loc || null)
};
}
function buildSource(source) {
return source || null;
}
function buildPosition(line, column) {
return {
line: line,
column: column
};
}
var SYNTHETIC = { source: '(synthetic)', start: { line: 1, column: 0 }, end: { line: 1, column: 0 } };
function buildLoc() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (args.length === 1) {
var loc = args[0];
if (loc && typeof loc === 'object') {
return {
source: buildSource(loc.source),
start: buildPosition(loc.start.line, loc.start.column),
end: buildPosition(loc.end.line, loc.end.column)
};
} else {
return SYNTHETIC;
}
} else {
var startLine = args[0],
startColumn = args[1],
endLine = args[2],
endColumn = args[3],
source = args[4];
return {
source: buildSource(source),
start: buildPosition(startLine, startColumn),
end: buildPosition(endLine, endColumn)
};
}
}
var b = {
mustache: buildMustache,
block: buildBlock,
partial: buildPartial,
comment: buildComment,
mustacheComment: buildMustacheComment,
element: buildElement,
elementModifier: buildElementModifier,
attr: buildAttr,
text: buildText,
sexpr: buildSexpr,
path: buildPath,
concat: buildConcat,
hash: buildHash,
pair: buildPair,
literal: buildLiteral,
program: buildProgram,
loc: buildLoc,
pos: buildPosition,
string: literal('StringLiteral'),
boolean: literal('BooleanLiteral'),
number: literal('NumberLiteral'),
undefined: function () {
return buildLiteral('UndefinedLiteral', undefined);
},
null: function () {
return buildLiteral('NullLiteral', null);
}
};
function literal(type) {
return function (value) {
return buildLiteral(type, value);
};
}
/**
* Subclass of `Error` with additional information
* about location of incorrect markup.
*/
var SyntaxError = function () {
SyntaxError.prototype = Object.create(Error.prototype);
SyntaxError.prototype.constructor = SyntaxError;
function SyntaxError(message, location) {
var error = Error.call(this, message);
this.message = message;
this.stack = error.stack;
this.location = location;
}
return SyntaxError;
}();
// Regex to validate the identifier for block parameters.
// Based on the ID validation regex in Handlebars.
var ID_INVERSE_PATTERN = /[!"#%-,\.\/;->@\[-\^`\{-~]/;
// Checks the element's attributes to see if it uses block params.
// If it does, registers the block params with the program and
// removes the corresponding attributes from the element.
function parseElementBlockParams(element) {
var params = parseBlockParams(element);
if (params) element.blockParams = params;
}
function parseBlockParams(element) {
var l = element.attributes.length;
var attrNames = [];
for (var i = 0; i < l; i++) {
attrNames.push(element.attributes[i].name);
}
var asIndex = attrNames.indexOf('as');
if (asIndex !== -1 && l > asIndex && attrNames[asIndex + 1].charAt(0) === '|') {
// Some basic validation, since we're doing the parsing ourselves
var paramsString = attrNames.slice(asIndex).join(' ');
if (paramsString.charAt(paramsString.length - 1) !== '|' || paramsString.match(/\|/g).length !== 2) {
throw new SyntaxError('Invalid block parameters syntax: \'' + paramsString + '\'', element.loc);
}
var params = [];
for (var _i = asIndex + 1; _i < l; _i++) {
var param = attrNames[_i].replace(/\|/g, '');
if (param !== '') {
if (ID_INVERSE_PATTERN.test(param)) {
throw new SyntaxError('Invalid identifier for block parameters: \'' + param + '\' in \'' + paramsString + '\'', element.loc);
}
params.push(param);
}
}
if (params.length === 0) {
throw new SyntaxError('Cannot use zero block parameters: \'' + paramsString + '\'', element.loc);
}
element.attributes = element.attributes.slice(0, asIndex);
return params;
}
return null;
}
function childrenFor(node) {
switch (node.type) {
case 'Program':
return node.body;
case 'ElementNode':
return node.children;
}
}
function appendChild(parent, node) {
childrenFor(parent).push(node);
}
function isLiteral$1(path) {
return path.type === 'StringLiteral' || path.type === 'BooleanLiteral' || path.type === 'NumberLiteral' || path.type === 'NullLiteral' || path.type === 'UndefinedLiteral';
}
function printLiteral(literal) {
if (literal.type === 'UndefinedLiteral') {
return 'undefined';
} else {
return JSON.stringify(literal.value);
}
}
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 _classCallCheck$2(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var entityParser = new simpleHtmlTokenizer.EntityParser(simpleHtmlTokenizer.HTML5NamedCharRefs);
var Parser = function () {
function Parser(source) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck$2(this, Parser);
this.elementStack = [];
this.currentAttribute = null;
this.currentNode = null;
this.tokenizer = new simpleHtmlTokenizer.EventedTokenizer(this, entityParser);
this.options = options;
this.source = source.split(/(?:\r\n?|\n)/g);
}
Parser.prototype.acceptNode = function acceptNode(node) {
return this[node.type](node);
};
Parser.prototype.currentElement = function currentElement() {
return this.elementStack[this.elementStack.length - 1];
};
Parser.prototype.sourceForNode = function sourceForNode(node, endNode) {
var firstLine = node.loc.start.line - 1;
var currentLine = firstLine - 1;
var firstColumn = node.loc.start.column;
var string = [];
var line = void 0;
var lastLine = void 0;
var lastColumn = void 0;
if (endNode) {
lastLine = endNode.loc.end.line - 1;
lastColumn = endNode.loc.end.column;
} else {
lastLine = node.loc.end.line - 1;
lastColumn = node.loc.end.column;
}
while (currentLine < lastLine) {
currentLine++;
line = this.source[currentLine];
if (currentLine === firstLine) {
if (firstLine === lastLine) {
string.push(line.slice(firstColumn, lastColumn));
} else {
string.push(line.slice(firstColumn));
}
} else if (currentLine === lastLine) {
string.push(line.slice(0, lastColumn));
} else {
string.push(line);
}
}
return string.join('\n');
};
_createClass(Parser, [{
key: 'currentAttr',
get: function () {
return this.currentAttribute;
}
}, {
key: 'currentTag',
get: function () {
var node = this.currentNode;
_glimmer_util.assert(node && (node.type === 'StartTag' || node.type === 'EndTag'), 'expected tag');
return node;
}
}, {
key: 'currentStartTag',
get: function () {
var node = this.currentNode;
_glimmer_util.assert(node && node.type === 'StartTag', 'expected start tag');
return node;
}
}, {
key: 'currentEndTag',
get: function () {
var node = this.currentNode;
_glimmer_util.assert(node && node.type === 'EndTag', 'expected end tag');
return node;
}
}, {
key: 'currentComment',
get: function () {
var node = this.currentNode;
_glimmer_util.assert(node && node.type === 'CommentStatement', 'expected a comment');
return node;
}
}, {
key: 'currentData',
get: function () {
var node = this.currentNode;
_glimmer_util.assert(node && node.type === 'TextNode', 'expected a text node');
return node;
}
}]);
return Parser;
}();
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 _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
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); }
var HandlebarsNodeVisitors = function (_Parser) {
_inherits$1(HandlebarsNodeVisitors, _Parser);
function HandlebarsNodeVisitors() {
_classCallCheck$1(this, HandlebarsNodeVisitors);
return _possibleConstructorReturn$1(this, _Parser.apply(this, arguments));
}
HandlebarsNodeVisitors.prototype.Program = function Program(program) {
var body = [];
var node = b.program(body, program.blockParams, program.loc);
var i = void 0,
l = program.body.length;
this.elementStack.push(node);
if (l === 0) {
return this.elementStack.pop();
}
for (i = 0; i < l; i++) {
this.acceptNode(program.body[i]);
}
// Ensure that that the element stack is balanced properly.
var poppedNode = this.elementStack.pop();
if (poppedNode !== node) {
var elementNode = poppedNode;
throw new SyntaxError("Unclosed element `" + elementNode.tag + "` (on line " + elementNode.loc.start.line + ").", elementNode.loc);
}
return node;
};
HandlebarsNodeVisitors.prototype.BlockStatement = function BlockStatement(block) {
if (this.tokenizer['state'] === 'comment') {
this.appendToCommentData(this.sourceForNode(block));
return;
}
if (this.tokenizer['state'] !== 'comment' && this.tokenizer['state'] !== 'data' && this.tokenizer['state'] !== 'beforeData') {
throw new SyntaxError("A block may only be used inside an HTML element or another block.", block.loc);
}
var _acceptCallNodes = acceptCallNodes(this, block),
path = _acceptCallNodes.path,
params = _acceptCallNodes.params,
hash = _acceptCallNodes.hash;
var program = this.Program(block.program);
var inverse = block.inverse ? this.Program(block.inverse) : null;
var node = b.block(path, params, hash, program, inverse, block.loc);
var parentProgram = this.currentElement();
appendChild(parentProgram, node);
};
HandlebarsNodeVisitors.prototype.MustacheStatement = function MustacheStatement(rawMustache) {
var tokenizer = this.tokenizer;
if (tokenizer['state'] === 'comment') {
this.appendToCommentData(this.sourceForNode(rawMustache));
return;
}
var mustache = void 0;
var escaped = rawMustache.escaped,
loc = rawMustache.loc;
if (rawMustache.path.type.match(/Literal$/)) {
mustache = {
type: 'MustacheStatement',
path: this.acceptNode(rawMustache.path),
params: [],
hash: b.hash(),
escaped: escaped,
loc: loc
};
} else {
var _acceptCallNodes2 = acceptCallNodes(this, rawMustache),
path = _acceptCallNodes2.path,
params = _acceptCallNodes2.params,
hash = _acceptCallNodes2.hash;
mustache = b.mustache(path, params, hash, !escaped, loc);
}
switch (tokenizer.state) {
// Tag helpers
case "tagName":
addElementModifier(this.currentStartTag, mustache);
tokenizer.state = "beforeAttributeName";
break;
case "beforeAttributeName":
addElementModifier(this.currentStartTag, mustache);
break;
case "attributeName":
case "afterAttributeName":
this.beginAttributeValue(false);
this.finishAttributeValue();
addElementModifier(this.currentStartTag, mustache);
tokenizer.state = "beforeAttributeName";
break;
case "afterAttributeValueQuoted":
addElementModifier(this.currentStartTag, mustache);
tokenizer.state = "beforeAttributeName";
break;
// Attribute values
case "beforeAttributeValue":
appendDynamicAttributeValuePart(this.currentAttribute, mustache);
tokenizer.state = 'attributeValueUnquoted';
break;
case "attributeValueDoubleQuoted":
case "attributeValueSingleQuoted":
case "attributeValueUnquoted":
appendDynamicAttributeValuePart(this.currentAttribute, mustache);
break;
// TODO: Only append child when the tokenizer state makes
// sense to do so, otherwise throw an error.
default:
appendChild(this.currentElement(), mustache);
}
return mustache;
};
HandlebarsNodeVisitors.prototype.ContentStatement = function ContentStatement(content) {
updateTokenizerLocation(this.tokenizer, content);
this.tokenizer.tokenizePart(content.value);
this.tokenizer.flushData();
};
HandlebarsNodeVisitors.prototype.CommentStatement = function CommentStatement(rawComment) {
var tokenizer = this.tokenizer;
if (tokenizer.state === 'comment') {
this.appendToCommentData(this.sourceForNode(rawComment));
return null;
}
var value = rawComment.value,
loc = rawComment.loc;
var comment = b.mustacheComment(value, loc);
switch (tokenizer.state) {
case "beforeAttributeName":
this.currentStartTag.comments.push(comment);
break;
case 'beforeData':
case 'data':
appendChild(this.currentElement(), comment);
break;
default:
throw new SyntaxError("Using a Handlebars comment when in the `" + tokenizer.state + "` state is not supported: \"" + comment.value + "\" on line " + loc.start.line + ":" + loc.start.column, rawComment.loc);
}
return comment;
};
HandlebarsNodeVisitors.prototype.PartialStatement = function PartialStatement(partial) {
var loc = partial.loc;
throw new SyntaxError("Handlebars partials are not supported: \"" + this.sourceForNode(partial, partial.name) + "\" at L" + loc.start.line + ":C" + loc.start.column, partial.loc);
};
HandlebarsNodeVisitors.prototype.PartialBlockStatement = function PartialBlockStatement(partialBlock) {
var loc = partialBlock.loc;
throw new SyntaxError("Handlebars partial blocks are not supported: \"" + this.sourceForNode(partialBlock, partialBlock.name) + "\" at L" + loc.start.line + ":C" + loc.start.column, partialBlock.loc);
};
HandlebarsNodeVisitors.prototype.Decorator = function Decorator(decorator) {
var loc = decorator.loc;
throw new SyntaxError("Handlebars decorators are not supported: \"" + this.sourceForNode(decorator, decorator.path) + "\" at L" + loc.start.line + ":C" + loc.start.column, decorator.loc);
};
HandlebarsNodeVisitors.prototype.DecoratorBlock = function DecoratorBlock(decoratorBlock) {
var loc = decoratorBlock.loc;
throw new SyntaxError("Handlebars decorator blocks are not supported: \"" + this.sourceForNode(decoratorBlock, decoratorBlock.path) + "\" at L" + loc.start.line + ":C" + loc.start.column, decoratorBlock.loc);
};
HandlebarsNodeVisitors.prototype.SubExpression = function SubExpression(sexpr) {
var _acceptCallNodes3 = acceptCallNodes(this, sexpr),
path = _acceptCallNodes3.path,
params = _acceptCallNodes3.params,
hash = _acceptCallNodes3.hash;
return b.sexpr(path, params, hash, sexpr.loc);
};
HandlebarsNodeVisitors.prototype.PathExpression = function PathExpression(path) {
var original = path.original,
loc = path.loc;
var parts = void 0;
if (original.indexOf('/') !== -1) {
if (original.slice(0, 2) === './') {
throw new SyntaxError("Using \"./\" is not supported in Glimmer and unnecessary: \"" + path.original + "\" on line " + loc.start.line + ".", path.loc);
}
if (original.slice(0, 3) === '../') {
throw new SyntaxError("Changing context using \"../\" is not supported in Glimmer: \"" + path.original + "\" on line " + loc.start.line + ".", path.loc);
}
if (original.indexOf('.') !== -1) {
throw new SyntaxError("Mixing '.' and '/' in paths is not supported in Glimmer; use only '.' to separate property paths: \"" + path.original + "\" on line " + loc.start.line + ".", path.loc);
}
parts = [path.parts.join('/')];
} else {
parts = path.parts;
}
var thisHead = false;
// This is to fix a bug in the Handlebars AST where the path expressions in
// `{{this.foo}}` (and similarly `{{foo-bar this.foo named=this.foo}}` etc)
// are simply turned into `{{foo}}`. The fix is to push it back onto the
// parts array and let the runtime see the difference. However, we cannot
// simply use the string `this` as it means literally the property called
// "this" in the current context (it can be expressed in the syntax as
// `{{[this]}}`, where the square bracket are generally for this kind of
// escaping – such as `{{foo.["bar.baz"]}}` would mean lookup a property
// named literally "bar.baz" on `this.foo`). By convention, we use `null`
// for this purpose.
if (original.match(/^this(\..+)?$/)) {
thisHead = true;
}
return {
type: 'PathExpression',
original: path.original,
this: thisHead,
parts: parts,
data: path.data,
loc: path.loc
};
};
HandlebarsNodeVisitors.prototype.Hash = function Hash(hash) {
var pairs = [];
for (var i = 0; i < hash.pairs.length; i++) {
var pair = hash.pairs[i];
pairs.push(b.pair(pair.key, this.acceptNode(pair.value), pair.loc));
}
return b.hash(pairs, hash.loc);
};
HandlebarsNodeVisitors.prototype.StringLiteral = function StringLiteral(string) {
return b.literal('StringLiteral', string.value, string.loc);
};
HandlebarsNodeVisitors.prototype.BooleanLiteral = function BooleanLiteral(boolean) {
return b.literal('BooleanLiteral', boolean.value, boolean.loc);
};
HandlebarsNodeVisitors.prototype.NumberLiteral = function NumberLiteral(number) {
return b.literal('NumberLiteral', number.value, number.loc);
};
HandlebarsNodeVisitors.prototype.UndefinedLiteral = function UndefinedLiteral(undef) {
return b.literal('UndefinedLiteral', undefined, undef.loc);
};
HandlebarsNodeVisitors.prototype.NullLiteral = function NullLiteral(nul) {
return b.literal('NullLiteral', null, nul.loc);
};
return HandlebarsNodeVisitors;
}(Parser);
function calculateRightStrippedOffsets(original, value) {
if (value === '') {
// if it is empty, just return the count of newlines
// in original
return {
lines: original.split("\n").length - 1,
columns: 0
};
}
// otherwise, return the number of newlines prior to
// `value`
var difference = original.split(value)[0];
var lines = difference.split(/\n/);
var lineCount = lines.length - 1;
return {
lines: lineCount,
columns: lines[lineCount].length
};
}
function updateTokenizerLocation(tokenizer, content) {
var line = content.loc.start.line;
var column = content.loc.start.column;
var offsets = calculateRightStrippedOffsets(content.original, content.value);
line = line + offsets.lines;
if (offsets.lines) {
column = offsets.columns;
} else {
column = column + offsets.columns;
}
tokenizer.line = line;
tokenizer.column = column;
}
function acceptCallNodes(compiler, node) {
var path = compiler.PathExpression(node.path);
var params = node.params ? node.params.map(function (e) {
return compiler.acceptNode(e);
}) : [];
var hash = node.hash ? compiler.Hash(node.hash) : b.hash();
return { path: path, params: params, hash: hash };
}
function addElementModifier(element, mustache) {
var path = mustache.path,
params = mustache.params,
hash = mustache.hash,
loc = mustache.loc;
if (isLiteral$1(path)) {
var _modifier = "{{" + printLiteral(path) + "}}";
var tag = "<" + element.name + " ... " + _modifier + " ...";
throw new SyntaxError("In " + tag + ", " + _modifier + " is not a valid modifier: \"" + path.original + "\" on line " + (loc && loc.start.line) + ".", mustache.loc);
}
var modifier = b.elementModifier(path, params, hash, loc);
element.modifiers.push(modifier);
}
function appendDynamicAttributeValuePart(attribute, part) {
attribute.isDynamic = true;
attribute.parts.push(part);
}
var visitorKeys = {
Program: ['body'],
MustacheStatement: ['path', 'params', 'hash'],
BlockStatement: ['path', 'params', 'hash', 'program', 'inverse'],
ElementModifierStatement: ['path', 'params', 'hash'],
PartialStatement: ['name', 'params', 'hash'],
CommentStatement: [],
MustacheCommentStatement: [],
ElementNode: ['attributes', 'modifiers', 'children', 'comments'],
AttrNode: ['value'],
TextNode: [],
ConcatStatement: ['parts'],
SubExpression: ['path', 'params', 'hash'],
PathExpression: [],
StringLiteral: [],
BooleanLiteral: [],
NumberLiteral: [],
NullLiteral: [],
UndefinedLiteral: [],
Hash: ['pairs'],
HashPair: ['value']
};
var TraversalError = function () {
TraversalError.prototype = Object.create(Error.prototype);
TraversalError.prototype.constructor = TraversalError;
function TraversalError(message, node, parent, key) {
var error = Error.call(this, message);
this.key = key;
this.message = message;
this.node = node;
this.parent = parent;
this.stack = error.stack;
}
return TraversalError;
}();
function cannotRemoveNode(node, parent, key) {
return new TraversalError("Cannot remove a node unless it is part of an array", node, parent, key);
}
function cannotReplaceNode(node, parent, key) {
return new TraversalError("Cannot replace a node with multiple nodes unless it is part of an array", node, parent, key);
}
function cannotReplaceOrRemoveInKeyHandlerYet(node, key) {
return new TraversalError("Replacing and removing in key handlers is not yet supported.", node, null, key);
}
function visitNode(visitor, node) {
var handler = visitor[node.type] || visitor.All || null;
var result = void 0;
if (handler && handler['enter']) {
result = handler['enter'].call(null, node);
}
if (result !== undefined && result !== null) {
if (JSON.stringify(node) === JSON.stringify(result)) {
result = undefined;
} else if (Array.isArray(result)) {
return visitArray(visitor, result) || result;
} else {
return visitNode(visitor, result) || result;
}
}
if (result === undefined) {
var keys = visitorKeys[node.type];
for (var i = 0; i < keys.length; i++) {
visitKey(visitor, handler, node, keys[i]);
}
if (handler && handler['exit']) {
result = handler['exit'].call(null, node);
}
}
return result;
}
function visitKey(visitor, handler, node, key) {
var value = node[key];
if (!value) {
return;
}
var keyHandler = handler && (handler.keys[key] || handler.keys.All);
var result = void 0;
if (keyHandler && keyHandler.enter) {
result = keyHandler.enter.call(null, node, key);
if (result !== undefined) {
throw cannotReplaceOrRemoveInKeyHandlerYet(node, key);
}
}
if (Array.isArray(value)) {
visitArray(visitor, value);
} else {
var _result = visitNode(visitor, value);
if (_result !== undefined) {
assignKey(node, key, _result);
}
}
if (keyHandler && keyHandler.exit) {
result = keyHandler.exit.call(null, node, key);
if (result !== undefined) {
throw cannotReplaceOrRemoveInKeyHandlerYet(node, key);
}
}
}
function visitArray(visitor, array) {
for (var i = 0; i < array.length; i++) {
var result = visitNode(visitor, array[i]);
if (result !== undefined) {
i += spliceArray(array, i, result) - 1;
}
}
}
function assignKey(node, key, result) {
if (result === null) {
throw cannotRemoveNode(node[key], node, key);
} else if (Array.isArray(result)) {
if (result.length === 1) {
node[key] = result[0];
} else {
if (result.length === 0) {
throw cannotRemoveNode(node[key], node, key);
} else {
throw cannotReplaceNode(node[key], node, key);
}
}
} else {
node[key] = result;
}
}
function spliceArray(array, index, result) {
if (result === null) {
array.splice(index, 1);
return 0;
} else if (Array.isArray(result)) {
array.splice.apply(array, [index, 1].concat(result));
return result.length;
} else {
array.splice(index, 1, result);
return 1;
}
}
function traverse(node, visitor) {
visitNode(normalizeVisitor(visitor), node);
}
function normalizeVisitor(visitor) {
var normalizedVisitor = {};
for (var type in visitor) {
var handler = visitor[type] || visitor.All;
var normalizedKeys = {};
if (typeof handler === 'object') {
var keys = handler.keys;
if (keys) {
for (var key in keys) {
var keyHandler = keys[key];
if (typeof keyHandler === 'object') {
normalizedKeys[key] = {
enter: typeof keyHandler.enter === 'function' ? keyHandler.enter : null,
exit: typeof keyHandler.exit === 'function' ? keyHandler.exit : null
};
} else if (typeof keyHandler === 'function') {
normalizedKeys[key] = {
enter: keyHandler,
exit: null
};
}
}
}
normalizedVisitor[type] = {
enter: typeof handler.enter === 'function' ? handler.enter : null,
exit: typeof handler.exit === 'function' ? handler.exit : null,
keys: normalizedKeys
};
} else if (typeof handler === 'function') {
normalizedVisitor[type] = {
enter: handler,
exit: null,
keys: normalizedKeys
};
}
}
return normalizedVisitor;
}
function unreachable() {
throw new Error('unreachable');
}
function build(ast) {
if (!ast) {
return '';
}
var output = [];
switch (ast.type) {
case 'Program':
{
var chainBlock = ast['chained'] && ast.body[0];
if (chainBlock) {
chainBlock['chained'] = true;
}
var body = buildEach(ast.body).join('');
output.push(body);
}
break;
case 'ElementNode':
output.push('<', ast.tag);
if (ast.attributes.length) {
output.push(' ', buildEach(ast.attributes).join(' '));
}
if (ast.modifiers.length) {
output.push(' ', buildEach(ast.modifiers).join(' '));
}
if (ast.comments.length) {
output.push(' ', buildEach(ast.comments).join(' '));
}
output.push('>');
output.push.apply(output, buildEach(ast.children));
output.push('</', ast.tag, '>');
break;
case 'AttrNode':
output.push(ast.name, '=');
var value = build(ast.value);
if (ast.value.type === 'TextNode') {
output.push('"', value, '"');
} else {
output.push(value);
}
break;
case 'ConcatStatement':
output.push('"');
ast.parts.forEach(function (node) {
if (node.type === 'StringLiteral') {
output.push(node.original);
} else {
output.push(build(node));
}
});
output.push('"');
break;
case 'TextNode':
output.push(ast.chars);
break;
case 'MustacheStatement':
{
output.push(compactJoin(['{{', pathParams(ast), '}}']));
}
break;
case 'MustacheCommentStatement':
{
output.push(compactJoin(['{{!--', ast.value, '--}}']));
}
break;
case 'ElementModifierStatement':
{
output.push(compactJoin(['{{', pathParams(ast), '}}']));
}
break;
case 'PathExpression':
output.push(ast.original);
break;
case 'SubExpression':
{
output.push('(', pathParams(ast), ')');
}
break;
case 'BooleanLiteral':
output.push(ast.value ? 'true' : 'false');
break;
case 'BlockStatement':
{
var lines = [];
if (ast['chained']) {
lines.push(['{{else ', pathParams(ast), '}}'].join(''));
} else {
lines.push(openBlock(ast));
}
lines.push(build(ast.program));
if (ast.inverse) {
if (!ast.inverse['chained']) {
lines.push('{{else}}');
}
lines.push(build(ast.inverse));
}
if (!ast['chained']) {
lines.push(closeBlock(ast));
}
output.push(lines.join(''));
}
break;
case 'PartialStatement':
{
output.push(compactJoin(['{{>', pathParams(ast), '}}']));
}
break;
case 'CommentStatement':
{
output.push(compactJoin(['<!--', ast.value, '-->']));
}
break;
case 'StringLiteral':
{
output.push('"' + ast.value + '"');
}
break;
case 'NumberLiteral':
{
output.push(String(ast.value));
}
break;
case 'UndefinedLiteral':
{
output.push('undefined');
}
break;
case 'NullLiteral':
{
output.push('null');
}
break;
case 'Hash':
{
output.push(ast.pairs.map(function (pair) {
return build(pair);
}).join(' '));
}
break;
case 'HashPair':
{
output.push(ast.key + '=' + build(ast.value));
}
break;
}
return output.join('');
}
function compact(array) {
var newArray = [];
array.forEach(function (a) {
if (typeof a !== 'undefined' && a !== null && a !== '') {
newArray.push(a);
}
});
return newArray;
}
function buildEach(asts) {
return asts.map(build);
}
function pathParams(ast) {
var path = void 0;
switch (ast.type) {
case 'MustacheStatement':
case 'SubExpression':
case 'ElementModifierStatement':
case 'BlockStatement':
if (isLiteral(ast.path)) {
return String(ast.path.value);
}
path = build(ast.path);
break;
case 'PartialStatement':
path = build(ast.name);
break;
default:
return unreachable();
}
return compactJoin([path, buildEach(ast.params).join(' '), build(ast.hash)], ' ');
}
function compactJoin(array, delimiter) {
return compact(array).join(delimiter || '');
}
function blockParams(block) {
var params = block.program.blockParams;
if (params.length) {
return ' as |' + params.join(' ') + '|';
}
return null;
}
function openBlock(block) {
return ['{{#', pathParams(block), blockParams(block), '}}'].join('');
}
function closeBlock(block) {
return ['{{/', build(block.path), '}}'].join('');
}
function _classCallCheck$3(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Walker = function () {
function Walker(order) {
_classCallCheck$3(this, Walker);
this.order = order;
this.stack = [];
}
Walker.prototype.visit = function visit(node, callback) {
if (!node) {
return;
}
this.stack.push(node);
if (this.order === 'post') {
this.children(node, callback);
callback(node, this);
} else {
callback(node, this);
this.children(node, callback);
}
this.stack.pop();
};
Walker.prototype.children = function children(node, callback) {
var visitor = visitors[node.type];
if (visitor) {
visitor(this, node, callback);
}
};
return Walker;
}();
var visitors = {
Program: function (walker, node, callback) {
for (var i = 0; i < node.body.length; i++) {
walker.visit(node.body[i], callback);
}
},
ElementNode: function (walker, node, callback) {
for (var i = 0; i < node.children.length; i++) {
walker.visit(node.children[i], callback);
}
},
BlockStatement: function (walker, node, callback) {
walker.visit(node.program, callback);
walker.visit(node.inverse || null, callback);
}
};
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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
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); }
var voidMap = Object.create(null);
var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr";
voidTagNames.split(" ").forEach(function (tagName) {
voidMap[tagName] = true;
});
var TokenizerEventHandlers = function (_HandlebarsNodeVisito) {
_inherits(TokenizerEventHandlers, _HandlebarsNodeVisito);
function TokenizerEventHandlers() {
_classCallCheck(this, TokenizerEventHandlers);
var _this = _possibleConstructorReturn(this, _HandlebarsNodeVisito.apply(this, arguments));
_this.tagOpenLine = 0;
_this.tagOpenColumn = 0;
return _this;
}
TokenizerEventHandlers.prototype.reset = function reset() {
this.currentNode = null;
};
// Comment
TokenizerEventHandlers.prototype.beginComment = function beginComment() {
this.currentNode = b.comment("");
this.currentNode.loc = {
source: null,
start: b.pos(this.tagOpenLine, this.tagOpenColumn),
end: null
};
};
TokenizerEventHandlers.prototype.appendToCommentData = function appendToCommentData(char) {
this.currentComment.value += char;
};
TokenizerEventHandlers.prototype.finishComment = function finishComment() {
this.currentComment.loc.end = b.pos(this.tokenizer.line, this.tokenizer.column);
appendChild(this.currentElement(), this.currentComment);
};
// Data
TokenizerEventHandlers.prototype.beginData = function beginData() {
this.currentNode = b.text();
this.currentNode.loc = {
source: null,
start: b.pos(this.tokenizer.line, this.tokenizer.column),
end: null
};
};
TokenizerEventHandlers.prototype.appendToData = function appendToData(char) {
this.currentData.chars += char;
};
TokenizerEventHandlers.prototype.finishData = function finishData() {
this.currentData.loc.end = b.pos(this.tokenizer.line, this.tokenizer.column);
appendChild(this.currentElement(), this.currentData);
};
// Tags - basic
TokenizerEventHandlers.prototype.tagOpen = function tagOpen() {
this.tagOpenLine = this.tokenizer.line;
this.tagOpenColumn = this.tokenizer.column;
};
TokenizerEventHandlers.prototype.beginStartTag = function beginStartTag() {
this.currentNode = {
type: 'StartTag',
name: "",
attributes: [],
modifiers: [],
comments: [],
selfClosing: false,
loc: SYNTHETIC
};
};
TokenizerEventHandlers.prototype.beginEndTag = function beginEndTag() {
this.currentNode = {
type: 'EndTag',
name: "",
attributes: [],
modifiers: [],
comments: [],
selfClosing: false,
loc: SYNTHETIC
};
};
TokenizerEventHandlers.prototype.finishTag = function finishTag() {
var _tokenizer = this.tokenizer,
line = _tokenizer.line,
column = _tokenizer.column;
var tag = this.currentTag;
tag.loc = b.loc(this.tagOpenLine, this.tagOpenColumn, line, column);
if (tag.type === 'StartTag') {
this.finishStartTag();
if (voidMap[tag.name] || tag.selfClosing) {
this.finishEndTag(true);
}
} else if (tag.type === 'EndTag') {
this.finishEndTag(false);
}
};
TokenizerEventHandlers.prototype.finishStartTag = function finishStartTag() {
var _currentStartTag = this.currentStartTag,
name = _currentStartTag.name,
attributes = _currentStartTag.attributes,
modifiers = _currentStartTag.modifiers,
comments = _currentStartTag.comments;
var loc = b.loc(this.tagOpenLine, this.tagOpenColumn);
var element = b.element(name, attributes, modifiers, [], comments, loc);
this.elementStack.push(element);
};
TokenizerEventHandlers.prototype.finishEndTag = function finishEndTag(isVoid) {
var tag = this.currentTag;
var element = this.elementStack.pop();
var parent = this.currentElement();
validateEndTag(tag, element, isVoid);
element.loc.end.line = this.tokenizer.line;
element.loc.end.column = this.tokenizer.column;
parseElementBlockParams(element);
appendChild(parent, element);
};
TokenizerEventHandlers.prototype.markTagAsSelfClosing = function markTagAsSelfClosing() {
this.currentTag.selfClosing = true;
};
// Tags - name
TokenizerEventHandlers.prototype.appendToTagName = function appendToTagName(char) {
this.currentTag.name += char;
};
// Tags - attributes
TokenizerEventHandlers.prototype.beginAttribute = function beginAttribute() {
var tag = this.currentTag;
if (tag.type === 'EndTag') {
throw new SyntaxError("Invalid end tag: closing tag must not have attributes, " + ("in `" + tag.name + "` (on line " + this.tokenizer.line + ")."), tag.loc);
}
this.currentAttribute = {
name: "",
parts: [],
isQuoted: false,
isDynamic: false,
start: b.pos(this.tokenizer.line, this.tokenizer.column),
valueStartLine: 0,
valueStartColumn: 0
};
};
TokenizerEventHandlers.prototype.appendToAttributeName = function appendToAttributeName(char) {
this.currentAttr.name += char;
};
TokenizerEventHandlers.prototype.beginAttributeValue = function beginAttributeValue(isQuoted) {
this.currentAttr.isQuoted = isQuoted;
this.currentAttr.valueStartLine = this.tokenizer.line;
this.currentAttr.valueStartColumn = this.tokenizer.column;
};
TokenizerEventHandlers.prototype.appendToAttributeValue = function appendToAttributeValue(char) {
var parts = this.currentAttr.parts;
var lastPart = parts[parts.length - 1];
if (lastPart && lastPart.type === 'TextNode') {
lastPart.chars += char;
// update end location for each added char
lastPart.loc.end.line = this.tokenizer.line;
lastPart.loc.end.column = this.tokenizer.column;
} else {
// initially assume the text node is a single char
var loc = b.loc(this.tokenizer.line, this.tokenizer.column, this.tokenizer.line, this.tokenizer.column);
// correct for `\n` as first char
if (char === '\n') {
loc.start.line -= 1;
loc.start.column = lastPart ? lastPart.loc.end.column : this.currentAttr.valueStartColumn;
}
var text = b.text(char, loc);
parts.push(text);
}
};
TokenizerEventHandlers.prototype.finishAttributeValue = function finishAttributeValue() {
var _currentAttr = this.currentAttr,
name = _currentAttr.name,
parts = _currentAttr.parts,
isQuoted = _currentAttr.isQuoted,
isDynamic = _currentAttr.isDynamic,
valueStartLine = _currentAttr.valueStartLine,
valueStartColumn = _currentAttr.valueStartColumn;
var value = assembleAttributeValue(parts, isQuoted, isDynamic, this.tokenizer.line);
value.loc = b.loc(valueStartLine, valueStartColumn, this.tokenizer.line, this.tokenizer.column);
var loc = b.loc(this.currentAttr.start.line, this.currentAttr.start.column, this.token