power-assert-formatter
Version:
Power Assert output formatter
1,461 lines (1,274 loc) • 315 kB
JavaScript
/**
* Modules in this bundle
*
* acorn:
* license: MIT
* maintainers: marijn <marijnh@gmail.com>
* contributors: List of Acorn contributors. Updated before every release., Adrian Rakovsky, Alistair Braidwood, Andres Suarez, Aparajita Fishman, Arian Stolwijk, Artem Govorov, Brandon Mills, Charles Hughes, Conrad Irwin, David Bonnet, Forbes Lindesay, Gilad Peleg, impinball, Ingvar Stepanyan, Jiaxing Wang, Johannes Herr, Jürg Lehni, keeyipchan, krator, Marijn Haverbeke, Martin Carlberg, Mathias Bynens, Mathieu 'p01' Henri, Max Schaefer, Max Zerzouri, Mihai Bazon, Mike Rennie, Nick Fitzgerald, Oskar Schöldström, Paul Harper, Peter Rust, PlNG, r-e-d, Rich Harris, Sebastian McKenzie, zsjforcn
*
* array-filter:
* license: MIT
* author: Julian Gruber <mail@juliangruber.com>
* maintainers: juliangruber <julian@juliangruber.com>
*
* array-foreach:
* license: MIT
* author: Takuto Wada <takuto.wada@gmail.com>
*
* array-map:
* license: MIT
* author: James Halliday <mail@substack.net>
* maintainers: substack <mail@substack.net>
*
* array-reduce:
* license: MIT
* author: James Halliday <mail@substack.net>
* maintainers: substack <mail@substack.net>
*
* array-reduce-right:
* license: MIT
* author: Takuto Wada <takuto.wada@gmail.com>
*
* eastasianwidth:
* license: MIT
* author: Masaki Komagata
* maintainers: komagata <komagata@gmail.com>
*
* estraverse:
* licenses: BSD
* maintainers: constellation <utatane.tea@gmail.com>, michaelficarra <npm@michael.ficarra.me>
*
* events:
* author: Irakli Gozalishvili <rfobic@gmail.com>
* maintainers: gozala <rfobic@gmail.com>, shtylman <shtylman@gmail.com>
*
* googlediff:
* licenses: Apache
* author: Neil Fraser <root@neil.fraser.name>
* maintainers: shimondoodkin <helpmepro1@gmail.com>
* contributors: Shimon Doodkin <helpmepro1@gmail.com>, Ryan Graham <r.m.graham@gmail.com>
*
* indexof:
* maintainers: tjholowaychuk <tj@vision-media.ca>
*
* inherits:
* license: ISC
*
* object-keys:
* license: MIT
* author: Jordan Harband
* maintainers: ljharb <ljharb@gmail.com>
*
* power-assert-formatter:
* license: MIT
* author: Takuto Wada <takuto.wada@gmail.com>
*
* process:
* author: Roman Shtylman <shtylman@gmail.com>
* maintainers: coolaj86 <coolaj86@gmail.com>, defunctzombie <shtylman@gmail.com>
*
* stringifier:
* license: MIT
* author: Takuto Wada <takuto.wada@gmail.com>
*
* traverse:
* license: MIT
* author: James Halliday <mail@substack.net>
* maintainers: substack <mail@substack.net>
*
* type-name:
* license: MIT
* author: Takuto Wada <takuto.wada@gmail.com>
* maintainers: twada <takuto.wada@gmail.com>
* contributors: azu, Yosuke Furukawa
*
* util:
* license: MIT
* author: Joyent
* maintainers: shtylman <shtylman@gmail.com>
*
* xtend:
* licenses: MIT
* author: Raynos <raynos2@gmail.com>
* contributors: Jake Verbaten, Matt Esch
*
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.powerAssertFormatter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw (f.code="MODULE_NOT_FOUND", f)}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
/**
* power-assert-formatter.js - Power Assert output formatter
*
* https://github.com/power-assert-js/power-assert-formatter
*
* Copyright (c) 2013-2015 Takuto Wada
* Licensed under the MIT license.
* https://github.com/power-assert-js/power-assert-formatter/blob/master/MIT-LICENSE.txt
*/
'use strict';
module.exports = _dereq_('./lib/create');
},{"./lib/create":6}],2:[function(_dereq_,module,exports){
'use strict';
function AssertionRenderer (traversal, config) {
var assertionLine;
traversal.on('start', function (context) {
assertionLine = context.source.content;
});
traversal.on('render', function (writer) {
writer.write('');
writer.write(assertionLine);
});
}
module.exports = AssertionRenderer;
},{}],3:[function(_dereq_,module,exports){
'use strict';
var typeName = _dereq_('type-name');
var keys = Object.keys || _dereq_('object-keys');
var syntax = _dereq_('estraverse').Syntax;
var forEach = _dereq_('array-foreach');
function BinaryExpressionRenderer(traversal, config) {
this.config = config;
this.stringify = config.stringify;
this.diff = config.diff;
this.espathToPair = {};
var _this = this;
traversal.on('esnode', function (esNode) {
var pair;
if (!esNode.isCaptured()) {
if (isTargetBinaryExpression(esNode.getParent()) && esNode.currentNode.type === syntax.Literal) {
_this.espathToPair[esNode.parentEspath][esNode.currentProp] = {code: esNode.code(), value: esNode.value()};
}
return;
}
if (isTargetBinaryExpression(esNode.getParent())) {
_this.espathToPair[esNode.parentEspath][esNode.currentProp] = {code: esNode.code(), value: esNode.value()};
}
if (isTargetBinaryExpression(esNode)) {
pair = {
operator: esNode.currentNode.operator,
value: esNode.value()
};
_this.espathToPair[esNode.espath] = pair;
}
});
traversal.on('render', function (writer) {
var pairs = [];
forEach(keys(_this.espathToPair), function (espath) {
var pair = _this.espathToPair[espath];
if (pair.left && pair.right) {
pairs.push(pair);
}
});
forEach(pairs, function (pair) {
_this.compare(pair, writer);
});
});
}
BinaryExpressionRenderer.prototype.compare = function (pair, writer) {
if (isStringDiffTarget(pair)) {
this.showStringDiff(pair, writer);
} else {
this.showExpectedAndActual(pair, writer);
}
};
BinaryExpressionRenderer.prototype.showExpectedAndActual = function (pair, writer) {
writer.write('');
writer.write('[' + typeName(pair.right.value) + '] ' + pair.right.code);
writer.write('=> ' + this.stringify(pair.right.value));
writer.write('[' + typeName(pair.left.value) + '] ' + pair.left.code);
writer.write('=> ' + this.stringify(pair.left.value));
};
BinaryExpressionRenderer.prototype.showStringDiff = function (pair, writer) {
writer.write('');
writer.write('--- [string] ' + pair.right.code);
writer.write('+++ [string] ' + pair.left.code);
writer.write(this.diff(pair.right.value, pair.left.value, this.config));
};
function isTargetBinaryExpression (esNode) {
return esNode &&
esNode.currentNode.type === syntax.BinaryExpression &&
(esNode.currentNode.operator === '===' || esNode.currentNode.operator === '==') &&
esNode.isCaptured() &&
!(esNode.value());
}
function isStringDiffTarget(pair) {
return typeof pair.left.value === 'string' && typeof pair.right.value === 'string';
}
module.exports = BinaryExpressionRenderer;
},{"array-foreach":15,"estraverse":24,"object-keys":28,"type-name":36}],4:[function(_dereq_,module,exports){
'use strict';
var forEach = _dereq_('array-foreach');
function DiagramRenderer (traversal, config) {
this.config = config;
this.events = [];
this.stringify = config.stringify;
this.widthOf = config.widthOf;
this.initialVertivalBarLength = 1;
var _this = this;
traversal.on('start', function (context) {
_this.context = context;
_this.assertionLine = context.source.content;
_this.initializeRows();
});
traversal.on('esnode', function (esNode) {
if (!esNode.isCaptured()) {
return;
}
_this.events.push({value: esNode.value(), loc: esNode.location()});
});
traversal.on('render', function (writer) {
_this.events.sort(rightToLeft);
_this.constructRows(_this.events);
forEach(_this.rows, function (columns) {
writer.write(columns.join(''));
});
});
}
DiagramRenderer.prototype.initializeRows = function () {
this.rows = [];
for (var i = 0; i <= this.initialVertivalBarLength; i += 1) {
this.addOneMoreRow();
}
};
DiagramRenderer.prototype.newRowFor = function (assertionLine) {
return createRow(this.widthOf(assertionLine), ' ');
};
DiagramRenderer.prototype.addOneMoreRow = function () {
this.rows.push(this.newRowFor(this.assertionLine));
};
DiagramRenderer.prototype.lastRow = function () {
return this.rows[this.rows.length - 1];
};
DiagramRenderer.prototype.renderVerticalBarAt = function (columnIndex) {
var i, lastRowIndex = this.rows.length - 1;
for (i = 0; i < lastRowIndex; i += 1) {
this.rows[i].splice(columnIndex, 1, '|');
}
};
DiagramRenderer.prototype.renderValueAt = function (columnIndex, dumpedValue) {
var i, width = this.widthOf(dumpedValue);
for (i = 0; i < width; i += 1) {
this.lastRow().splice(columnIndex + i, 1, dumpedValue.charAt(i));
}
};
DiagramRenderer.prototype.isOverlapped = function (prevCapturing, nextCaputuring, dumpedValue) {
return (typeof prevCapturing !== 'undefined') && this.startColumnFor(prevCapturing) <= (this.startColumnFor(nextCaputuring) + this.widthOf(dumpedValue));
};
DiagramRenderer.prototype.constructRows = function (capturedEvents) {
var that = this;
var prevCaptured;
forEach(capturedEvents, function (captured) {
var dumpedValue = that.stringify(captured.value);
if (that.isOverlapped(prevCaptured, captured, dumpedValue)) {
that.addOneMoreRow();
}
that.renderVerticalBarAt(that.startColumnFor(captured));
that.renderValueAt(that.startColumnFor(captured), dumpedValue);
prevCaptured = captured;
});
};
DiagramRenderer.prototype.startColumnFor = function (captured) {
return this.widthOf(this.assertionLine.slice(0, captured.loc.start.column));
};
function createRow (numCols, initial) {
var row = [], i;
for(i = 0; i < numCols; i += 1) {
row[i] = initial;
}
return row;
}
function rightToLeft (a, b) {
return b.loc.start.column - a.loc.start.column;
}
module.exports = DiagramRenderer;
},{"array-foreach":15}],5:[function(_dereq_,module,exports){
'use strict';
function FileRenderer (traversal, config) {
var filepath, lineNumber;
traversal.on('start', function (context) {
filepath = context.source.filepath;
lineNumber = context.source.line;
});
traversal.on('render', function (writer) {
if (filepath) {
writer.write('# ' + [filepath, lineNumber].join(':'));
} else {
writer.write('# at line: ' + lineNumber);
}
});
}
module.exports = FileRenderer;
},{}],6:[function(_dereq_,module,exports){
'use strict';
var stringifier = _dereq_('stringifier');
var stringWidth = _dereq_('./string-width');
var StringWriter = _dereq_('./string-writer');
var ContextTraversal = _dereq_('./traverse');
var udiff = _dereq_('./udiff');
var defaultOptions = _dereq_('./default-options');
var typeName = _dereq_('type-name');
var extend = _dereq_('xtend');
var map = _dereq_('array-map');
// "Browserify can only analyze static requires. It is not in the scope of browserify to handle dynamic requires."
// https://github.com/substack/node-browserify/issues/377
var defaultRendererClasses = {
'./built-in/file': _dereq_('./built-in/file'),
'./built-in/assertion': _dereq_('./built-in/assertion'),
'./built-in/diagram': _dereq_('./built-in/diagram'),
'./built-in/binary-expression': _dereq_('./built-in/binary-expression')
};
function findRendererClass (rendererName, config) {
var RendererClass;
if (typeName(rendererName) === 'function') {
RendererClass = rendererName;
} else if (typeName(rendererName) === 'string') {
if (defaultRendererClasses[rendererName]) {
RendererClass = defaultRendererClasses[rendererName];
} else {
RendererClass = _dereq_(rendererName);
}
}
return RendererClass;
}
function configure (options) {
var config = extend(defaultOptions(), options);
if (typeof config.widthOf !== 'function') {
config.widthOf = stringWidth(extend(config));
}
if (typeof config.stringify !== 'function') {
config.stringify = stringifier(extend(config));
}
if (typeof config.diff !== 'function') {
config.diff = udiff(extend(config));
}
if (!config.writerClass) {
config.writerClass = StringWriter;
}
return config;
}
function create (options) {
var config = configure(options);
var rendererClasses = map(config.renderers, function (rendererName) {
return findRendererClass(rendererName, config);
});
return function (context) {
var traversal = new ContextTraversal(context);
var writer = new config.writerClass(extend(config));
var renderers = map(rendererClasses, function (RendererClass) {
return new RendererClass(traversal, extend(config));
});
traversal.emit('start', context);
traversal.traverse();
traversal.emit('render', writer);
writer.write('');
renderers.length = 0;
return writer.flush();
};
}
create.defaultOptions = defaultOptions;
create.stringWidth = stringWidth;
module.exports = create;
},{"./built-in/assertion":2,"./built-in/binary-expression":3,"./built-in/diagram":4,"./built-in/file":5,"./default-options":7,"./string-width":10,"./string-writer":11,"./traverse":12,"./udiff":13,"array-map":16,"stringifier":30,"type-name":36,"xtend":37}],7:[function(_dereq_,module,exports){
module.exports = function defaultOptions () {
'use strict';
return {
lineDiffThreshold: 5,
maxDepth: 1,
outputOffset: 2,
anonymous: 'Object',
circular: '#@Circular#',
lineSeparator: '\n',
ambiguousEastAsianCharWidth: 2,
renderers: [
'./built-in/file',
'./built-in/assertion',
'./built-in/diagram',
'./built-in/binary-expression'
]
};
};
},{}],8:[function(_dereq_,module,exports){
'use strict';
var syntax = _dereq_('estraverse').Syntax;
var locationOf = _dereq_('./location');
function EsNode (path, currentNode, parentNode, espathToValue, jsCode, tokens) {
if (path) {
this.espath = path.join('/');
this.parentEspath = path.slice(0, path.length - 1).join('/');
this.currentProp = path[path.length - 1];
} else {
this.espath = '';
this.parentEspath = '';
this.currentProp = null;
}
this.currentNode = currentNode;
this.parentNode = parentNode;
this.parentEsNode = null;
this.espathToValue = espathToValue;
this.jsCode = jsCode;
this.tokens = tokens;
}
EsNode.prototype.setParent = function (parentEsNode) {
this.parentEsNode = parentEsNode;
};
EsNode.prototype.getParent = function () {
return this.parentEsNode;
};
EsNode.prototype.code = function () {
return this.jsCode.slice(this.currentNode.loc.start.column, this.currentNode.loc.end.column);
};
EsNode.prototype.value = function () {
if (this.currentNode.type === syntax.Literal) {
return this.currentNode.value;
}
return this.espathToValue[this.espath];
};
EsNode.prototype.isCaptured = function () {
return this.espathToValue.hasOwnProperty(this.espath);
};
EsNode.prototype.location = function () {
return locationOf(this.currentNode, this.tokens);
};
module.exports = EsNode;
},{"./location":9,"estraverse":24}],9:[function(_dereq_,module,exports){
'use strict';
var syntax = _dereq_('estraverse').Syntax;
function locationOf(currentNode, tokens) {
switch(currentNode.type) {
case syntax.MemberExpression:
return propertyLocationOf(currentNode, tokens);
case syntax.CallExpression:
if (currentNode.callee.type === syntax.MemberExpression) {
return propertyLocationOf(currentNode.callee, tokens);
}
break;
case syntax.BinaryExpression:
case syntax.LogicalExpression:
case syntax.AssignmentExpression:
return infixOperatorLocationOf(currentNode, tokens);
default:
break;
}
return currentNode.loc;
}
function propertyLocationOf(memberExpression, tokens) {
var prop = memberExpression.property;
var token;
if (!memberExpression.computed) {
return prop.loc;
}
token = findLeftBracketTokenOf(memberExpression, tokens);
return token ? token.loc : prop.loc;
}
// calculate location of infix operator for BinaryExpression, AssignmentExpression and LogicalExpression.
function infixOperatorLocationOf (expression, tokens) {
var token = findOperatorTokenOf(expression, tokens);
return token ? token.loc : expression.left.loc;
}
function findLeftBracketTokenOf(expression, tokens) {
var fromLine = expression.loc.start.line;
var toLine = expression.property.loc.start.line;
var fromColumn = expression.property.loc.start.column;
return searchToken(tokens, fromLine, toLine, function (token, index) {
var prevToken;
if (token.loc.start.column === fromColumn) {
prevToken = tokens[index - 1];
// if (prevToken.type === 'Punctuator' && prevToken.value === '[') { // esprima
if (prevToken.type.label === '[') { // acorn
return prevToken;
}
}
return undefined;
});
}
function findOperatorTokenOf(expression, tokens) {
var fromLine = expression.left.loc.end.line;
var toLine = expression.right.loc.start.line;
var fromColumn = expression.left.loc.end.column;
var toColumn = expression.right.loc.start.column;
return searchToken(tokens, fromLine, toLine, function (token, index) {
if (fromColumn < token.loc.start.column &&
token.loc.end.column < toColumn &&
// token.type === 'Punctuator' && // esprima
token.value === expression.operator) {
return token;
}
return undefined;
});
}
function searchToken(tokens, fromLine, toLine, predicate) {
var i, token, found;
for(i = 0; i < tokens.length; i += 1) {
token = tokens[i];
if (token.loc.start.line < fromLine) {
continue;
}
if (toLine < token.loc.end.line) {
break;
}
found = predicate(token, i);
if (found) {
return found;
}
}
return undefined;
}
module.exports = locationOf;
},{"estraverse":24}],10:[function(_dereq_,module,exports){
'use strict';
var eaw = _dereq_('eastasianwidth');
function stringWidth (config) {
var ambiguousCharWidth = (config && config.ambiguousEastAsianCharWidth) || 1;
return function widthOf (str) {
var i, code, width = 0;
for(i = 0; i < str.length; i+=1) {
code = eaw.eastAsianWidth(str.charAt(i));
switch(code) {
case 'F':
case 'W':
width += 2;
break;
case 'H':
case 'Na':
case 'N':
width += 1;
break;
case 'A':
width += ambiguousCharWidth;
break;
}
}
return width;
};
}
module.exports = stringWidth;
},{"eastasianwidth":23}],11:[function(_dereq_,module,exports){
'use strict';
function spacerStr (len) {
var str = '';
for(var i = 0; i < len; i += 1) {
str += ' ';
}
return str;
}
function StringWriter (config) {
this.lines = [];
this.lineSeparator = config.lineSeparator;
this.regex = new RegExp(this.lineSeparator, 'g');
this.spacer = spacerStr(config.outputOffset);
}
StringWriter.prototype.write = function (str) {
this.lines.push(this.spacer + str.replace(this.regex, this.lineSeparator + this.spacer));
};
StringWriter.prototype.flush = function () {
var str = this.lines.join(this.lineSeparator);
this.lines.length = 0;
return str;
};
module.exports = StringWriter;
},{}],12:[function(_dereq_,module,exports){
'use strict';
var estraverse = _dereq_('estraverse');
var acorn = _dereq_('acorn');
var EventEmitter = _dereq_('events').EventEmitter;
var inherits = _dereq_('util').inherits;
var EsNode = _dereq_('./esnode');
var forEach = _dereq_('array-foreach');
var reduce = _dereq_('array-reduce');
function ContextTraversal (context) {
this.context = context;
EventEmitter.call(this);
}
inherits(ContextTraversal, EventEmitter);
ContextTraversal.prototype.traverse = function () {
var _this = this;
forEach(this.context.args, function (arg) {
onEachEsNode(arg, _this.context.source.content, function (esNode) {
_this.emit('esnode', esNode);
});
});
};
function onEachEsNode(arg, jsCode, callback) {
var tokens = [];
var jsAST = acorn.parse(jsCode, {ecmaVersion: 6, locations: true, onToken: tokens});
var espathToValue = reduce(arg.events, function (accum, ev) {
accum[ev.espath] = ev.value;
return accum;
}, {});
var nodeStack = [];
estraverse.traverse(extractExpressionFrom(jsAST), {
enter: function (currentNode, parentNode) {
var esNode = new EsNode(this.path(), currentNode, parentNode, espathToValue, jsCode, tokens);
if (1 < nodeStack.length) {
esNode.setParent(nodeStack[nodeStack.length - 1]);
}
nodeStack.push(esNode);
callback(esNode);
},
leave: function (currentNode, parentNode) {
nodeStack.pop();
}
});
}
function extractExpressionFrom (tree) {
var expressionStatement = tree.body[0];
var expression = expressionStatement.expression;
return expression;
}
module.exports = ContextTraversal;
},{"./esnode":8,"acorn":14,"array-foreach":15,"array-reduce":17,"estraverse":24,"events":18,"util":22}],13:[function(_dereq_,module,exports){
'use strict';
var DiffMatchPatch = _dereq_('googlediff');
var dmp = new DiffMatchPatch();
function udiff (config) {
return function diff (text1, text2) {
var patch;
if (config && shouldUseLineLevelDiff(text1, config)) {
patch = udiffLines(text1, text2);
} else {
patch = udiffChars(text1, text2);
}
return decodeURIComponent(patch);
};
}
function shouldUseLineLevelDiff (text, config) {
return config.lineDiffThreshold < text.split(/\r\n|\r|\n/).length;
}
function udiffLines(text1, text2) {
/*jshint camelcase: false */
var a = dmp.diff_linesToChars_(text1, text2);
var diffs = dmp.diff_main(a.chars1, a.chars2, false);
dmp.diff_charsToLines_(diffs, a.lineArray);
dmp.diff_cleanupSemantic(diffs);
return dmp.patch_toText(dmp.patch_make(text1, diffs));
}
function udiffChars (text1, text2) {
/*jshint camelcase: false */
var diffs = dmp.diff_main(text1, text2, false);
dmp.diff_cleanupSemantic(diffs);
return dmp.patch_toText(dmp.patch_make(text1, diffs));
}
module.exports = udiff;
},{"googlediff":26}],14:[function(_dereq_,module,exports){
(function (global){
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.acorn = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof _dereq_=="function"&&_dereq_;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw (f.code="MODULE_NOT_FOUND", f)}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof _dereq_=="function"&&_dereq_;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
// The main exported interface (under `self.acorn` when in the
// browser) is a `parse` function that takes a code string and
// returns an abstract syntax tree as specified by [Mozilla parser
// API][api].
//
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
"use strict";
exports.parse = parse;
// This function tries to parse a single expression at a given
// offset in a string. Useful for parsing mixed-language formats
// that embed JavaScript expressions.
exports.parseExpressionAt = parseExpressionAt;
// Acorn is organized as a tokenizer and a recursive-descent parser.
// The `tokenize` export provides an interface to the tokenizer.
exports.tokenizer = tokenizer;
exports.__esModule = true;
// Acorn is a tiny, fast JavaScript parser written in JavaScript.
//
// Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and
// various contributors and released under an MIT license.
//
// Git repositories for Acorn are available at
//
// http://marijnhaverbeke.nl/git/acorn
// https://github.com/marijnh/acorn.git
//
// Please use the [github bug tracker][ghbt] to report issues.
//
// [ghbt]: https://github.com/marijnh/acorn/issues
//
// This file defines the main parser interface. The library also comes
// with a [error-tolerant parser][dammit] and an
// [abstract syntax tree walker][walk], defined in other files.
//
// [dammit]: acorn_loose.js
// [walk]: util/walk.js
var _state = _dereq_("./state");
var Parser = _state.Parser;
var _options = _dereq_("./options");
var getOptions = _options.getOptions;
_dereq_("./parseutil");
_dereq_("./statement");
_dereq_("./lval");
_dereq_("./expression");
exports.Parser = _state.Parser;
exports.plugins = _state.plugins;
exports.defaultOptions = _options.defaultOptions;
var _location = _dereq_("./location");
exports.SourceLocation = _location.SourceLocation;
exports.getLineInfo = _location.getLineInfo;
exports.Node = _dereq_("./node").Node;
var _tokentype = _dereq_("./tokentype");
exports.TokenType = _tokentype.TokenType;
exports.tokTypes = _tokentype.types;
var _tokencontext = _dereq_("./tokencontext");
exports.TokContext = _tokencontext.TokContext;
exports.tokContexts = _tokencontext.types;
var _identifier = _dereq_("./identifier");
exports.isIdentifierChar = _identifier.isIdentifierChar;
exports.isIdentifierStart = _identifier.isIdentifierStart;
exports.Token = _dereq_("./tokenize").Token;
var _whitespace = _dereq_("./whitespace");
exports.isNewLine = _whitespace.isNewLine;
exports.lineBreak = _whitespace.lineBreak;
exports.lineBreakG = _whitespace.lineBreakG;
var version = "2.0.4";exports.version = version;
function parse(input, options) {
var p = parser(options, input);
var startPos = p.pos,
startLoc = p.options.locations && p.curPosition();
p.nextToken();
return p.parseTopLevel(p.options.program || p.startNodeAt(startPos, startLoc));
}
function parseExpressionAt(input, pos, options) {
var p = parser(options, input, pos);
p.nextToken();
return p.parseExpression();
}
function tokenizer(input, options) {
return parser(options, input);
}
function parser(options, input) {
return new Parser(getOptions(options), String(input));
}
},{"./expression":2,"./identifier":3,"./location":4,"./lval":5,"./node":6,"./options":7,"./parseutil":8,"./state":9,"./statement":10,"./tokencontext":11,"./tokenize":12,"./tokentype":13,"./whitespace":15}],2:[function(_dereq_,module,exports){
// A recursive descent parser operates by defining functions for all
// syntactic elements, and recursively calling those, each function
// advancing the input stream and returning an AST node. Precedence
// of constructs (for example, the fact that `!x[1]` means `!(x[1])`
// instead of `(!x)[1]` is handled by the fact that the parser
// function that parses unary prefix operators is called first, and
// in turn calls the function that parses `[]` subscripts — that
// way, it'll receive the node for `x[1]` already parsed, and wraps
// *that* in the unary operator node.
//
// Acorn uses an [operator precedence parser][opp] to handle binary
// operator precedence, because it is much more compact than using
// the technique outlined above, which uses different, nesting
// functions to specify precedence, for all of the ten binary
// precedence levels that JavaScript defines.
//
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
"use strict";
var tt = _dereq_("./tokentype").types;
var Parser = _dereq_("./state").Parser;
var reservedWords = _dereq_("./identifier").reservedWords;
var has = _dereq_("./util").has;
var pp = Parser.prototype;
// Check if property name clashes with already added.
// Object/class getters and setters are not allowed to clash —
// either with each other or with an init property — and in
// strict mode, init properties are also not allowed to be repeated.
pp.checkPropClash = function (prop, propHash) {
if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand)) return;
var key = prop.key,
name = undefined;
switch (key.type) {
case "Identifier":
name = key.name;break;
case "Literal":
name = String(key.value);break;
default:
return;
}
var kind = prop.kind;
if (this.options.ecmaVersion >= 6) {
if (name === "__proto__" && kind === "init") {
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
propHash.proto = true;
}
return;
}
var other = undefined;
if (has(propHash, name)) {
other = propHash[name];
var isGetSet = kind !== "init";
if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) this.raise(key.start, "Redefinition of property");
} else {
other = propHash[name] = {
init: false,
get: false,
set: false
};
}
other[kind] = true;
};
// ### Expression parsing
// These nest, from the most general expression type at the top to
// 'atomic', nondivisible expression types at the bottom. Most of
// the functions will simply let the function(s) below them parse,
// and, *if* the syntactic construct they handle is present, wrap
// the AST node that the inner parser gave them in another node.
// Parse a full expression. The optional arguments are used to
// forbid the `in` operator (in for loops initalization expressions)
// and provide reference for storing '=' operator inside shorthand
// property assignment in contexts where both object expression
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).
pp.parseExpression = function (noIn, refShorthandDefaultPos) {
var startPos = this.start,
startLoc = this.startLoc;
var expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);
if (this.type === tt.comma) {
var node = this.startNodeAt(startPos, startLoc);
node.expressions = [expr];
while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos));
return this.finishNode(node, "SequenceExpression");
}
return expr;
};
// Parse an assignment expression. This includes applications of
// operators like `+=`.
pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) {
if (this.type == tt._yield && this.inGenerator) return this.parseYield();
var failOnShorthandAssign = undefined;
if (!refShorthandDefaultPos) {
refShorthandDefaultPos = { start: 0 };
failOnShorthandAssign = true;
} else {
failOnShorthandAssign = false;
}
var startPos = this.start,
startLoc = this.startLoc;
if (this.type == tt.parenL || this.type == tt.name) this.potentialArrowAt = this.start;
var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos);
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc);
if (this.type.isAssign) {
var node = this.startNodeAt(startPos, startLoc);
node.operator = this.value;
node.left = this.type === tt.eq ? this.toAssignable(left) : left;
refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly
this.checkLVal(left);
this.next();
node.right = this.parseMaybeAssign(noIn);
return this.finishNode(node, "AssignmentExpression");
} else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
}
return left;
};
// Parse a ternary conditional (`?:`) operator.
pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) {
var startPos = this.start,
startLoc = this.startLoc;
var expr = this.parseExprOps(noIn, refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
if (this.eat(tt.question)) {
var node = this.startNodeAt(startPos, startLoc);
node.test = expr;
node.consequent = this.parseMaybeAssign();
this.expect(tt.colon);
node.alternate = this.parseMaybeAssign(noIn);
return this.finishNode(node, "ConditionalExpression");
}
return expr;
};
// Start the precedence parser.
pp.parseExprOps = function (noIn, refShorthandDefaultPos) {
var startPos = this.start,
startLoc = this.startLoc;
var expr = this.parseMaybeUnary(refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
return this.parseExprOp(expr, startPos, startLoc, -1, noIn);
};
// Parse binary operators with the operator precedence parsing
// algorithm. `left` is the left-hand side of the operator.
// `minPrec` provides context that allows the function to stop and
// defer further parser to one of its callers when it encounters an
// operator that has a lower precedence than the set it is parsing.
pp.parseExprOp = function (left, leftStartPos, leftStartLoc, minPrec, noIn) {
var prec = this.type.binop;
if (prec != null && (!noIn || this.type !== tt._in)) {
if (prec > minPrec) {
var node = this.startNodeAt(leftStartPos, leftStartLoc);
node.left = left;
node.operator = this.value;
var op = this.type;
this.next();
var startPos = this.start,
startLoc = this.startLoc;
node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn);
this.finishNode(node, op === tt.logicalOR || op === tt.logicalAND ? "LogicalExpression" : "BinaryExpression");
return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn);
}
}
return left;
};
// Parse unary operators, both prefix and postfix.
pp.parseMaybeUnary = function (refShorthandDefaultPos) {
if (this.type.prefix) {
var node = this.startNode(),
update = this.type === tt.incDec;
node.operator = this.value;
node.prefix = true;
this.next();
node.argument = this.parseMaybeUnary();
if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
if (update) this.checkLVal(node.argument);else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") this.raise(node.start, "Deleting local variable in strict mode");
return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
}
var startPos = this.start,
startLoc = this.startLoc;
var expr = this.parseExprSubscripts(refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
while (this.type.postfix && !this.canInsertSemicolon()) {
var node = this.startNodeAt(startPos, startLoc);
node.operator = this.value;
node.prefix = false;
node.argument = expr;
this.checkLVal(expr);
this.next();
expr = this.finishNode(node, "UpdateExpression");
}
return expr;
};
// Parse call, dot, and `[]`-subscript expressions.
pp.parseExprSubscripts = function (refShorthandDefaultPos) {
var startPos = this.start,
startLoc = this.startLoc;
var expr = this.parseExprAtom(refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
return this.parseSubscripts(expr, startPos, startLoc);
};
pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
for (;;) {
if (this.eat(tt.dot)) {
var node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.parseIdent(true);
node.computed = false;
base = this.finishNode(node, "MemberExpression");
} else if (this.eat(tt.bracketL)) {
var node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.parseExpression();
node.computed = true;
this.expect(tt.bracketR);
base = this.finishNode(node, "MemberExpression");
} else if (!noCalls && this.eat(tt.parenL)) {
var node = this.startNodeAt(startPos, startLoc);
node.callee = base;
node.arguments = this.parseExprList(tt.parenR, false);
base = this.finishNode(node, "CallExpression");
} else if (this.type === tt.backQuote) {
var node = this.startNodeAt(startPos, startLoc);
node.tag = base;
node.quasi = this.parseTemplate();
base = this.finishNode(node, "TaggedTemplateExpression");
} else {
return base;
}
}
};
// Parse an atomic expression — either a single token that is an
// expression, an expression started by a keyword like `function` or
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
pp.parseExprAtom = function (refShorthandDefaultPos) {
var node = undefined,
canBeArrow = this.potentialArrowAt == this.start;
switch (this.type) {
case tt._super:
if (!this.inFunction) this.raise(this.start, "'super' outside of function or class");
case tt._this:
var type = this.type === tt._this ? "ThisExpression" : "Super";
node = this.startNode();
this.next();
return this.finishNode(node, type);
case tt._yield:
if (this.inGenerator) this.unexpected();
case tt.name:
var startPos = this.start,
startLoc = this.startLoc;
var id = this.parseIdent(this.type !== tt.name);
if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]);
return id;
case tt.regexp:
var value = this.value;
node = this.parseLiteral(value.value);
node.regex = { pattern: value.pattern, flags: value.flags };
return node;
case tt.num:case tt.string:
return this.parseLiteral(this.value);
case tt._null:case tt._true:case tt._false:
node = this.startNode();
node.value = this.type === tt._null ? null : this.type === tt._true;
node.raw = this.type.keyword;
this.next();
return this.finishNode(node, "Literal");
case tt.parenL:
return this.parseParenAndDistinguishExpression(canBeArrow);
case tt.bracketL:
node = this.startNode();
this.next();
// check whether this is array comprehension or regular array
if (this.options.ecmaVersion >= 7 && this.type === tt._for) {
return this.parseComprehension(node, false);
}
node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos);
return this.finishNode(node, "ArrayExpression");
case tt.braceL:
return this.parseObj(false, refShorthandDefaultPos);
case tt._function:
node = this.startNode();
this.next();
return this.parseFunction(node, false);
case tt._class:
return this.parseClass(this.startNode(), false);
case tt._new:
return this.parseNew();
case tt.backQuote:
return this.parseTemplate();
default:
this.unexpected();
}
};
pp.parseLiteral = function (value) {
var node = this.startNode();
node.value = value;
node.raw = this.input.slice(this.start, this.end);
this.next();
return this.finishNode(node, "Literal");
};
pp.parseParenExpression = function () {
this.expect(tt.parenL);
var val = this.parseExpression();
this.expect(tt.parenR);
return val;
};
pp.parseParenAndDistinguishExpression = function (canBeArrow) {
var startPos = this.start,
startLoc = this.startLoc,
val = undefined;
if (this.options.ecmaVersion >= 6) {
this.next();
if (this.options.ecmaVersion >= 7 && this.type === tt._for) {
return this.parseComprehension(this.startNodeAt(startPos, startLoc), true);
}
var innerStartPos = this.start,
innerStartLoc = this.startLoc;
var exprList = [],
first = true;
var refShorthandDefaultPos = { start: 0 },
spreadStart = undefined,
innerParenStart = undefined;
while (this.type !== tt.parenR) {
first ? first = false : this.expect(tt.comma);
if (this.type === tt.ellipsis) {
spreadStart = this.start;
exprList.push(this.parseParenItem(this.parseRest()));
break;
} else {
if (this.type === tt.parenL && !innerParenStart) {
innerParenStart = this.start;
}
exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem));
}
}
var innerEndPos = this.start,
innerEndLoc = this.startLoc;
this.expect(tt.parenR);
if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
if (innerParenStart) this.unexpected(innerParenStart);
return this.parseParenArrowList(startPos, startLoc, exprList);
}
if (!exprList.length) this.unexpected(this.lastTokStart);
if (spreadStart) this.unexpected(spreadStart);
if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
if (exprList.length > 1) {
val = this.startNodeAt(innerStartPos, innerStartLoc);
val.expressions = exprList;
this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc);
} else {
val = exprList[0];
}
} else {
val = this.parseParenExpression();
}
if (this.options.preserveParens) {
var par = this.startNodeAt(startPos, startLoc);
par.expression = val;
return this.finishNode(par, "ParenthesizedExpression");
} else {
return val;
}
};
pp.parseParenItem = function (item) {
return item;
};
pp.parseParenArrowList = function (startPos, startLoc, exprList) {
return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList);
};
// New's precedence is slightly tricky. It must allow its argument
// to be a `[]` or dot subscript expression, but not a call — at
// least, not without wrapping it in parentheses. Thus, it uses the
var empty = [];
pp.parseNew = function () {
var node = this.startNode();
var meta = this.parseIdent(true);
if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {
node.meta = meta;
node.property = this.parseIdent(true);
if (node.property.name !== "target") this.raise(node.property.start, "The only valid meta property for new is new.target");
return this.finishNode(node, "MetaProperty");
}
var startPos = this.start,
startLoc = this.startLoc;
node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true);
if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false);else node.arguments = empty;
return this.finishNode(node, "NewExpression");
};
// Parse template expression.
pp.parseTemplateElement = function () {
var elem = this.startNode();
elem.value = {
raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, "\n"),
cooked: this.value
};
this.next();
elem.tail = this.type === tt.backQuote;
return this.finishNode(elem, "TemplateElement");
};
pp.parseTemplate = function () {
var node = this.startNode();
this.next();
node.expressions = [];
var curElt = this.parseTemplateElement();
node.quasis = [curElt];
while (!curElt.tail) {
this.expect(tt.dollarBraceL);
node.expressions.push(this.parseExpression());
this.expect(tt.braceR);
node.quasis.push(curElt = this.parseTemplateElement());
}
this.next();
return this.finishNode(node, "TemplateLiteral");
};
// Parse an object literal or binding pattern.
pp.parseObj = function (isPattern, refShorthandDefaultPos) {
var node = this.startNode(),
first = true,
propHash = {};
node.properties = [];
this.next();
while (!this.eat(tt.braceR)) {
if (!first) {
this.expect(tt.comma);
if (this.afterTrailingComma(tt.braceR)) break;
} else first = false;
var prop = this.startNode(),
isGenerator = undefined,
startPos = undefined,
startLoc = undefined;
if (this.options.ecmaVersion >= 6) {
prop.method = false;
prop.shorthand = false;
if (isPattern || refShorthandDefaultPos) {
startPos = this.start;
startLoc = this.startLoc;
}
if (!isPattern) isGenerator = this.eat(tt.star);
}
this.parsePropertyName(prop);
this.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos);
this.checkPropClash(prop, propHash);
node.properties.push(this.finishNode(prop, "Property"));
}
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
};
pp.parsePropertyValue = function (prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos) {
if (this.eat(tt.colon)) {
prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos);
prop.kind = "init";
} else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {
if (isPattern) this.unexpected();
prop.kind = "init";
prop.method = true;
prop.value = this.parseMethod(isGenerator);
} else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type != tt.comma && this.type != tt.braceR)) {
if (isGenerator || isPattern) this.unexpected();
prop.kind = prop.key.name;
this.parsePropertyName(prop);
prop.value = this.parseMethod(false);
var paramCount = prop.kind === "get" ? 0 : 1;
if (prop.value.params.length !== paramCount) {
var start = prop.value.start;
if (prop.kind === "get") this.raise(start, "getter should have no params");else this.raise(start, "setter should have exactly one param");
}
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
prop.kind = "init";
if (isPattern) {
if (this.isKeyword(prop.key.name) || this.strict && (reservedWords.strictBind(prop.key.name) || reservedWords.strict(prop.key.name)) || !this.options.allowReserved && this.isReservedWord(prop.key.name)) this.raise(prop.key.start, "Binding " + prop.key.name);
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key);
} else if (this.type === tt.eq && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start) refShorthandDefaultPos.start = this.start;
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key);
} else {
prop.value = prop.key;
}
prop.shorthand = true;
} else this.unexpected();
};
pp.parsePropertyName = function (prop) {
if (this.options.ecmaVersion >= 6) {
if (this.eat(tt.bracketL)) {
prop.computed = true;
prop.key = this.parseMaybeAssign();
this.expect(tt.bracketR);
return prop.key;
} else {
prop.computed = false;
}
}
return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true);
};
// Initialize empty function node.
pp.initFunction = function (node) {
node.id = null;
if (this.options.ecmaVersion >= 6) {
node.generator = false;
node.expression = false;
}
};
// Parse object or class method.
pp.parseMethod = function (isGenerator) {
var node = this.startNode();
this.initFunction(node);
this.expect(tt.parenL);
node.params = this.parseBindingList(tt.parenR, false, false);
var allowExpressionBody = undefined;
if (this.options.ecmaVersion >= 6) {
node.generator = isGenerator;
}
this.parseFunctionBody(node, false);
return this.finishNode(node, "FunctionExpression");
};
// Parse arrow function expression with given parameters.
pp.parseArrowExpression = function (node, params) {
this.initFunction(node);
node.params = this.toAssignableList(params, true);
this.parseFunctionBody(node, true);
return this.finishNode(node, "ArrowFunctionExpression");
};
// Parse function body and check parameters.
pp.parseFunctionBody = function (node, allowExpression) {
var isExpression = allowExpression && this.type !== tt.braceL;
if (isExpression) {
node.body = this.parseMaybeAssign();
node.expression = true;
} else {
// Start a new scope with regard to labels and the `inFunction`
// flag (restore them to their old value afterwards).
var oldInFunc = this.inFunction,
oldInGen = this.inGenerator,
oldLabels = this.labels;
this.inFunction = true;this.inGenerator = node.generator;this.labels = [];
node.body = this.parseBlock(true);
node.expression = false;
this.inFunction = oldInFunc;this.inGenerator = oldInGen;this.labels = oldLabels;
}
// If this is a strict mode function, verify that argument names
// are not repeated, a