Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

recast

Package Overview
Dependencies
Maintainers
1
Versions
266
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

recast - npm Package Compare versions

Comparing version 0.16.2 to 0.17.0

lib/comments.d.ts

206

lib/comments.js

@@ -1,14 +0,15 @@

var assert = require("assert");
var types = require("./types");
var n = types.namedTypes;
var isArray = types.builtInTypes.array;
var isObject = types.builtInTypes.object;
var linesModule = require("./lines");
var fromString = linesModule.fromString;
var Lines = linesModule.Lines;
var concat = linesModule.concat;
var util = require("./util");
var comparePos = util.comparePos;
var childNodesCacheKey = require("private").makeUniqueKey();
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var types_1 = __importDefault(require("./types"));
var n = types_1.default.namedTypes;
var isArray = types_1.default.builtInTypes.array;
var isObject = types_1.default.builtInTypes.object;
var lines_1 = require("./lines");
var util_1 = require("./util");
var private_1 = require("private");
var childNodesCacheKey = private_1.makeUniqueKey();
// TODO Move a non-caching implementation of this function into ast-types,

@@ -20,3 +21,2 @@ // and implement a caching wrapper function here.

}
// The .loc checks below are sensitive to some of the problems that

@@ -26,4 +26,3 @@ // are fixed by this utility function. Specifically, if it decides to

// is unreliable, then we don't want to add node to the resultArray.
util.fixFaultyLocations(node, lines);
util_1.fixFaultyLocations(node, lines);
if (resultArray) {

@@ -36,4 +35,3 @@ if (n.Node.check(node) &&

for (var i = resultArray.length - 1; i >= 0; --i) {
if (comparePos(resultArray[i].loc.end,
node.loc.start) <= 0) {
if (util_1.comparePos(resultArray[i].loc.end, node.loc.start) <= 0) {
break;

@@ -45,15 +43,16 @@ }

}
} else if (node[childNodesCacheKey]) {
}
else if (node[childNodesCacheKey]) {
return node[childNodesCacheKey];
}
var names;
if (isArray.check(node)) {
names = Object.keys(node);
} else if (isObject.check(node)) {
names = types.getFieldNames(node);
} else {
}
else if (isObject.check(node)) {
names = types_1.default.getFieldNames(node);
}
else {
return;
}
if (!resultArray) {

@@ -65,10 +64,7 @@ Object.defineProperty(node, childNodesCacheKey, {

}
for (var i = 0, nameCount = names.length; i < nameCount; ++i) {
getSortedChildNodes(node[names[i]], lines, resultArray);
}
return resultArray;
}
// As efficiently as possible, decorate the comment object with

@@ -79,3 +75,2 @@ // .precedingNode, .enclosingNode, and/or .followingNode properties, at

var childNodes = getSortedChildNodes(node, lines);
// Time to dust off the old binary search robes and wizard hat.

@@ -86,5 +81,4 @@ var left = 0, right = childNodes.length;

var child = childNodes[middle];
if (comparePos(child.loc.start, comment.loc.start) <= 0 &&
comparePos(comment.loc.end, child.loc.end) <= 0) {
if (util_1.comparePos(child.loc.start, comment.loc.start) <= 0 &&
util_1.comparePos(comment.loc.end, child.loc.end) <= 0) {
// The comment is completely contained by this child node.

@@ -94,4 +88,3 @@ decorateComment(comment.enclosingNode = child, comment, lines);

}
if (comparePos(child.loc.end, comment.loc.start) <= 0) {
if (util_1.comparePos(child.loc.end, comment.loc.start) <= 0) {
// This child node falls completely before the comment.

@@ -105,4 +98,3 @@ // Because we will never consider this node or any nodes

}
if (comparePos(comment.loc.end, child.loc.start) <= 0) {
if (util_1.comparePos(comment.loc.end, child.loc.start) <= 0) {
// This child node falls completely after the comment.

@@ -116,10 +108,7 @@ // Because we will never consider this node or any nodes after

}
throw new Error("Comment location overlaps with node location");
}
if (precedingNode) {
comment.precedingNode = precedingNode;
}
if (followingNode) {

@@ -129,18 +118,13 @@ comment.followingNode = followingNode;

}
exports.attach = function(comments, ast, lines) {
function attach(comments, ast, lines) {
if (!isArray.check(comments)) {
return;
}
var tiesToBreak = [];
comments.forEach(function(comment) {
comments.forEach(function (comment) {
comment.loc.lines = lines;
decorateComment(ast, comment, lines);
var pn = comment.precedingNode;
var en = comment.enclosingNode;
var fn = comment.followingNode;
if (pn && fn) {

@@ -150,8 +134,3 @@ var tieCount = tiesToBreak.length;

var lastTie = tiesToBreak[tieCount - 1];
assert.strictEqual(
lastTie.precedingNode === comment.precedingNode,
lastTie.followingNode === comment.followingNode
);
assert_1.default.strictEqual(lastTie.precedingNode === comment.precedingNode, lastTie.followingNode === comment.followingNode);
if (lastTie.followingNode !== comment.followingNode) {

@@ -161,16 +140,15 @@ breakTies(tiesToBreak, lines);

}
tiesToBreak.push(comment);
} else if (pn) {
}
else if (pn) {
// No contest: we have a trailing comment.
breakTies(tiesToBreak, lines);
addTrailingComment(pn, comment);
} else if (fn) {
}
else if (fn) {
// No contest: we have a leading comment.
breakTies(tiesToBreak, lines);
addLeadingComment(fn, comment);
} else if (en) {
}
else if (en) {
// The enclosing node has no child nodes at all, so what we

@@ -180,11 +158,9 @@ // have here is a dangling comment, e.g. [/* crickets */].

addDanglingComment(en, comment);
} else {
}
else {
throw new Error("AST contains no nodes at all?");
}
});
breakTies(tiesToBreak, lines);
comments.forEach(function(comment) {
comments.forEach(function (comment) {
// These node references were useful for breaking ties, but we

@@ -197,4 +173,5 @@ // don't need them anymore, and they create cycles in the AST that

});
};
}
exports.attach = attach;
;
function breakTies(tiesToBreak, lines) {

@@ -205,7 +182,5 @@ var tieCount = tiesToBreak.length;

}
var pn = tiesToBreak[0].precedingNode;
var fn = tiesToBreak[0].followingNode;
var gapEndPos = fn.loc.start;
// Iterate backwards through tiesToBreak, examining the gaps

@@ -215,9 +190,6 @@ // between the tied comments. In order to qualify as leading, a

// whitespace-only gaps (or other comments).
for (var indexOfFirstLeadingComment = tieCount;
indexOfFirstLeadingComment > 0;
--indexOfFirstLeadingComment) {
for (var indexOfFirstLeadingComment = tieCount; indexOfFirstLeadingComment > 0; --indexOfFirstLeadingComment) {
var comment = tiesToBreak[indexOfFirstLeadingComment - 1];
assert.strictEqual(comment.precedingNode, pn);
assert.strictEqual(comment.followingNode, fn);
assert_1.default.strictEqual(comment.precedingNode, pn);
assert_1.default.strictEqual(comment.followingNode, fn);
var gap = lines.sliceString(comment.loc.end, gapEndPos);

@@ -228,26 +200,22 @@ if (/\S/.test(gap)) {

}
gapEndPos = comment.loc.start;
}
while (indexOfFirstLeadingComment <= tieCount &&
(comment = tiesToBreak[indexOfFirstLeadingComment]) &&
// If the comment is a //-style comment and indented more
// deeply than the node itself, reconsider it as trailing.
(comment.type === "Line" || comment.type === "CommentLine") &&
comment.loc.start.column > fn.loc.start.column) {
(comment = tiesToBreak[indexOfFirstLeadingComment]) &&
// If the comment is a //-style comment and indented more
// deeply than the node itself, reconsider it as trailing.
(comment.type === "Line" || comment.type === "CommentLine") &&
comment.loc.start.column > fn.loc.start.column) {
++indexOfFirstLeadingComment;
}
tiesToBreak.forEach(function(comment, i) {
tiesToBreak.forEach(function (comment, i) {
if (i < indexOfFirstLeadingComment) {
addTrailingComment(pn, comment);
} else {
}
else {
addLeadingComment(fn, comment);
}
});
tiesToBreak.length = 0;
}
function addCommentHelper(node, comment) {

@@ -257,3 +225,2 @@ var comments = node.comments || (node.comments = []);

}
function addLeadingComment(node, comment) {

@@ -264,3 +231,2 @@ comment.leading = true;

}
function addDanglingComment(node, comment) {

@@ -271,3 +237,2 @@ comment.leading = false;

}
function addTrailingComment(node, comment) {

@@ -278,11 +243,8 @@ comment.leading = false;

}
function printLeadingComment(commentPath, print) {
var comment = commentPath.getValue();
n.Comment.assert(comment);
var loc = comment.loc;
var lines = loc && loc.lines;
var parts = [print(commentPath)];
if (comment.trailing) {

@@ -292,9 +254,5 @@ // When we print trailing comments as leading comments, we don't

parts.push("\n");
} else if (lines instanceof Lines) {
var trailingSpace = lines.slice(
loc.end,
lines.skipSpaces(loc.end)
);
}
else if (lines instanceof lines_1.Lines) {
var trailingSpace = lines.slice(loc.end, lines.skipSpaces(loc.end));
if (trailingSpace.length === 1) {

@@ -304,3 +262,4 @@ // If the trailing space contains no newlines, then we want to

parts.push(trailingSpace);
} else {
}
else {
// If the trailing space contains newlines, then replace it

@@ -310,22 +269,17 @@ // with just that many newlines, with all other spaces removed.

}
} else {
}
else {
parts.push("\n");
}
return concat(parts);
return lines_1.concat(parts);
}
function printTrailingComment(commentPath, print) {
var comment = commentPath.getValue(commentPath);
n.Comment.assert(comment);
var loc = comment.loc;
var lines = loc && loc.lines;
var parts = [];
if (lines instanceof Lines) {
if (lines instanceof lines_1.Lines) {
var fromPos = lines.skipSpaces(loc.start, true) || lines.firstPos();
var leadingSpace = lines.slice(fromPos, loc.start);
if (leadingSpace.length === 1) {

@@ -335,3 +289,4 @@ // If the leading space contains no newlines, then we want to

parts.push(leadingSpace);
} else {
}
else {
// If the leading space contains newlines, then replace it

@@ -342,37 +297,32 @@ // with just that many newlines, sans all other spaces.

}
parts.push(print(commentPath));
return concat(parts);
return lines_1.concat(parts);
}
exports.printComments = function(path, print) {
function printComments(path, print) {
var value = path.getValue();
var innerLines = print(path);
var comments = n.Node.check(value) &&
types.getFieldValue(value, "comments");
types_1.default.getFieldValue(value, "comments");
if (!comments || comments.length === 0) {
return innerLines;
}
var leadingParts = [];
var trailingParts = [innerLines];
path.each(function(commentPath) {
path.each(function (commentPath) {
var comment = commentPath.getValue();
var leading = types.getFieldValue(comment, "leading");
var trailing = types.getFieldValue(comment, "trailing");
var leading = types_1.default.getFieldValue(comment, "leading");
var trailing = types_1.default.getFieldValue(comment, "trailing");
if (leading || (trailing && !(n.Statement.check(value) ||
comment.type === "Block" ||
comment.type === "CommentBlock"))) {
comment.type === "Block" ||
comment.type === "CommentBlock"))) {
leadingParts.push(printLeadingComment(commentPath, print));
} else if (trailing) {
}
else if (trailing) {
trailingParts.push(printTrailingComment(commentPath, print));
}
}, "comments");
leadingParts.push.apply(leadingParts, trailingParts);
return concat(leadingParts);
};
return lines_1.concat(leadingParts);
}
exports.printComments = printComments;
;

@@ -1,92 +0,89 @@

var assert = require("assert");
var types = require("./types");
var n = types.namedTypes;
var Node = n.Node;
var isArray = types.builtInTypes.array;
var isNumber = types.builtInTypes.number;
var util = require("./util.js");
function FastPath(value) {
assert.ok(this instanceof FastPath);
this.stack = [value];
}
"use strict";;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var types_1 = __importDefault(require("./types"));
var n = types_1.default.namedTypes;
var isArray = types_1.default.builtInTypes.array;
var isNumber = types_1.default.builtInTypes.number;
var util = __importStar(require("./util"));
var FastPath = function FastPath(value) {
assert_1.default.ok(this instanceof FastPath);
this.stack = [value];
};
var FPp = FastPath.prototype;
module.exports = FastPath;
// Static convenience function for coercing a value to a FastPath.
FastPath.from = function(obj) {
if (obj instanceof FastPath) {
// Return a defensive copy of any existing FastPath instances.
return obj.copy();
}
if (obj instanceof types.NodePath) {
// For backwards compatibility, unroll NodePath instances into
// lightweight FastPath [..., name, value] stacks.
FastPath.from = function (obj) {
if (obj instanceof FastPath) {
// Return a defensive copy of any existing FastPath instances.
return obj.copy();
}
if (obj instanceof types_1.default.NodePath) {
// For backwards compatibility, unroll NodePath instances into
// lightweight FastPath [..., name, value] stacks.
var copy = Object.create(FastPath.prototype);
var stack = [obj.value];
for (var pp; (pp = obj.parentPath); obj = pp)
stack.push(obj.name, pp.value);
copy.stack = stack.reverse();
return copy;
}
// Otherwise use obj as the value of the new FastPath instance.
return new FastPath(obj);
};
FPp.copy = function copy() {
var copy = Object.create(FastPath.prototype);
var stack = [obj.value];
for (var pp; (pp = obj.parentPath); obj = pp)
stack.push(obj.name, pp.value);
copy.stack = stack.reverse();
copy.stack = this.stack.slice(0);
return copy;
}
// Otherwise use obj as the value of the new FastPath instance.
return new FastPath(obj);
};
FPp.copy = function copy() {
var copy = Object.create(FastPath.prototype);
copy.stack = this.stack.slice(0);
return copy;
};
// The name of the current property is always the penultimate element of
// this.stack, and always a String.
FPp.getName = function getName() {
var s = this.stack;
var len = s.length;
if (len > 1) {
return s[len - 2];
}
// Since the name is always a string, null is a safe sentinel value to
// return if we do not know the name of the (root) value.
return null;
var s = this.stack;
var len = s.length;
if (len > 1) {
return s[len - 2];
}
// Since the name is always a string, null is a safe sentinel value to
// return if we do not know the name of the (root) value.
return null;
};
// The value of the current property is always the final element of
// this.stack.
FPp.getValue = function getValue() {
var s = this.stack;
return s[s.length - 1];
var s = this.stack;
return s[s.length - 1];
};
FPp.valueIsDuplicate = function () {
var s = this.stack;
var valueIndex = s.length - 1;
return s.lastIndexOf(s[valueIndex], valueIndex - 1) >= 0;
var s = this.stack;
var valueIndex = s.length - 1;
return s.lastIndexOf(s[valueIndex], valueIndex - 1) >= 0;
};
function getNodeHelper(path, count) {
var s = path.stack;
for (var i = s.length - 1; i >= 0; i -= 2) {
var value = s[i];
if (n.Node.check(value) && --count < 0) {
return value;
var s = path.stack;
for (var i = s.length - 1; i >= 0; i -= 2) {
var value = s[i];
if (n.Node.check(value) && --count < 0) {
return value;
}
}
}
return null;
return null;
}
FPp.getNode = function getNode(count) {
return getNodeHelper(this, ~~count);
if (count === void 0) { count = 0; }
return getNodeHelper(this, ~~count);
};
FPp.getParentNode = function getParentNode(count) {
return getNodeHelper(this, ~~count + 1);
if (count === void 0) { count = 0; }
return getNodeHelper(this, ~~count + 1);
};
// The length of the stack can be either even or odd, depending on whether

@@ -98,9 +95,8 @@ // or not we have a name for the root value. The difference between the

FPp.getRootValue = function getRootValue() {
var s = this.stack;
if (s.length % 2 === 0) {
return s[1];
}
return s[0];
var s = this.stack;
if (s.length % 2 === 0) {
return s[1];
}
return s[0];
};
// Temporarily push properties named by string arguments given after the

@@ -111,17 +107,16 @@ // callback function onto this.stack, then call the callback with a

// is probably a mistake to retain a reference to the path.
FPp.call = function call(callback/*, name1, name2, ... */) {
var s = this.stack;
var origLen = s.length;
var value = s[origLen - 1];
var argc = arguments.length;
for (var i = 1; i < argc; ++i) {
var name = arguments[i];
value = value[name];
s.push(name, value);
}
var result = callback(this);
s.length = origLen;
return result;
FPp.call = function call(callback /*, name1, name2, ... */) {
var s = this.stack;
var origLen = s.length;
var value = s[origLen - 1];
var argc = arguments.length;
for (var i = 1; i < argc; ++i) {
var name = arguments[i];
value = value[name];
s.push(name, value);
}
var result = callback(this);
s.length = origLen;
return result;
};
// Similar to FastPath.prototype.call, except that the value obtained by

@@ -131,57 +126,47 @@ // accessing this.getValue()[name1][name2]... should be array-like. The

// element of the array.
FPp.each = function each(callback/*, name1, name2, ... */) {
var s = this.stack;
var origLen = s.length;
var value = s[origLen - 1];
var argc = arguments.length;
for (var i = 1; i < argc; ++i) {
var name = arguments[i];
value = value[name];
s.push(name, value);
}
for (var i = 0; i < value.length; ++i) {
if (i in value) {
s.push(i, value[i]);
// If the callback needs to know the value of i, call
// path.getName(), assuming path is the parameter name.
callback(this);
s.length -= 2;
FPp.each = function each(callback /*, name1, name2, ... */) {
var s = this.stack;
var origLen = s.length;
var value = s[origLen - 1];
var argc = arguments.length;
for (var i = 1; i < argc; ++i) {
var name = arguments[i];
value = value[name];
s.push(name, value);
}
}
s.length = origLen;
for (var i = 0; i < value.length; ++i) {
if (i in value) {
s.push(i, value[i]);
// If the callback needs to know the value of i, call
// path.getName(), assuming path is the parameter name.
callback(this);
s.length -= 2;
}
}
s.length = origLen;
};
// Similar to FastPath.prototype.each, except that the results of the
// callback function invocations are stored in an array and returned at
// the end of the iteration.
FPp.map = function map(callback/*, name1, name2, ... */) {
var s = this.stack;
var origLen = s.length;
var value = s[origLen - 1];
var argc = arguments.length;
for (var i = 1; i < argc; ++i) {
var name = arguments[i];
value = value[name];
s.push(name, value);
}
var result = new Array(value.length);
for (var i = 0; i < value.length; ++i) {
if (i in value) {
s.push(i, value[i]);
result[i] = callback(this, i);
s.length -= 2;
FPp.map = function map(callback /*, name1, name2, ... */) {
var s = this.stack;
var origLen = s.length;
var value = s[origLen - 1];
var argc = arguments.length;
for (var i = 1; i < argc; ++i) {
var name = arguments[i];
value = value[name];
s.push(name, value);
}
}
s.length = origLen;
return result;
var result = new Array(value.length);
for (var i = 0; i < value.length; ++i) {
if (i in value) {
s.push(i, value[i]);
result[i] = callback(this, i);
s.length -= 2;
}
}
s.length = origLen;
return result;
};
// Returns true if the node at the tip of the path is wrapped with

@@ -198,434 +183,362 @@ // parentheses, OR if the only reason the node needed parentheses was that

FPp.hasParens = function () {
const node = this.getNode();
const prevToken = this.getPrevToken(node);
if (! prevToken) {
return false;
}
const nextToken = this.getNextToken(node);
if (! nextToken) {
return false;
}
if (prevToken.value === "(") {
if (nextToken.value === ")") {
// If the node preceded by a `(` token and followed by a `)` token,
// then of course it has parentheses.
return true;
var node = this.getNode();
var prevToken = this.getPrevToken(node);
if (!prevToken) {
return false;
}
// If this is one of the few Expression types that can't come first in
// the enclosing statement because of parsing ambiguities (namely,
// FunctionExpression, ObjectExpression, and ClassExpression) and
// this.firstInStatement() returns true, and the node would not need
// parentheses in an expression context because this.needsParens(true)
// returns false, then it just needs an opening parenthesis to resolve
// the parsing ambiguity that made it appear to need parentheses.
const justNeedsOpeningParen =
! this.canBeFirstInStatement() &&
this.firstInStatement() &&
! this.needsParens(true);
if (justNeedsOpeningParen) {
return true;
var nextToken = this.getNextToken(node);
if (!nextToken) {
return false;
}
}
return false;
if (prevToken.value === "(") {
if (nextToken.value === ")") {
// If the node preceded by a `(` token and followed by a `)` token,
// then of course it has parentheses.
return true;
}
// If this is one of the few Expression types that can't come first in
// the enclosing statement because of parsing ambiguities (namely,
// FunctionExpression, ObjectExpression, and ClassExpression) and
// this.firstInStatement() returns true, and the node would not need
// parentheses in an expression context because this.needsParens(true)
// returns false, then it just needs an opening parenthesis to resolve
// the parsing ambiguity that made it appear to need parentheses.
var justNeedsOpeningParen = !this.canBeFirstInStatement() &&
this.firstInStatement() &&
!this.needsParens(true);
if (justNeedsOpeningParen) {
return true;
}
}
return false;
};
FPp.getPrevToken = function (node) {
node = node || this.getNode();
const loc = node && node.loc;
const tokens = loc && loc.tokens;
if (tokens && loc.start.token > 0) {
const token = tokens[loc.start.token - 1];
if (token) {
// Do not return tokens that fall outside the root subtree.
const rootLoc = this.getRootValue().loc;
if (util.comparePos(rootLoc.start, token.loc.start) <= 0) {
return token;
}
node = node || this.getNode();
var loc = node && node.loc;
var tokens = loc && loc.tokens;
if (tokens && loc.start.token > 0) {
var token = tokens[loc.start.token - 1];
if (token) {
// Do not return tokens that fall outside the root subtree.
var rootLoc = this.getRootValue().loc;
if (util.comparePos(rootLoc.start, token.loc.start) <= 0) {
return token;
}
}
}
}
return null;
return null;
};
FPp.getNextToken = function (node) {
node = node || this.getNode();
const loc = node && node.loc;
const tokens = loc && loc.tokens;
if (tokens && loc.end.token < tokens.length) {
const token = tokens[loc.end.token];
if (token) {
// Do not return tokens that fall outside the root subtree.
const rootLoc = this.getRootValue().loc;
if (util.comparePos(token.loc.end, rootLoc.end) <= 0) {
return token;
}
node = node || this.getNode();
var loc = node && node.loc;
var tokens = loc && loc.tokens;
if (tokens && loc.end.token < tokens.length) {
var token = tokens[loc.end.token];
if (token) {
// Do not return tokens that fall outside the root subtree.
var rootLoc = this.getRootValue().loc;
if (util.comparePos(token.loc.end, rootLoc.end) <= 0) {
return token;
}
}
}
}
return null;
return null;
};
// Inspired by require("ast-types").NodePath.prototype.needsParens, but
// more efficient because we're iterating backwards through a stack.
FPp.needsParens = function(assumeExpressionContext) {
var node = this.getNode();
// This needs to come before `if (!parent) { return false }` because
// an object destructuring assignment requires parens for
// correctness even when it's the topmost expression.
if (node.type === "AssignmentExpression" && node.left.type === 'ObjectPattern') {
return true;
}
var parent = this.getParentNode();
if (!parent) {
return false;
}
var name = this.getName();
// If the value of this path is some child of a Node and not a Node
// itself, then it doesn't need parentheses. Only Node objects (in fact,
// only Expression nodes) need parentheses.
if (this.getValue() !== node) {
return false;
}
// Only statements don't need parentheses.
if (n.Statement.check(node)) {
return false;
}
// Identifiers never need parentheses.
if (node.type === "Identifier") {
return false;
}
if (parent.type === "ParenthesizedExpression") {
return false;
}
switch (node.type) {
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
return parent.type === "MemberExpression"
&& name === "object"
&& parent.object === node;
case "BinaryExpression":
case "LogicalExpression":
switch (parent.type) {
case "CallExpression":
return name === "callee"
&& parent.callee === node;
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
return true;
case "MemberExpression":
return name === "object"
&& parent.object === node;
case "BinaryExpression":
case "LogicalExpression":
var po = parent.operator;
var pp = PRECEDENCE[po];
var no = node.operator;
var np = PRECEDENCE[no];
if (pp > np) {
FPp.needsParens = function (assumeExpressionContext) {
var node = this.getNode();
// This needs to come before `if (!parent) { return false }` because
// an object destructuring assignment requires parens for
// correctness even when it's the topmost expression.
if (node.type === "AssignmentExpression" && node.left.type === 'ObjectPattern') {
return true;
}
if (pp === np && name === "right") {
assert.strictEqual(parent.right, node);
return true;
}
default:
return false;
}
case "SequenceExpression":
switch (parent.type) {
case "ReturnStatement":
return false;
case "ForStatement":
// Although parentheses wouldn't hurt around sequence expressions in
// the head of for loops, traditional style dictates that e.g. i++,
// j++ should not be wrapped with parentheses.
return false;
case "ExpressionStatement":
return name !== "expression";
default:
// Otherwise err on the side of overparenthesization, adding
// explicit exceptions above if this proves overzealous.
return true;
var parent = this.getParentNode();
if (!parent) {
return false;
}
case "YieldExpression":
switch (parent.type) {
case "BinaryExpression":
case "LogicalExpression":
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
case "CallExpression":
case "MemberExpression":
case "NewExpression":
case "ConditionalExpression":
case "YieldExpression":
return true;
default:
return false;
var name = this.getName();
// If the value of this path is some child of a Node and not a Node
// itself, then it doesn't need parentheses. Only Node objects (in fact,
// only Expression nodes) need parentheses.
if (this.getValue() !== node) {
return false;
}
case "IntersectionTypeAnnotation":
case "UnionTypeAnnotation":
return parent.type === "NullableTypeAnnotation";
case "Literal":
return parent.type === "MemberExpression"
&& isNumber.check(node.value)
&& name === "object"
&& parent.object === node;
// Babel 6 Literal split
case "NumericLiteral":
return parent.type === "MemberExpression"
&& name === "object"
&& parent.object === node;
case "AssignmentExpression":
case "ConditionalExpression":
switch (parent.type) {
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
case "BinaryExpression":
case "LogicalExpression":
return true;
case "CallExpression":
case "NewExpression":
return name === "callee"
&& parent.callee === node;
case "ConditionalExpression":
return name === "test"
&& parent.test === node;
case "MemberExpression":
return name === "object"
&& parent.object === node;
default:
return false;
// Only statements don't need parentheses.
if (n.Statement.check(node)) {
return false;
}
case "ArrowFunctionExpression":
if (n.CallExpression.check(parent) &&
name === 'callee') {
return true;
// Identifiers never need parentheses.
if (node.type === "Identifier") {
return false;
}
if (n.MemberExpression.check(parent) &&
name === 'object') {
return true;
if (parent.type === "ParenthesizedExpression") {
return false;
}
return isBinary(parent);
case "ObjectExpression":
if (parent.type === "ArrowFunctionExpression" &&
name === "body") {
return true;
switch (node.type) {
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
return parent.type === "MemberExpression"
&& name === "object"
&& parent.object === node;
case "BinaryExpression":
case "LogicalExpression":
switch (parent.type) {
case "CallExpression":
return name === "callee"
&& parent.callee === node;
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
return true;
case "MemberExpression":
return name === "object"
&& parent.object === node;
case "BinaryExpression":
case "LogicalExpression":
var po = parent.operator;
var pp = PRECEDENCE[po];
var no = node.operator;
var np = PRECEDENCE[no];
if (pp > np) {
return true;
}
if (pp === np && name === "right") {
assert_1.default.strictEqual(parent.right, node);
return true;
}
default:
return false;
}
case "SequenceExpression":
switch (parent.type) {
case "ReturnStatement":
return false;
case "ForStatement":
// Although parentheses wouldn't hurt around sequence expressions in
// the head of for loops, traditional style dictates that e.g. i++,
// j++ should not be wrapped with parentheses.
return false;
case "ExpressionStatement":
return name !== "expression";
default:
// Otherwise err on the side of overparenthesization, adding
// explicit exceptions above if this proves overzealous.
return true;
}
case "YieldExpression":
switch (parent.type) {
case "BinaryExpression":
case "LogicalExpression":
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
case "CallExpression":
case "MemberExpression":
case "NewExpression":
case "ConditionalExpression":
case "YieldExpression":
return true;
default:
return false;
}
case "IntersectionTypeAnnotation":
case "UnionTypeAnnotation":
return parent.type === "NullableTypeAnnotation";
case "Literal":
return parent.type === "MemberExpression"
&& isNumber.check(node.value)
&& name === "object"
&& parent.object === node;
// Babel 6 Literal split
case "NumericLiteral":
return parent.type === "MemberExpression"
&& name === "object"
&& parent.object === node;
case "AssignmentExpression":
case "ConditionalExpression":
switch (parent.type) {
case "UnaryExpression":
case "SpreadElement":
case "SpreadProperty":
case "BinaryExpression":
case "LogicalExpression":
return true;
case "CallExpression":
case "NewExpression":
return name === "callee"
&& parent.callee === node;
case "ConditionalExpression":
return name === "test"
&& parent.test === node;
case "MemberExpression":
return name === "object"
&& parent.object === node;
default:
return false;
}
case "ArrowFunctionExpression":
if (n.CallExpression.check(parent) &&
name === 'callee') {
return true;
}
if (n.MemberExpression.check(parent) &&
name === 'object') {
return true;
}
return isBinary(parent);
case "ObjectExpression":
if (parent.type === "ArrowFunctionExpression" &&
name === "body") {
return true;
}
break;
case "CallExpression":
if (name === "declaration" &&
n.ExportDefaultDeclaration.check(parent) &&
n.FunctionExpression.check(node.callee)) {
return true;
}
}
break;
case "CallExpression":
if (name === "declaration" &&
n.ExportDefaultDeclaration.check(parent) &&
n.FunctionExpression.check(node.callee)) {
return true;
if (parent.type === "NewExpression" &&
name === "callee" &&
parent.callee === node) {
return containsCallExpression(node);
}
}
if (parent.type === "NewExpression" &&
name === "callee" &&
parent.callee === node) {
return containsCallExpression(node);
}
if (assumeExpressionContext !== true &&
!this.canBeFirstInStatement() &&
this.firstInStatement()) {
return true;
}
return false;
if (assumeExpressionContext !== true &&
!this.canBeFirstInStatement() &&
this.firstInStatement()) {
return true;
}
return false;
};
function isBinary(node) {
return n.BinaryExpression.check(node)
|| n.LogicalExpression.check(node);
return n.BinaryExpression.check(node)
|| n.LogicalExpression.check(node);
}
// @ts-ignore 'isUnaryLike' is declared but its value is never read. [6133]
function isUnaryLike(node) {
return n.UnaryExpression.check(node)
// I considered making SpreadElement and SpreadProperty subtypes of
// UnaryExpression, but they're not really Expression nodes.
|| (n.SpreadElement && n.SpreadElement.check(node))
|| (n.SpreadProperty && n.SpreadProperty.check(node));
return n.UnaryExpression.check(node)
// I considered making SpreadElement and SpreadProperty subtypes of
// UnaryExpression, but they're not really Expression nodes.
|| (n.SpreadElement && n.SpreadElement.check(node))
|| (n.SpreadProperty && n.SpreadProperty.check(node));
}
var PRECEDENCE = {};
[["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%", "**"]
].forEach(function(tier, i) {
tier.forEach(function(op) {
PRECEDENCE[op] = i;
});
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%", "**"]
].forEach(function (tier, i) {
tier.forEach(function (op) {
PRECEDENCE[op] = i;
});
});
function containsCallExpression(node) {
if (n.CallExpression.check(node)) {
return true;
}
if (isArray.check(node)) {
return node.some(containsCallExpression);
}
if (n.Node.check(node)) {
return types.someField(node, function(name, child) {
return containsCallExpression(child);
});
}
return false;
}
FPp.canBeFirstInStatement = function() {
var node = this.getNode();
if (n.FunctionExpression.check(node)) {
return false;
}
if (n.ObjectExpression.check(node)) {
return false;
}
if (n.ClassExpression.check(node)) {
return false;
}
return true;
};
FPp.firstInStatement = function() {
var s = this.stack;
var parentName, parent;
var childName, child;
for (var i = s.length - 1; i >= 0; i -= 2) {
if (n.Node.check(s[i])) {
childName = parentName;
child = parent;
parentName = s[i - 1];
parent = s[i];
if (n.CallExpression.check(node)) {
return true;
}
if (!parent || !child) {
continue;
if (isArray.check(node)) {
return node.some(containsCallExpression);
}
if (n.BlockStatement.check(parent) &&
parentName === "body" &&
childName === 0) {
assert.strictEqual(parent.body[0], child);
return true;
if (n.Node.check(node)) {
return types_1.default.someField(node, function (_name, child) {
return containsCallExpression(child);
});
}
if (n.ExpressionStatement.check(parent) &&
childName === "expression") {
assert.strictEqual(parent.expression, child);
return true;
return false;
}
FPp.canBeFirstInStatement = function () {
var node = this.getNode();
if (n.FunctionExpression.check(node)) {
return false;
}
if (n.AssignmentExpression.check(parent) &&
childName === "left") {
assert.strictEqual(parent.left, child);
return true;
if (n.ObjectExpression.check(node)) {
return false;
}
if (n.ArrowFunctionExpression.check(parent) &&
childName === "body") {
assert.strictEqual(parent.body, child);
return true;
if (n.ClassExpression.check(node)) {
return false;
}
if (n.SequenceExpression.check(parent) &&
parentName === "expressions" &&
childName === 0) {
assert.strictEqual(parent.expressions[0], child);
continue;
return true;
};
FPp.firstInStatement = function () {
var s = this.stack;
var parentName, parent;
var childName, child;
for (var i = s.length - 1; i >= 0; i -= 2) {
if (n.Node.check(s[i])) {
childName = parentName;
child = parent;
parentName = s[i - 1];
parent = s[i];
}
if (!parent || !child) {
continue;
}
if (n.BlockStatement.check(parent) &&
parentName === "body" &&
childName === 0) {
assert_1.default.strictEqual(parent.body[0], child);
return true;
}
if (n.ExpressionStatement.check(parent) &&
childName === "expression") {
assert_1.default.strictEqual(parent.expression, child);
return true;
}
if (n.AssignmentExpression.check(parent) &&
childName === "left") {
assert_1.default.strictEqual(parent.left, child);
return true;
}
if (n.ArrowFunctionExpression.check(parent) &&
childName === "body") {
assert_1.default.strictEqual(parent.body, child);
return true;
}
if (n.SequenceExpression.check(parent) &&
parentName === "expressions" &&
childName === 0) {
assert_1.default.strictEqual(parent.expressions[0], child);
continue;
}
if (n.CallExpression.check(parent) &&
childName === "callee") {
assert_1.default.strictEqual(parent.callee, child);
continue;
}
if (n.MemberExpression.check(parent) &&
childName === "object") {
assert_1.default.strictEqual(parent.object, child);
continue;
}
if (n.ConditionalExpression.check(parent) &&
childName === "test") {
assert_1.default.strictEqual(parent.test, child);
continue;
}
if (isBinary(parent) &&
childName === "left") {
assert_1.default.strictEqual(parent.left, child);
continue;
}
if (n.UnaryExpression.check(parent) &&
!parent.prefix &&
childName === "argument") {
assert_1.default.strictEqual(parent.argument, child);
continue;
}
return false;
}
if (n.CallExpression.check(parent) &&
childName === "callee") {
assert.strictEqual(parent.callee, child);
continue;
}
if (n.MemberExpression.check(parent) &&
childName === "object") {
assert.strictEqual(parent.object, child);
continue;
}
if (n.ConditionalExpression.check(parent) &&
childName === "test") {
assert.strictEqual(parent.test, child);
continue;
}
if (isBinary(parent) &&
childName === "left") {
assert.strictEqual(parent.left, child);
continue;
}
if (n.UnaryExpression.check(parent) &&
!parent.prefix &&
childName === "argument") {
assert.strictEqual(parent.argument, child);
continue;
}
return false;
}
return true;
return true;
};
exports.default = FastPath;
module.exports = exports["default"];

@@ -1,10 +0,15 @@

var assert = require("assert");
var sourceMap = require("source-map");
var normalizeOptions = require("./options").normalize;
var secretKey = require("private").makeUniqueKey();
var types = require("./types");
var isString = types.builtInTypes.string;
var comparePos = require("./util").comparePos;
var Mapping = require("./mapping");
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var source_map_1 = __importDefault(require("source-map"));
var options_1 = require("./options");
var private_1 = require("private");
var secretKey = private_1.makeUniqueKey();
var types_1 = __importDefault(require("./types"));
var isString = types_1.default.builtInTypes.string;
var util_1 = require("./util");
var mapping_1 = __importDefault(require("./mapping"));
// Goals:

@@ -16,118 +21,95 @@ // 1. Minimize new string creation.

// 5. No newline characters.
var useSymbol = typeof Symbol === "function";
// @ts-ignore Subsequent variable declarations must have the same type.
var secretKey = "recastLinesSecret";
if (useSymbol) {
secretKey = Symbol.for(secretKey);
secretKey = Symbol.for(secretKey);
}
function getSecret(lines) {
return lines[secretKey];
return lines[secretKey];
}
function Lines(infos, sourceFileName) {
assert.ok(this instanceof Lines);
assert.ok(infos.length > 0);
if (sourceFileName) {
isString.assert(sourceFileName);
} else {
sourceFileName = null;
}
setSymbolOrKey(this, secretKey, {
infos: infos,
mappings: [],
name: sourceFileName,
cachedSourceMap: null
});
this.length = infos.length;
this.name = sourceFileName;
if (sourceFileName) {
getSecret(this).mappings.push(new Mapping(this, {
start: this.firstPos(),
end: this.lastPos()
}));
}
}
var Lines = function Lines(infos, sourceFileName) {
assert_1.default.ok(this instanceof Lines);
assert_1.default.ok(infos.length > 0);
if (sourceFileName) {
isString.assert(sourceFileName);
}
else {
sourceFileName = null;
}
setSymbolOrKey(this, secretKey, {
infos: infos,
mappings: [],
name: sourceFileName,
cachedSourceMap: null
});
this.length = infos.length;
this.name = sourceFileName;
if (sourceFileName) {
getSecret(this).mappings.push(new mapping_1.default(this, {
start: this.firstPos(),
end: this.lastPos()
}));
}
};
exports.Lines = Lines;
function setSymbolOrKey(obj, key, value) {
if (useSymbol) {
return obj[key] = value;
}
Object.defineProperty(obj, key, {
value: value,
enumerable: false,
writable: false,
configurable: true
});
return value;
if (useSymbol) {
return obj[key] = value;
}
Object.defineProperty(obj, key, {
value: value,
enumerable: false,
writable: false,
configurable: true
});
return value;
}
// Exposed for instanceof checks. The fromString function should be used
// to create new Lines objects.
exports.Lines = Lines;
var Lp = Lines.prototype;
function copyLineInfo(info) {
return {
line: info.line,
indent: info.indent,
locked: info.locked,
sliceStart: info.sliceStart,
sliceEnd: info.sliceEnd
};
return {
line: info.line,
indent: info.indent,
locked: info.locked,
sliceStart: info.sliceStart,
sliceEnd: info.sliceEnd
};
}
var fromStringCache = {};
var hasOwn = fromStringCache.hasOwnProperty;
var maxCacheKeyLen = 10;
function countSpaces(spaces, tabWidth) {
var count = 0;
var len = spaces.length;
for (var i = 0; i < len; ++i) {
switch (spaces.charCodeAt(i)) {
case 9: // '\t'
assert.strictEqual(typeof tabWidth, "number");
assert.ok(tabWidth > 0);
var next = Math.ceil(count / tabWidth) * tabWidth;
if (next === count) {
count += tabWidth;
} else {
count = next;
}
break;
case 11: // '\v'
case 12: // '\f'
case 13: // '\r'
case 0xfeff: // zero-width non-breaking space
// These characters contribute nothing to indentation.
break;
case 32: // ' '
default: // Treat all other whitespace like ' '.
count += 1;
break;
var count = 0;
var len = spaces.length;
for (var i = 0; i < len; ++i) {
switch (spaces.charCodeAt(i)) {
case 9: // '\t'
assert_1.default.strictEqual(typeof tabWidth, "number");
assert_1.default.ok(tabWidth > 0);
var next = Math.ceil(count / tabWidth) * tabWidth;
if (next === count) {
count += tabWidth;
}
else {
count = next;
}
break;
case 11: // '\v'
case 12: // '\f'
case 13: // '\r'
case 0xfeff: // zero-width non-breaking space
// These characters contribute nothing to indentation.
break;
case 32: // ' '
default: // Treat all other whitespace like ' '.
count += 1;
break;
}
}
}
return count;
return count;
}
exports.countSpaces = countSpaces;
var leadingSpaceExp = /^\s*/;
// As specified here: http://www.ecma-international.org/ecma-262/6.0/#sec-line-terminators
var lineTerminatorSeqExp =
/\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/;
var lineTerminatorSeqExp = /\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/;
/**

@@ -137,322 +119,235 @@ * @param {Object} options - Options object that configures printing.

function fromString(string, options) {
if (string instanceof Lines)
return string;
string += "";
var tabWidth = options && options.tabWidth;
var tabless = string.indexOf("\t") < 0;
var locked = !! (options && options.locked);
var cacheable = !options && tabless && (string.length <= maxCacheKeyLen);
assert.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string);
if (cacheable && hasOwn.call(fromStringCache, string))
return fromStringCache[string];
var lines = new Lines(string.split(lineTerminatorSeqExp).map(function(line) {
var spaces = leadingSpaceExp.exec(line)[0];
return {
line: line,
indent: countSpaces(spaces, tabWidth),
// Boolean indicating whether this line can be reindented.
locked: locked,
sliceStart: spaces.length,
sliceEnd: line.length
};
}), normalizeOptions(options).sourceFileName);
if (cacheable)
fromStringCache[string] = lines;
return lines;
if (string instanceof Lines)
return string;
string += "";
var tabWidth = options && options.tabWidth;
var tabless = string.indexOf("\t") < 0;
var locked = !!(options && options.locked);
var cacheable = !options && tabless && (string.length <= maxCacheKeyLen);
assert_1.default.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string);
if (cacheable && hasOwn.call(fromStringCache, string))
return fromStringCache[string];
var lines = new Lines(string.split(lineTerminatorSeqExp).map(function (line) {
// TODO: handle null exec result
var spaces = leadingSpaceExp.exec(line)[0];
return {
line: line,
indent: countSpaces(spaces, tabWidth),
// Boolean indicating whether this line can be reindented.
locked: locked,
sliceStart: spaces.length,
sliceEnd: line.length
};
}), options_1.normalize(options).sourceFileName);
if (cacheable)
fromStringCache[string] = lines;
return lines;
}
exports.fromString = fromString;
function isOnlyWhitespace(string) {
return !/\S/.test(string);
return !/\S/.test(string);
}
Lp.toString = function(options) {
return this.sliceString(this.firstPos(), this.lastPos(), options);
Lp.toString = function (options) {
return this.sliceString(this.firstPos(), this.lastPos(), options);
};
Lp.getSourceMap = function(sourceMapName, sourceRoot) {
if (!sourceMapName) {
// Although we could make up a name or generate an anonymous
// source map, instead we assume that any consumer who does not
// provide a name does not actually want a source map.
return null;
}
var targetLines = this;
function updateJSON(json) {
json = json || {};
isString.assert(sourceMapName);
json.file = sourceMapName;
if (sourceRoot) {
isString.assert(sourceRoot);
json.sourceRoot = sourceRoot;
Lp.getSourceMap = function (sourceMapName, sourceRoot) {
if (!sourceMapName) {
// Although we could make up a name or generate an anonymous
// source map, instead we assume that any consumer who does not
// provide a name does not actually want a source map.
return null;
}
return json;
}
var secret = getSecret(targetLines);
if (secret.cachedSourceMap) {
// Since Lines objects are immutable, we can reuse any source map
// that was previously generated. Nevertheless, we return a new
// JSON object here to protect the cached source map from outside
// modification.
return updateJSON(secret.cachedSourceMap.toJSON());
}
var smg = new sourceMap.SourceMapGenerator(updateJSON());
var sourcesToContents = {};
secret.mappings.forEach(function(mapping) {
var sourceCursor = mapping.sourceLines.skipSpaces(
mapping.sourceLoc.start
) || mapping.sourceLines.lastPos();
var targetCursor = targetLines.skipSpaces(
mapping.targetLoc.start
) || targetLines.lastPos();
while (comparePos(sourceCursor, mapping.sourceLoc.end) < 0 &&
comparePos(targetCursor, mapping.targetLoc.end) < 0) {
var sourceChar = mapping.sourceLines.charAt(sourceCursor);
var targetChar = targetLines.charAt(targetCursor);
assert.strictEqual(sourceChar, targetChar);
var sourceName = mapping.sourceLines.name;
// Add mappings one character at a time for maximum resolution.
smg.addMapping({
source: sourceName,
original: { line: sourceCursor.line,
var targetLines = this;
function updateJSON(json) {
json = json || {};
isString.assert(sourceMapName);
json.file = sourceMapName;
if (sourceRoot) {
isString.assert(sourceRoot);
json.sourceRoot = sourceRoot;
}
return json;
}
var secret = getSecret(targetLines);
if (secret.cachedSourceMap) {
// Since Lines objects are immutable, we can reuse any source map
// that was previously generated. Nevertheless, we return a new
// JSON object here to protect the cached source map from outside
// modification.
return updateJSON(secret.cachedSourceMap.toJSON());
}
var smg = new source_map_1.default.SourceMapGenerator(updateJSON());
var sourcesToContents = {};
secret.mappings.forEach(function (mapping) {
var sourceCursor = mapping.sourceLines.skipSpaces(mapping.sourceLoc.start) || mapping.sourceLines.lastPos();
var targetCursor = targetLines.skipSpaces(mapping.targetLoc.start) || targetLines.lastPos();
while (util_1.comparePos(sourceCursor, mapping.sourceLoc.end) < 0 &&
util_1.comparePos(targetCursor, mapping.targetLoc.end) < 0) {
var sourceChar = mapping.sourceLines.charAt(sourceCursor);
var targetChar = targetLines.charAt(targetCursor);
assert_1.default.strictEqual(sourceChar, targetChar);
var sourceName = mapping.sourceLines.name;
// Add mappings one character at a time for maximum resolution.
smg.addMapping({
source: sourceName,
original: { line: sourceCursor.line,
column: sourceCursor.column },
generated: { line: targetCursor.line,
column: targetCursor.column }
});
if (!hasOwn.call(sourcesToContents, sourceName)) {
var sourceContent = mapping.sourceLines.toString();
smg.setSourceContent(sourceName, sourceContent);
sourcesToContents[sourceName] = sourceContent;
}
targetLines.nextPos(targetCursor, true);
mapping.sourceLines.nextPos(sourceCursor, true);
}
});
secret.cachedSourceMap = smg;
return smg.toJSON();
generated: { line: targetCursor.line,
column: targetCursor.column }
});
if (!hasOwn.call(sourcesToContents, sourceName)) {
var sourceContent = mapping.sourceLines.toString();
smg.setSourceContent(sourceName, sourceContent);
sourcesToContents[sourceName] = sourceContent;
}
targetLines.nextPos(targetCursor, true);
mapping.sourceLines.nextPos(sourceCursor, true);
}
});
secret.cachedSourceMap = smg;
return smg.toJSON();
};
Lp.bootstrapCharAt = function(pos) {
assert.strictEqual(typeof pos, "object");
assert.strictEqual(typeof pos.line, "number");
assert.strictEqual(typeof pos.column, "number");
var line = pos.line,
column = pos.column,
strings = this.toString().split(lineTerminatorSeqExp),
string = strings[line - 1];
if (typeof string === "undefined")
return "";
if (column === string.length &&
line < strings.length)
return "\n";
if (column >= string.length)
return "";
return string.charAt(column);
Lp.bootstrapCharAt = function (pos) {
assert_1.default.strictEqual(typeof pos, "object");
assert_1.default.strictEqual(typeof pos.line, "number");
assert_1.default.strictEqual(typeof pos.column, "number");
var line = pos.line, column = pos.column, strings = this.toString().split(lineTerminatorSeqExp), string = strings[line - 1];
if (typeof string === "undefined")
return "";
if (column === string.length &&
line < strings.length)
return "\n";
if (column >= string.length)
return "";
return string.charAt(column);
};
Lp.charAt = function(pos) {
assert.strictEqual(typeof pos, "object");
assert.strictEqual(typeof pos.line, "number");
assert.strictEqual(typeof pos.column, "number");
var line = pos.line,
column = pos.column,
secret = getSecret(this),
infos = secret.infos,
info = infos[line - 1],
c = column;
if (typeof info === "undefined" || c < 0)
return "";
var indent = this.getIndentAt(line);
if (c < indent)
return " ";
c += info.sliceStart - indent;
if (c === info.sliceEnd &&
line < this.length)
return "\n";
if (c >= info.sliceEnd)
return "";
return info.line.charAt(c);
Lp.charAt = function (pos) {
assert_1.default.strictEqual(typeof pos, "object");
assert_1.default.strictEqual(typeof pos.line, "number");
assert_1.default.strictEqual(typeof pos.column, "number");
var line = pos.line, column = pos.column, secret = getSecret(this), infos = secret.infos, info = infos[line - 1], c = column;
if (typeof info === "undefined" || c < 0)
return "";
var indent = this.getIndentAt(line);
if (c < indent)
return " ";
c += info.sliceStart - indent;
if (c === info.sliceEnd &&
line < this.length)
return "\n";
if (c >= info.sliceEnd)
return "";
return info.line.charAt(c);
};
Lp.stripMargin = function(width, skipFirstLine) {
if (width === 0)
return this;
assert.ok(width > 0, "negative margin: " + width);
if (skipFirstLine && this.length === 1)
return this;
var secret = getSecret(this);
var lines = new Lines(secret.infos.map(function(info, i) {
if (info.line && (i > 0 || !skipFirstLine)) {
info = copyLineInfo(info);
info.indent = Math.max(0, info.indent - width);
Lp.stripMargin = function (width, skipFirstLine) {
if (width === 0)
return this;
assert_1.default.ok(width > 0, "negative margin: " + width);
if (skipFirstLine && this.length === 1)
return this;
var secret = getSecret(this);
var lines = new Lines(secret.infos.map(function (info, i) {
if (info.line && (i > 0 || !skipFirstLine)) {
info = copyLineInfo(info);
info.indent = Math.max(0, info.indent - width);
}
return info;
}));
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert_1.default.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function (mapping) {
newMappings.push(mapping.indent(width, skipFirstLine, true));
});
}
return info;
}));
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function(mapping) {
newMappings.push(mapping.indent(width, skipFirstLine, true));
});
}
return lines;
return lines;
};
Lp.indent = function(by) {
if (by === 0)
return this;
var secret = getSecret(this);
var lines = new Lines(secret.infos.map(function(info) {
if (info.line && ! info.locked) {
info = copyLineInfo(info);
info.indent += by;
Lp.indent = function (by) {
if (by === 0)
return this;
var secret = getSecret(this);
var lines = new Lines(secret.infos.map(function (info) {
if (info.line && !info.locked) {
info = copyLineInfo(info);
info.indent += by;
}
return info;
}));
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert_1.default.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function (mapping) {
newMappings.push(mapping.indent(by));
});
}
return info
}));
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function(mapping) {
newMappings.push(mapping.indent(by));
});
}
return lines;
return lines;
};
Lp.indentTail = function(by) {
if (by === 0)
return this;
if (this.length < 2)
return this;
var secret = getSecret(this);
var lines = new Lines(secret.infos.map(function(info, i) {
if (i > 0 && info.line && ! info.locked) {
info = copyLineInfo(info);
info.indent += by;
Lp.indentTail = function (by) {
if (by === 0)
return this;
if (this.length < 2)
return this;
var secret = getSecret(this);
var lines = new Lines(secret.infos.map(function (info, i) {
if (i > 0 && info.line && !info.locked) {
info = copyLineInfo(info);
info.indent += by;
}
return info;
}));
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert_1.default.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function (mapping) {
newMappings.push(mapping.indent(by, true));
});
}
return info;
}));
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function(mapping) {
newMappings.push(mapping.indent(by, true));
});
}
return lines;
return lines;
};
Lp.lockIndentTail = function () {
if (this.length < 2) {
return this;
}
var infos = getSecret(this).infos;
return new Lines(infos.map(function (info, i) {
info = copyLineInfo(info);
info.locked = i > 0;
return info;
}));
if (this.length < 2) {
return this;
}
var infos = getSecret(this).infos;
return new Lines(infos.map(function (info, i) {
info = copyLineInfo(info);
info.locked = i > 0;
return info;
}));
};
Lp.getIndentAt = function(line) {
assert.ok(line >= 1, "no line " + line + " (line numbers start from 1)");
var secret = getSecret(this),
info = secret.infos[line - 1];
return Math.max(info.indent, 0);
Lp.getIndentAt = function (line) {
assert_1.default.ok(line >= 1, "no line " + line + " (line numbers start from 1)");
var secret = getSecret(this), info = secret.infos[line - 1];
return Math.max(info.indent, 0);
};
Lp.guessTabWidth = function() {
var secret = getSecret(this);
if (hasOwn.call(secret, "cachedTabWidth")) {
return secret.cachedTabWidth;
}
var counts = []; // Sparse array.
var lastIndent = 0;
for (var line = 1, last = this.length; line <= last; ++line) {
var info = secret.infos[line - 1];
var sliced = info.line.slice(info.sliceStart, info.sliceEnd);
// Whitespace-only lines don't tell us much about the likely tab
// width of this code.
if (isOnlyWhitespace(sliced)) {
continue;
Lp.guessTabWidth = function () {
var secret = getSecret(this);
if (hasOwn.call(secret, "cachedTabWidth")) {
return secret.cachedTabWidth;
}
var diff = Math.abs(info.indent - lastIndent);
counts[diff] = ~~counts[diff] + 1;
lastIndent = info.indent;
}
var maxCount = -1;
var result = 2;
for (var tabWidth = 1;
tabWidth < counts.length;
tabWidth += 1) {
if (hasOwn.call(counts, tabWidth) &&
counts[tabWidth] > maxCount) {
maxCount = counts[tabWidth];
result = tabWidth;
var counts = []; // Sparse array.
var lastIndent = 0;
for (var line = 1, last = this.length; line <= last; ++line) {
var info = secret.infos[line - 1];
var sliced = info.line.slice(info.sliceStart, info.sliceEnd);
// Whitespace-only lines don't tell us much about the likely tab
// width of this code.
if (isOnlyWhitespace(sliced)) {
continue;
}
var diff = Math.abs(info.indent - lastIndent);
counts[diff] = ~~counts[diff] + 1;
lastIndent = info.indent;
}
}
return secret.cachedTabWidth = result;
var maxCount = -1;
var result = 2;
for (var tabWidth = 1; tabWidth < counts.length; tabWidth += 1) {
if (hasOwn.call(counts, tabWidth) &&
counts[tabWidth] > maxCount) {
maxCount = counts[tabWidth];
result = tabWidth;
}
}
return secret.cachedTabWidth = result;
};
// Determine if the list of lines has a first line that starts with a //

@@ -462,442 +357,358 @@ // or /* comment. If this is the case, the code may need to be wrapped in

Lp.startsWithComment = function () {
var secret = getSecret(this);
if (secret.infos.length === 0) {
return false;
}
var firstLineInfo = secret.infos[0],
sliceStart = firstLineInfo.sliceStart,
sliceEnd = firstLineInfo.sliceEnd,
firstLine = firstLineInfo.line.slice(sliceStart, sliceEnd).trim();
return firstLine.length === 0 ||
firstLine.slice(0, 2) === "//" ||
firstLine.slice(0, 2) === "/*";
var secret = getSecret(this);
if (secret.infos.length === 0) {
return false;
}
var firstLineInfo = secret.infos[0], sliceStart = firstLineInfo.sliceStart, sliceEnd = firstLineInfo.sliceEnd, firstLine = firstLineInfo.line.slice(sliceStart, sliceEnd).trim();
return firstLine.length === 0 ||
firstLine.slice(0, 2) === "//" ||
firstLine.slice(0, 2) === "/*";
};
Lp.isOnlyWhitespace = function() {
return isOnlyWhitespace(this.toString());
Lp.isOnlyWhitespace = function () {
return isOnlyWhitespace(this.toString());
};
Lp.isPrecededOnlyByWhitespace = function(pos) {
var secret = getSecret(this);
var info = secret.infos[pos.line - 1];
var indent = Math.max(info.indent, 0);
var diff = pos.column - indent;
if (diff <= 0) {
// If pos.column does not exceed the indentation amount, then
// there must be only whitespace before it.
return true;
}
var start = info.sliceStart;
var end = Math.min(start + diff, info.sliceEnd);
var prefix = info.line.slice(start, end);
return isOnlyWhitespace(prefix);
Lp.isPrecededOnlyByWhitespace = function (pos) {
var secret = getSecret(this);
var info = secret.infos[pos.line - 1];
var indent = Math.max(info.indent, 0);
var diff = pos.column - indent;
if (diff <= 0) {
// If pos.column does not exceed the indentation amount, then
// there must be only whitespace before it.
return true;
}
var start = info.sliceStart;
var end = Math.min(start + diff, info.sliceEnd);
var prefix = info.line.slice(start, end);
return isOnlyWhitespace(prefix);
};
Lp.getLineLength = function(line) {
var secret = getSecret(this),
info = secret.infos[line - 1];
return this.getIndentAt(line) + info.sliceEnd - info.sliceStart;
Lp.getLineLength = function (line) {
var secret = getSecret(this), info = secret.infos[line - 1];
return this.getIndentAt(line) + info.sliceEnd - info.sliceStart;
};
Lp.nextPos = function(pos, skipSpaces) {
var l = Math.max(pos.line, 0),
c = Math.max(pos.column, 0);
if (c < this.getLineLength(l)) {
pos.column += 1;
Lp.nextPos = function (pos, skipSpaces) {
var l = Math.max(pos.line, 0), c = Math.max(pos.column, 0);
if (c < this.getLineLength(l)) {
pos.column += 1;
return skipSpaces
? !!this.skipSpaces(pos, false, true)
: true;
}
if (l < this.length) {
pos.line += 1;
pos.column = 0;
return skipSpaces
? !!this.skipSpaces(pos, false, true)
: true;
}
return false;
};
Lp.prevPos = function (pos, skipSpaces) {
var l = pos.line, c = pos.column;
if (c < 1) {
l -= 1;
if (l < 1)
return false;
c = this.getLineLength(l);
}
else {
c = Math.min(c - 1, this.getLineLength(l));
}
pos.line = l;
pos.column = c;
return skipSpaces
? !!this.skipSpaces(pos, false, true)
: true;
}
if (l < this.length) {
pos.line += 1;
pos.column = 0;
return skipSpaces
? !!this.skipSpaces(pos, false, true)
: true;
}
return false;
? !!this.skipSpaces(pos, true, true)
: true;
};
Lp.prevPos = function(pos, skipSpaces) {
var l = pos.line,
c = pos.column;
if (c < 1) {
l -= 1;
if (l < 1)
return false;
c = this.getLineLength(l);
} else {
c = Math.min(c - 1, this.getLineLength(l));
}
pos.line = l;
pos.column = c;
return skipSpaces
? !!this.skipSpaces(pos, true, true)
: true;
Lp.firstPos = function () {
// Trivial, but provided for completeness.
return { line: 1, column: 0 };
};
Lp.firstPos = function() {
// Trivial, but provided for completeness.
return { line: 1, column: 0 };
Lp.lastPos = function () {
return {
line: this.length,
column: this.getLineLength(this.length)
};
};
Lp.lastPos = function() {
return {
line: this.length,
column: this.getLineLength(this.length)
};
};
Lp.skipSpaces = function(pos, backward, modifyInPlace) {
if (pos) {
pos = modifyInPlace ? pos : {
line: pos.line,
column: pos.column
};
} else if (backward) {
pos = this.lastPos();
} else {
pos = this.firstPos();
}
if (backward) {
while (this.prevPos(pos)) {
if (!isOnlyWhitespace(this.charAt(pos)) &&
this.nextPos(pos)) {
return pos;
}
Lp.skipSpaces = function (pos, backward, modifyInPlace) {
if (pos) {
pos = modifyInPlace ? pos : {
line: pos.line,
column: pos.column
};
}
return null;
} else {
while (isOnlyWhitespace(this.charAt(pos))) {
if (!this.nextPos(pos)) {
else if (backward) {
pos = this.lastPos();
}
else {
pos = this.firstPos();
}
if (backward) {
while (this.prevPos(pos)) {
if (!isOnlyWhitespace(this.charAt(pos)) &&
this.nextPos(pos)) {
return pos;
}
}
return null;
}
}
return pos;
}
else {
while (isOnlyWhitespace(this.charAt(pos))) {
if (!this.nextPos(pos)) {
return null;
}
}
return pos;
}
};
Lp.trimLeft = function() {
var pos = this.skipSpaces(this.firstPos(), false, true);
return pos ? this.slice(pos) : emptyLines;
Lp.trimLeft = function () {
var pos = this.skipSpaces(this.firstPos(), false, true);
return pos ? this.slice(pos) : emptyLines;
};
Lp.trimRight = function() {
var pos = this.skipSpaces(this.lastPos(), true, true);
return pos ? this.slice(this.firstPos(), pos) : emptyLines;
Lp.trimRight = function () {
var pos = this.skipSpaces(this.lastPos(), true, true);
return pos ? this.slice(this.firstPos(), pos) : emptyLines;
};
Lp.trim = function() {
var start = this.skipSpaces(this.firstPos(), false, true);
if (start === null)
return emptyLines;
var end = this.skipSpaces(this.lastPos(), true, true);
assert.notStrictEqual(end, null);
return this.slice(start, end);
Lp.trim = function () {
var start = this.skipSpaces(this.firstPos(), false, true);
if (start === null)
return emptyLines;
var end = this.skipSpaces(this.lastPos(), true, true);
assert_1.default.notStrictEqual(end, null);
return this.slice(start, end);
};
Lp.eachPos = function(callback, startPos, skipSpaces) {
var pos = this.firstPos();
if (startPos) {
pos.line = startPos.line,
pos.column = startPos.column
}
if (skipSpaces && !this.skipSpaces(pos, false, true)) {
return; // Encountered nothing but spaces.
}
do callback.call(this, pos);
while (this.nextPos(pos, skipSpaces));
Lp.eachPos = function (callback, startPos, skipSpaces) {
var pos = this.firstPos();
if (startPos) {
pos.line = startPos.line,
pos.column = startPos.column;
}
if (skipSpaces && !this.skipSpaces(pos, false, true)) {
return; // Encountered nothing but spaces.
}
do
callback.call(this, pos);
while (this.nextPos(pos, skipSpaces));
};
Lp.bootstrapSlice = function(start, end) {
var strings = this.toString().split(
lineTerminatorSeqExp
).slice(
start.line - 1,
end.line
);
strings.push(strings.pop().slice(0, end.column));
strings[0] = strings[0].slice(start.column);
return fromString(strings.join("\n"));
Lp.bootstrapSlice = function (start, end) {
var strings = this.toString().split(lineTerminatorSeqExp).slice(start.line - 1, end.line);
strings.push(strings.pop().slice(0, end.column));
strings[0] = strings[0].slice(start.column);
return fromString(strings.join("\n"));
};
Lp.slice = function(start, end) {
if (!end) {
Lp.slice = function (start, end) {
if (!end) {
if (!start) {
// The client seems to want a copy of this Lines object, but
// Lines objects are immutable, so it's perfectly adequate to
// return the same object.
return this;
}
// Slice to the end if no end position was provided.
end = this.lastPos();
}
if (!start) {
// The client seems to want a copy of this Lines object, but
// Lines objects are immutable, so it's perfectly adequate to
// return the same object.
return this;
throw new Error("cannot slice with end but not start");
}
// Slice to the end if no end position was provided.
end = this.lastPos();
}
var secret = getSecret(this);
var sliced = secret.infos.slice(start.line - 1, end.line);
if (start.line === end.line) {
sliced[0] = sliceInfo(sliced[0], start.column, end.column);
} else {
assert.ok(start.line < end.line);
sliced[0] = sliceInfo(sliced[0], start.column);
sliced.push(sliceInfo(sliced.pop(), 0, end.column));
}
var lines = new Lines(sliced);
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function(mapping) {
var sliced = mapping.slice(this, start, end);
if (sliced) {
newMappings.push(sliced);
}
}, this);
}
return lines;
var secret = getSecret(this);
var sliced = secret.infos.slice(start.line - 1, end.line);
if (start.line === end.line) {
sliced[0] = sliceInfo(sliced[0], start.column, end.column);
}
else {
assert_1.default.ok(start.line < end.line);
sliced[0] = sliceInfo(sliced[0], start.column);
sliced.push(sliceInfo(sliced.pop(), 0, end.column));
}
var lines = new Lines(sliced);
if (secret.mappings.length > 0) {
var newMappings = getSecret(lines).mappings;
assert_1.default.strictEqual(newMappings.length, 0);
secret.mappings.forEach(function (mapping) {
var sliced = mapping.slice(this, start, end);
if (sliced) {
newMappings.push(sliced);
}
}, this);
}
return lines;
};
function sliceInfo(info, startCol, endCol) {
var sliceStart = info.sliceStart;
var sliceEnd = info.sliceEnd;
var indent = Math.max(info.indent, 0);
var lineLength = indent + sliceEnd - sliceStart;
if (typeof endCol === "undefined") {
endCol = lineLength;
}
startCol = Math.max(startCol, 0);
endCol = Math.min(endCol, lineLength);
endCol = Math.max(endCol, startCol);
if (endCol < indent) {
indent = endCol;
sliceEnd = sliceStart;
} else {
sliceEnd -= lineLength - endCol;
}
lineLength = endCol;
lineLength -= startCol;
if (startCol < indent) {
indent -= startCol;
} else {
startCol -= indent;
indent = 0;
sliceStart += startCol;
}
assert.ok(indent >= 0);
assert.ok(sliceStart <= sliceEnd);
assert.strictEqual(lineLength, indent + sliceEnd - sliceStart);
if (info.indent === indent &&
info.sliceStart === sliceStart &&
info.sliceEnd === sliceEnd) {
return info;
}
return {
line: info.line,
indent: indent,
// A destructive slice always unlocks indentation.
locked: false,
sliceStart: sliceStart,
sliceEnd: sliceEnd
};
}
Lp.bootstrapSliceString = function(start, end, options) {
return this.slice(start, end).toString(options);
};
Lp.sliceString = function(start, end, options) {
if (!end) {
if (!start) {
// The client seems to want a copy of this Lines object, but
// Lines objects are immutable, so it's perfectly adequate to
// return the same object.
return this;
var sliceStart = info.sliceStart;
var sliceEnd = info.sliceEnd;
var indent = Math.max(info.indent, 0);
var lineLength = indent + sliceEnd - sliceStart;
if (typeof endCol === "undefined") {
endCol = lineLength;
}
// Slice to the end if no end position was provided.
end = this.lastPos();
}
options = normalizeOptions(options);
var infos = getSecret(this).infos;
var parts = [];
var tabWidth = options.tabWidth;
for (var line = start.line; line <= end.line; ++line) {
var info = infos[line - 1];
if (line === start.line) {
if (line === end.line) {
info = sliceInfo(info, start.column, end.column);
} else {
info = sliceInfo(info, start.column);
}
} else if (line === end.line) {
info = sliceInfo(info, 0, end.column);
startCol = Math.max(startCol, 0);
endCol = Math.min(endCol, lineLength);
endCol = Math.max(endCol, startCol);
if (endCol < indent) {
indent = endCol;
sliceEnd = sliceStart;
}
var indent = Math.max(info.indent, 0);
var before = info.line.slice(0, info.sliceStart);
if (options.reuseWhitespace &&
isOnlyWhitespace(before) &&
countSpaces(before, options.tabWidth) === indent) {
// Reuse original spaces if the indentation is correct.
parts.push(info.line.slice(0, info.sliceEnd));
continue;
else {
sliceEnd -= lineLength - endCol;
}
var tabs = 0;
var spaces = indent;
if (options.useTabs) {
tabs = Math.floor(indent / tabWidth);
spaces -= tabs * tabWidth;
lineLength = endCol;
lineLength -= startCol;
if (startCol < indent) {
indent -= startCol;
}
var result = "";
if (tabs > 0) {
result += new Array(tabs + 1).join("\t");
else {
startCol -= indent;
indent = 0;
sliceStart += startCol;
}
if (spaces > 0) {
result += new Array(spaces + 1).join(" ");
assert_1.default.ok(indent >= 0);
assert_1.default.ok(sliceStart <= sliceEnd);
assert_1.default.strictEqual(lineLength, indent + sliceEnd - sliceStart);
if (info.indent === indent &&
info.sliceStart === sliceStart &&
info.sliceEnd === sliceEnd) {
return info;
}
result += info.line.slice(info.sliceStart, info.sliceEnd);
parts.push(result);
}
return parts.join(options.lineTerminator);
return {
line: info.line,
indent: indent,
// A destructive slice always unlocks indentation.
locked: false,
sliceStart: sliceStart,
sliceEnd: sliceEnd
};
}
Lp.bootstrapSliceString = function (start, end, options) {
return this.slice(start, end).toString(options);
};
Lp.isEmpty = function() {
return this.length < 2 && this.getLineLength(1) < 1;
Lp.sliceString = function (start, end, options) {
if (!end) {
if (!start) {
// The client seems to want a copy of this Lines object, but
// Lines objects are immutable, so it's perfectly adequate to
// return the same object.
return this;
}
// Slice to the end if no end position was provided.
end = this.lastPos();
}
options = options_1.normalize(options);
var infos = getSecret(this).infos;
var parts = [];
var tabWidth = options.tabWidth;
for (var line = start.line; line <= end.line; ++line) {
var info = infos[line - 1];
if (line === start.line) {
if (line === end.line) {
info = sliceInfo(info, start.column, end.column);
}
else {
info = sliceInfo(info, start.column);
}
}
else if (line === end.line) {
info = sliceInfo(info, 0, end.column);
}
var indent = Math.max(info.indent, 0);
var before = info.line.slice(0, info.sliceStart);
if (options.reuseWhitespace &&
isOnlyWhitespace(before) &&
countSpaces(before, options.tabWidth) === indent) {
// Reuse original spaces if the indentation is correct.
parts.push(info.line.slice(0, info.sliceEnd));
continue;
}
var tabs = 0;
var spaces = indent;
if (options.useTabs) {
tabs = Math.floor(indent / tabWidth);
spaces -= tabs * tabWidth;
}
var result = "";
if (tabs > 0) {
result += new Array(tabs + 1).join("\t");
}
if (spaces > 0) {
result += new Array(spaces + 1).join(" ");
}
result += info.line.slice(info.sliceStart, info.sliceEnd);
parts.push(result);
}
return parts.join(options.lineTerminator);
};
Lp.join = function(elements) {
var separator = this;
var separatorSecret = getSecret(separator);
var infos = [];
var mappings = [];
var prevInfo;
function appendSecret(secret) {
if (secret === null)
return;
if (prevInfo) {
var info = secret.infos[0];
var indent = new Array(info.indent + 1).join(" ");
var prevLine = infos.length;
var prevColumn = Math.max(prevInfo.indent, 0) +
prevInfo.sliceEnd - prevInfo.sliceStart;
prevInfo.line = prevInfo.line.slice(
0, prevInfo.sliceEnd) + indent + info.line.slice(
info.sliceStart, info.sliceEnd);
// If any part of a line is indentation-locked, the whole line
// will be indentation-locked.
prevInfo.locked = prevInfo.locked || info.locked;
prevInfo.sliceEnd = prevInfo.line.length;
if (secret.mappings.length > 0) {
secret.mappings.forEach(function(mapping) {
mappings.push(mapping.add(prevLine, prevColumn));
Lp.isEmpty = function () {
return this.length < 2 && this.getLineLength(1) < 1;
};
Lp.join = function (elements) {
var separator = this;
var separatorSecret = getSecret(separator);
var infos = [];
var mappings = [];
var prevInfo;
function appendSecret(secret) {
if (secret === null)
return;
if (prevInfo) {
var info = secret.infos[0];
var indent = new Array(info.indent + 1).join(" ");
var prevLine = infos.length;
var prevColumn = Math.max(prevInfo.indent, 0) +
prevInfo.sliceEnd - prevInfo.sliceStart;
prevInfo.line = prevInfo.line.slice(0, prevInfo.sliceEnd) + indent + info.line.slice(info.sliceStart, info.sliceEnd);
// If any part of a line is indentation-locked, the whole line
// will be indentation-locked.
prevInfo.locked = prevInfo.locked || info.locked;
prevInfo.sliceEnd = prevInfo.line.length;
if (secret.mappings.length > 0) {
secret.mappings.forEach(function (mapping) {
mappings.push(mapping.add(prevLine, prevColumn));
});
}
}
else if (secret.mappings.length > 0) {
mappings.push.apply(mappings, secret.mappings);
}
secret.infos.forEach(function (info, i) {
if (!prevInfo || i > 0) {
prevInfo = copyLineInfo(info);
infos.push(prevInfo);
}
});
}
} else if (secret.mappings.length > 0) {
mappings.push.apply(mappings, secret.mappings);
}
secret.infos.forEach(function(info, i) {
if (!prevInfo || i > 0) {
prevInfo = copyLineInfo(info);
infos.push(prevInfo);
}
});
}
function appendWithSeparator(secret, i) {
if (i > 0)
appendSecret(separatorSecret);
appendSecret(secret);
}
elements.map(function(elem) {
var lines = fromString(elem);
if (lines.isEmpty())
return null;
return getSecret(lines);
}).forEach(separator.isEmpty()
? appendSecret
: appendWithSeparator);
if (infos.length < 1)
return emptyLines;
var lines = new Lines(infos);
getSecret(lines).mappings = mappings;
return lines;
function appendWithSeparator(secret, i) {
if (i > 0)
appendSecret(separatorSecret);
appendSecret(secret);
}
elements.map(function (elem) {
var lines = fromString(elem);
if (lines.isEmpty())
return null;
return getSecret(lines);
}).forEach(separator.isEmpty()
? appendSecret
: appendWithSeparator);
if (infos.length < 1)
return emptyLines;
var lines = new Lines(infos);
getSecret(lines).mappings = mappings;
return lines;
};
exports.concat = function(elements) {
return emptyLines.join(elements);
function concat(elements) {
return emptyLines.join(elements);
}
exports.concat = concat;
;
Lp.concat = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var list = [this];
list.push.apply(list, args);
assert_1.default.strictEqual(list.length, args.length + 1);
return emptyLines.join(list);
};
Lp.concat = function(other) {
var args = arguments,
list = [this];
list.push.apply(list, args);
assert.strictEqual(list.length, args.length + 1);
return emptyLines.join(list);
};
// The emptyLines object needs to be created all the way down here so that
// Lines.prototype will be fully populated.
var emptyLines = fromString("");

@@ -1,15 +0,24 @@

var assert = require("assert");
var types = require("./types");
var isString = types.builtInTypes.string;
var isNumber = types.builtInTypes.number;
var SourceLocation = types.namedTypes.SourceLocation;
var Position = types.namedTypes.Position;
var linesModule = require("./lines");
var comparePos = require("./util").comparePos;
function Mapping(sourceLines, sourceLoc, targetLoc) {
assert.ok(this instanceof Mapping);
assert.ok(sourceLines instanceof linesModule.Lines);
"use strict";;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var types_1 = __importDefault(require("./types"));
var isNumber = types_1.default.builtInTypes.number;
var SourceLocation = types_1.default.namedTypes.SourceLocation;
var Position = types_1.default.namedTypes.Position;
var linesModule = __importStar(require("./lines"));
var util_1 = require("./util");
var Mapping = function Mapping(sourceLines, sourceLoc, targetLoc) {
assert_1.default.ok(this instanceof Mapping);
assert_1.default.ok(sourceLines instanceof linesModule.Lines);
SourceLocation.assert(sourceLoc);
if (targetLoc) {

@@ -19,13 +28,11 @@ // In certain cases it's possible for targetLoc.{start,end}.column

// valid SourceLocation nodes, so we need to be more forgiving.
assert.ok(
isNumber.check(targetLoc.start.line) &&
assert_1.default.ok(isNumber.check(targetLoc.start.line) &&
isNumber.check(targetLoc.start.column) &&
isNumber.check(targetLoc.end.line) &&
isNumber.check(targetLoc.end.column)
);
} else {
isNumber.check(targetLoc.end.column));
}
else {
// Assume identity mapping if no targetLoc specified.
targetLoc = sourceLoc;
}
Object.defineProperties(this, {

@@ -36,21 +43,17 @@ sourceLines: { value: sourceLines },

});
}
};
var Mp = Mapping.prototype;
module.exports = Mapping;
Mp.slice = function(lines, start, end) {
assert.ok(lines instanceof linesModule.Lines);
exports.default = Mapping;
Mp.slice = function (lines, start, end) {
assert_1.default.ok(lines instanceof linesModule.Lines);
Position.assert(start);
if (end) {
Position.assert(end);
} else {
}
else {
end = lines.lastPos();
}
var sourceLines = this.sourceLines;
var sourceLoc = this.sourceLoc;
var targetLoc = this.targetLoc;
function skip(name) {

@@ -60,17 +63,12 @@ var sourceFromPos = sourceLoc[name];

var targetToPos = start;
if (name === "end") {
targetToPos = end;
} else {
assert.strictEqual(name, "start");
}
return skipChars(
sourceLines, sourceFromPos,
lines, targetFromPos, targetToPos
);
else {
assert_1.default.strictEqual(name, "start");
}
return skipChars(sourceLines, sourceFromPos, lines, targetFromPos, targetToPos);
}
if (comparePos(start, targetLoc.start) <= 0) {
if (comparePos(targetLoc.end, end) <= 0) {
if (util_1.comparePos(start, targetLoc.start) <= 0) {
if (util_1.comparePos(targetLoc.end, end) <= 0) {
targetLoc = {

@@ -80,10 +78,9 @@ start: subtractPos(targetLoc.start, start.line, start.column),

};
// The sourceLoc can stay the same because the contents of the
// targetLoc have not changed.
} else if (comparePos(end, targetLoc.start) <= 0) {
}
else if (util_1.comparePos(end, targetLoc.start) <= 0) {
return null;
} else {
}
else {
sourceLoc = {

@@ -93,3 +90,2 @@ start: sourceLoc.start,

};
targetLoc = {

@@ -100,9 +96,8 @@ start: subtractPos(targetLoc.start, start.line, start.column),

}
} else {
if (comparePos(targetLoc.end, start) <= 0) {
}
else {
if (util_1.comparePos(targetLoc.end, start) <= 0) {
return null;
}
if (comparePos(targetLoc.end, end) <= 0) {
if (util_1.comparePos(targetLoc.end, end) <= 0) {
sourceLoc = {

@@ -112,3 +107,2 @@ start: skip("start"),

};
targetLoc = {

@@ -119,4 +113,4 @@ // Same as subtractPos(start, start.line, start.column):

};
} else {
}
else {
sourceLoc = {

@@ -126,3 +120,2 @@ start: skip("start"),

};
targetLoc = {

@@ -135,7 +128,5 @@ // Same as subtractPos(start, start.line, start.column):

}
return new Mapping(this.sourceLines, sourceLoc, targetLoc);
};
Mp.add = function(line, column) {
Mp.add = function (line, column) {
return new Mapping(this.sourceLines, this.sourceLoc, {

@@ -146,3 +137,2 @@ start: addPos(this.targetLoc.start, line, column),

};
function addPos(toPos, line, column) {

@@ -156,4 +146,3 @@ return {

}
Mp.subtract = function(line, column) {
Mp.subtract = function (line, column) {
return new Mapping(this.sourceLines, this.sourceLoc, {

@@ -164,3 +153,2 @@ start: subtractPos(this.targetLoc.start, line, column),

};
function subtractPos(fromPos, line, column) {

@@ -174,16 +162,12 @@ return {

}
Mp.indent = function(by, skipFirstLine, noNegativeColumns) {
Mp.indent = function (by, skipFirstLine, noNegativeColumns) {
if (by === 0) {
return this;
}
var targetLoc = this.targetLoc;
var startLine = targetLoc.start.line;
var endLine = targetLoc.end.line;
if (skipFirstLine && startLine === 1 && endLine === 1) {
return this;
}
targetLoc = {

@@ -193,3 +177,2 @@ start: targetLoc.start,

};
if (!skipFirstLine || startLine > 1) {

@@ -204,3 +187,2 @@ var startColumn = targetLoc.start.column + by;

}
if (!skipFirstLine || endLine > 1) {

@@ -215,17 +197,11 @@ var endColumn = targetLoc.end.column + by;

}
return new Mapping(this.sourceLines, this.sourceLoc, targetLoc);
};
function skipChars(
sourceLines, sourceFromPos,
targetLines, targetFromPos, targetToPos
) {
assert.ok(sourceLines instanceof linesModule.Lines);
assert.ok(targetLines instanceof linesModule.Lines);
function skipChars(sourceLines, sourceFromPos, targetLines, targetFromPos, targetToPos) {
assert_1.default.ok(sourceLines instanceof linesModule.Lines);
assert_1.default.ok(targetLines instanceof linesModule.Lines);
Position.assert(sourceFromPos);
Position.assert(targetFromPos);
Position.assert(targetToPos);
var targetComparison = comparePos(targetFromPos, targetToPos);
var targetComparison = util_1.comparePos(targetFromPos, targetToPos);
if (targetComparison === 0) {

@@ -235,13 +211,9 @@ // Trivial case: no characters to skip.

}
if (targetComparison < 0) {
// Skipping forward.
var sourceCursor = sourceLines.skipSpaces(sourceFromPos);
var targetCursor = targetLines.skipSpaces(targetFromPos);
var lineDiff = targetToPos.line - targetCursor.line;
sourceCursor.line += lineDiff;
targetCursor.line += lineDiff;
if (lineDiff > 0) {

@@ -252,25 +224,19 @@ // If jumping to later lines, reset columns to the beginnings

targetCursor.column = 0;
} else {
assert.strictEqual(lineDiff, 0);
}
while (comparePos(targetCursor, targetToPos) < 0 &&
targetLines.nextPos(targetCursor, true)) {
assert.ok(sourceLines.nextPos(sourceCursor, true));
assert.strictEqual(
sourceLines.charAt(sourceCursor),
targetLines.charAt(targetCursor)
);
else {
assert_1.default.strictEqual(lineDiff, 0);
}
} else {
while (util_1.comparePos(targetCursor, targetToPos) < 0 &&
targetLines.nextPos(targetCursor, true)) {
assert_1.default.ok(sourceLines.nextPos(sourceCursor, true));
assert_1.default.strictEqual(sourceLines.charAt(sourceCursor), targetLines.charAt(targetCursor));
}
}
else {
// Skipping backward.
var sourceCursor = sourceLines.skipSpaces(sourceFromPos, true);
var targetCursor = targetLines.skipSpaces(targetFromPos, true);
var lineDiff = targetToPos.line - targetCursor.line;
sourceCursor.line += lineDiff;
targetCursor.line += lineDiff;
if (lineDiff < 0) {

@@ -281,17 +247,14 @@ // If jumping to earlier lines, reset columns to the ends of

targetCursor.column = targetLines.getLineLength(targetCursor.line);
} else {
assert.strictEqual(lineDiff, 0);
}
while (comparePos(targetToPos, targetCursor) < 0 &&
targetLines.prevPos(targetCursor, true)) {
assert.ok(sourceLines.prevPos(sourceCursor, true));
assert.strictEqual(
sourceLines.charAt(sourceCursor),
targetLines.charAt(targetCursor)
);
else {
assert_1.default.strictEqual(lineDiff, 0);
}
while (util_1.comparePos(targetToPos, targetCursor) < 0 &&
targetLines.prevPos(targetCursor, true)) {
assert_1.default.ok(sourceLines.prevPos(sourceCursor, true));
assert_1.default.strictEqual(sourceLines.charAt(sourceCursor), targetLines.charAt(targetCursor));
}
}
return sourceCursor;
}
module.exports = exports["default"];

@@ -0,130 +1,55 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var defaults = {
// If you want to use a different branch of esprima, or any other module
// that supports a .parse function, pass that module object to
// recast.parse as options.parser (legacy synonym: options.esprima).
parser: require("../parsers/esprima"),
// Number of spaces the pretty-printer should use per tab for
// indentation. If you do not pass this option explicitly, it will be
// (quite reliably!) inferred from the original code.
tabWidth: 4,
// If you really want the pretty-printer to use tabs instead of spaces,
// make this option true.
useTabs: false,
// The reprinting code leaves leading whitespace untouched unless it has
// to reindent a line, or you pass false for this option.
reuseWhitespace: true,
// Override this option to use a different line terminator, e.g. \r\n.
lineTerminator: require("os").EOL || "\n",
// Some of the pretty-printer code (such as that for printing function
// parameter lists) makes a valiant attempt to prevent really long
// lines. You can adjust the limit by changing this option; however,
// there is no guarantee that line length will fit inside this limit.
wrapColumn: 74, // Aspirational for now.
// Pass a string as options.sourceFileName to recast.parse to tell the
// reprinter to keep track of reused code so that it can construct a
// source map automatically.
sourceFileName: null,
// Pass a string as options.sourceMapName to recast.print, and (provided
// you passed options.sourceFileName earlier) the PrintResult of
// recast.print will have a .map property for the generated source map.
sourceMapName: null,
// If provided, this option will be passed along to the source map
// generator as a root directory for relative source file paths.
sourceRoot: null,
// If you provide a source map that was generated from a previous call
// to recast.print as options.inputSourceMap, the old source map will be
// composed with the new source map.
inputSourceMap: null,
// If you want esprima to generate .range information (recast only uses
// .loc internally), pass true for this option.
range: false,
// If you want esprima not to throw exceptions when it encounters
// non-fatal errors, keep this option true.
tolerant: true,
// If you want to override the quotes used in string literals, specify
// either "single", "double", or "auto" here ("auto" will select the one
// which results in the shorter literal) Otherwise, use double quotes.
quote: null,
// Controls the printing of trailing commas in object literals, array
// expressions and function parameters.
//
// This option could either be:
// * Boolean - enable/disable in all contexts (objects, arrays and function params).
// * Object - enable/disable per context.
//
// Example:
// trailingComma: {
// objects: true,
// arrays: true,
// parameters: false,
// }
trailingComma: false,
// Controls the printing of spaces inside array brackets.
// See: http://eslint.org/docs/rules/array-bracket-spacing
arrayBracketSpacing: false,
// Controls the printing of spaces inside object literals,
// destructuring assignments, and import/export specifiers.
// See: http://eslint.org/docs/rules/object-curly-spacing
objectCurlySpacing: true,
// If you want parenthesis to wrap single-argument arrow function
// parameter lists, pass true for this option.
arrowParensAlways: false,
// There are 2 supported syntaxes (`,` and `;`) in Flow Object Types;
// The use of commas is in line with the more popular style and matches
// how objects are defined in JS, making it a bit more natural to write.
flowObjectCommas: true,
// Whether to return an array of .tokens on the root AST node.
tokens: true
parser: require("../parsers/esprima"),
tabWidth: 4,
useTabs: false,
reuseWhitespace: true,
lineTerminator: require("os").EOL || "\n",
wrapColumn: 74,
sourceFileName: null,
sourceMapName: null,
sourceRoot: null,
inputSourceMap: null,
range: false,
tolerant: true,
quote: null,
trailingComma: false,
arrayBracketSpacing: false,
objectCurlySpacing: true,
arrowParensAlways: false,
flowObjectCommas: true,
tokens: true
}, hasOwn = defaults.hasOwnProperty;
// Copy options and fill in default values.
exports.normalize = function(options) {
options = options || defaults;
function get(key) {
return hasOwn.call(options, key)
? options[key]
: defaults[key];
}
return {
tabWidth: +get("tabWidth"),
useTabs: !!get("useTabs"),
reuseWhitespace: !!get("reuseWhitespace"),
lineTerminator: get("lineTerminator"),
wrapColumn: Math.max(get("wrapColumn"), 0),
sourceFileName: get("sourceFileName"),
sourceMapName: get("sourceMapName"),
sourceRoot: get("sourceRoot"),
inputSourceMap: get("inputSourceMap"),
parser: get("esprima") || get("parser"),
range: get("range"),
tolerant: get("tolerant"),
quote: get("quote"),
trailingComma: get("trailingComma"),
arrayBracketSpacing: get("arrayBracketSpacing"),
objectCurlySpacing: get("objectCurlySpacing"),
arrowParensAlways: get("arrowParensAlways"),
flowObjectCommas: get("flowObjectCommas"),
tokens: !!get("tokens")
};
};
function normalize(opts) {
var options = opts || defaults;
function get(key) {
return hasOwn.call(options, key)
? options[key]
: defaults[key];
}
return {
tabWidth: +get("tabWidth"),
useTabs: !!get("useTabs"),
reuseWhitespace: !!get("reuseWhitespace"),
lineTerminator: get("lineTerminator"),
wrapColumn: Math.max(get("wrapColumn"), 0),
sourceFileName: get("sourceFileName"),
sourceMapName: get("sourceMapName"),
sourceRoot: get("sourceRoot"),
inputSourceMap: get("inputSourceMap"),
parser: get("esprima") || get("parser"),
range: get("range"),
tolerant: get("tolerant"),
quote: get("quote"),
trailingComma: get("trailingComma"),
arrayBracketSpacing: get("arrayBracketSpacing"),
objectCurlySpacing: get("objectCurlySpacing"),
arrowParensAlways: get("arrowParensAlways"),
flowObjectCommas: get("flowObjectCommas"),
tokens: !!get("tokens")
};
}
exports.normalize = normalize;
;
"use strict";
var assert = require("assert");
var types = require("./types");
var n = types.namedTypes;
var b = types.builders;
var isObject = types.builtInTypes.object;
var isArray = types.builtInTypes.array;
var isFunction = types.builtInTypes.function;
var Patcher = require("./patcher").Patcher;
var normalizeOptions = require("./options").normalize;
var fromString = require("./lines").fromString;
var attachComments = require("./comments").attach;
var util = require("./util");
exports.parse = function parse(source, options) {
options = normalizeOptions(options);
const lines = fromString(source, options);
const sourceWithoutTabs = lines.toString({
tabWidth: options.tabWidth,
reuseWhitespace: false,
useTabs: false
});
let comments = [];
const ast = options.parser.parse(sourceWithoutTabs, {
jsx: true,
loc: true,
locations: true,
range: options.range,
comment: true,
onComment: comments,
tolerant: util.getOption(options, "tolerant", true),
ecmaVersion: 6,
sourceType: util.getOption(options, "sourceType", "module")
});
// Use ast.tokens if possible, and otherwise fall back to the Esprima
// tokenizer. All the preconfigured ../parsers/* expose ast.tokens
// automatically, but custom parsers might need additional configuration
// to avoid this fallback.
const tokens = Array.isArray(ast.tokens)
? ast.tokens
: require("esprima").tokenize(sourceWithoutTabs, {
loc: true
});
// We will reattach the tokens array to the file object below.
delete ast.tokens;
// Make sure every token has a token.value string.
tokens.forEach(function (token) {
if (typeof token.value !== "string") {
token.value = lines.sliceString(token.loc.start, token.loc.end);
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var types_1 = __importDefault(require("./types"));
var b = types_1.default.builders;
var isObject = types_1.default.builtInTypes.object;
var isArray = types_1.default.builtInTypes.array;
var options_1 = require("./options");
var lines_1 = require("./lines");
var comments_1 = require("./comments");
var util = __importStar(require("./util"));
function parse(source, options) {
options = options_1.normalize(options);
var lines = lines_1.fromString(source, options);
var sourceWithoutTabs = lines.toString({
tabWidth: options.tabWidth,
reuseWhitespace: false,
useTabs: false
});
var comments = [];
var ast = options.parser.parse(sourceWithoutTabs, {
jsx: true,
loc: true,
locations: true,
range: options.range,
comment: true,
onComment: comments,
tolerant: util.getOption(options, "tolerant", true),
ecmaVersion: 6,
sourceType: util.getOption(options, "sourceType", "module")
});
// Use ast.tokens if possible, and otherwise fall back to the Esprima
// tokenizer. All the preconfigured ../parsers/* expose ast.tokens
// automatically, but custom parsers might need additional configuration
// to avoid this fallback.
var tokens = Array.isArray(ast.tokens)
? ast.tokens
: require("esprima").tokenize(sourceWithoutTabs, {
loc: true
});
// We will reattach the tokens array to the file object below.
delete ast.tokens;
// Make sure every token has a token.value string.
tokens.forEach(function (token) {
if (typeof token.value !== "string") {
token.value = lines.sliceString(token.loc.start, token.loc.end);
}
});
if (Array.isArray(ast.comments)) {
comments = ast.comments;
delete ast.comments;
}
});
if (Array.isArray(ast.comments)) {
comments = ast.comments;
delete ast.comments;
}
if (ast.loc) {
// If the source was empty, some parsers give loc.{start,end}.line
// values of 0, instead of the minimum of 1.
util.fixFaultyLocations(ast, lines);
} else {
ast.loc = {
start: lines.firstPos(),
end: lines.lastPos()
};
}
ast.loc.lines = lines;
ast.loc.indent = 0;
let file;
let program;
if (ast.type === "Program") {
program = ast;
// In order to ensure we reprint leading and trailing program
// comments, wrap the original Program node with a File node. Only
// ESTree parsers (Acorn and Esprima) return a Program as the root AST
// node. Most other (Babylon-like) parsers return a File.
file = b.file(ast, options.sourceFileName || null);
file.loc = {
start: lines.firstPos(),
end: lines.lastPos(),
lines: lines,
indent: 0
};
} else if (ast.type === "File") {
file = ast;
program = file.program;
}
// Expose file.tokens unless the caller passed false for options.tokens.
if (options.tokens) {
file.tokens = tokens;
}
// Expand the Program's .loc to include all comments (not just those
// attached to the Program node, as its children may have comments as
// well), since sometimes program.loc.{start,end} will coincide with the
// .loc.{start,end} of the first and last *statements*, mistakenly
// excluding comments that fall outside that region.
var trueProgramLoc = util.getTrueLoc({
type: program.type,
loc: program.loc,
body: [],
comments
}, lines);
program.loc.start = trueProgramLoc.start;
program.loc.end = trueProgramLoc.end;
// Passing file.program here instead of just file means that initial
// comments will be attached to program.body[0] instead of program.
attachComments(
comments,
program.body.length ? file.program : file,
lines
);
// Return a copy of the original AST so that any changes made may be
// compared to the original.
return new TreeCopier(lines, tokens).copy(file);
if (ast.loc) {
// If the source was empty, some parsers give loc.{start,end}.line
// values of 0, instead of the minimum of 1.
util.fixFaultyLocations(ast, lines);
}
else {
ast.loc = {
start: lines.firstPos(),
end: lines.lastPos()
};
}
ast.loc.lines = lines;
ast.loc.indent = 0;
var file;
var program;
if (ast.type === "Program") {
program = ast;
// In order to ensure we reprint leading and trailing program
// comments, wrap the original Program node with a File node. Only
// ESTree parsers (Acorn and Esprima) return a Program as the root AST
// node. Most other (Babylon-like) parsers return a File.
file = b.file(ast, options.sourceFileName || null);
file.loc = {
start: lines.firstPos(),
end: lines.lastPos(),
lines: lines,
indent: 0
};
}
else if (ast.type === "File") {
file = ast;
program = file.program;
}
// Expose file.tokens unless the caller passed false for options.tokens.
if (options.tokens) {
file.tokens = tokens;
}
// Expand the Program's .loc to include all comments (not just those
// attached to the Program node, as its children may have comments as
// well), since sometimes program.loc.{start,end} will coincide with the
// .loc.{start,end} of the first and last *statements*, mistakenly
// excluding comments that fall outside that region.
var trueProgramLoc = util.getTrueLoc({
type: program.type,
loc: program.loc,
body: [],
comments: comments
}, lines);
program.loc.start = trueProgramLoc.start;
program.loc.end = trueProgramLoc.end;
// Passing file.program here instead of just file means that initial
// comments will be attached to program.body[0] instead of program.
comments_1.attach(comments, program.body.length ? file.program : file, lines);
// Return a copy of the original AST so that any changes made may be
// compared to the original.
return new TreeCopier(lines, tokens).copy(file);
}
exports.parse = parse;
;
var TreeCopier = function TreeCopier(lines, tokens) {
assert_1.default.ok(this instanceof TreeCopier);
this.lines = lines;
this.tokens = tokens;
this.startTokenIndex = 0;
this.endTokenIndex = tokens.length;
this.indent = 0;
this.seen = new Map;
};
function TreeCopier(lines, tokens) {
assert.ok(this instanceof TreeCopier);
this.lines = lines;
this.tokens = tokens;
this.startTokenIndex = 0;
this.endTokenIndex = tokens.length;
this.indent = 0;
this.seen = new Map;
}
var TCp = TreeCopier.prototype;
TCp.copy = function(node) {
if (this.seen.has(node)) {
return this.seen.get(node);
}
if (isArray.check(node)) {
var copy = new Array(node.length);
TCp.copy = function (node) {
if (this.seen.has(node)) {
return this.seen.get(node);
}
if (isArray.check(node)) {
var copy = new Array(node.length);
this.seen.set(node, copy);
node.forEach(function (item, i) {
copy[i] = this.copy(item);
}, this);
return copy;
}
if (!isObject.check(node)) {
return node;
}
util.fixFaultyLocations(node, this.lines);
var copy = Object.create(Object.getPrototypeOf(node), {
original: {
value: node,
configurable: false,
enumerable: false,
writable: true
}
});
this.seen.set(node, copy);
node.forEach(function (item, i) {
copy[i] = this.copy(item);
}, this);
return copy;
}
if (!isObject.check(node)) {
return node;
}
util.fixFaultyLocations(node, this.lines);
var copy = Object.create(Object.getPrototypeOf(node), {
original: { // Provide a link from the copy to the original.
value: node,
configurable: false,
enumerable: false,
writable: true
var loc = node.loc;
var oldIndent = this.indent;
var newIndent = oldIndent;
var oldStartTokenIndex = this.startTokenIndex;
var oldEndTokenIndex = this.endTokenIndex;
if (loc) {
// When node is a comment, we set node.loc.indent to
// node.loc.start.column so that, when/if we print the comment by
// itself, we can strip that much whitespace from the left margin of
// the comment. This only really matters for multiline Block comments,
// but it doesn't hurt for Line comments.
if (node.type === "Block" || node.type === "Line" ||
node.type === "CommentBlock" || node.type === "CommentLine" ||
this.lines.isPrecededOnlyByWhitespace(loc.start)) {
newIndent = this.indent = loc.start.column;
}
// Every node.loc has a reference to the original source lines as well
// as a complete list of source tokens.
loc.lines = this.lines;
loc.tokens = this.tokens;
loc.indent = newIndent;
// Set loc.start.token and loc.end.token such that
// loc.tokens.slice(loc.start.token, loc.end.token) returns a list of
// all the tokens that make up this node.
this.findTokenRange(loc);
}
});
this.seen.set(node, copy);
var loc = node.loc;
var oldIndent = this.indent;
var newIndent = oldIndent;
const oldStartTokenIndex = this.startTokenIndex;
const oldEndTokenIndex = this.endTokenIndex;
if (loc) {
// When node is a comment, we set node.loc.indent to
// node.loc.start.column so that, when/if we print the comment by
// itself, we can strip that much whitespace from the left margin of
// the comment. This only really matters for multiline Block comments,
// but it doesn't hurt for Line comments.
if (node.type === "Block" || node.type === "Line" ||
node.type === "CommentBlock" || node.type === "CommentLine" ||
this.lines.isPrecededOnlyByWhitespace(loc.start)) {
newIndent = this.indent = loc.start.column;
var keys = Object.keys(node);
var keyCount = keys.length;
for (var i = 0; i < keyCount; ++i) {
var key = keys[i];
if (key === "loc") {
copy[key] = node[key];
}
else if (key === "tokens" &&
node.type === "File") {
// Preserve file.tokens (uncopied) in case client code cares about
// it, even though Recast ignores it when reprinting.
copy[key] = node[key];
}
else {
copy[key] = this.copy(node[key]);
}
}
// Every node.loc has a reference to the original source lines as well
// as a complete list of source tokens.
loc.lines = this.lines;
loc.tokens = this.tokens;
loc.indent = newIndent;
// Set loc.start.token and loc.end.token such that
// loc.tokens.slice(loc.start.token, loc.end.token) returns a list of
// all the tokens that make up this node.
this.findTokenRange(loc);
}
var keys = Object.keys(node);
var keyCount = keys.length;
for (var i = 0; i < keyCount; ++i) {
var key = keys[i];
if (key === "loc") {
copy[key] = node[key];
} else if (key === "tokens" &&
node.type === "File") {
// Preserve file.tokens (uncopied) in case client code cares about
// it, even though Recast ignores it when reprinting.
copy[key] = node[key];
} else {
copy[key] = this.copy(node[key]);
}
}
this.indent = oldIndent;
this.startTokenIndex = oldStartTokenIndex;
this.endTokenIndex = oldEndTokenIndex;
return copy;
this.indent = oldIndent;
this.startTokenIndex = oldStartTokenIndex;
this.endTokenIndex = oldEndTokenIndex;
return copy;
};
// If we didn't have any idea where in loc.tokens to look for tokens

@@ -234,45 +211,48 @@ // contained by this loc, a binary search would be appropriate, but

TCp.findTokenRange = function (loc) {
// In the unlikely event that loc.tokens[this.startTokenIndex] starts
// *after* loc.start, we need to rewind this.startTokenIndex first.
while (this.startTokenIndex > 0) {
const token = loc.tokens[this.startTokenIndex];
if (util.comparePos(loc.start, token.loc.start) < 0) {
--this.startTokenIndex;
} else break;
}
// In the unlikely event that loc.tokens[this.endTokenIndex - 1] ends
// *before* loc.end, we need to fast-forward this.endTokenIndex first.
while (this.endTokenIndex < loc.tokens.length) {
const token = loc.tokens[this.endTokenIndex];
if (util.comparePos(token.loc.end, loc.end) < 0) {
++this.endTokenIndex;
} else break;
}
// Increment this.startTokenIndex until we've found the first token
// contained by this node.
while (this.startTokenIndex < this.endTokenIndex) {
const token = loc.tokens[this.startTokenIndex];
if (util.comparePos(token.loc.start, loc.start) < 0) {
++this.startTokenIndex;
} else break;
}
// Index into loc.tokens of the first token within this node.
loc.start.token = this.startTokenIndex;
// Decrement this.endTokenIndex until we've found the first token after
// this node (not contained by the node).
while (this.endTokenIndex > this.startTokenIndex) {
const token = loc.tokens[this.endTokenIndex - 1];
if (util.comparePos(loc.end, token.loc.end) < 0) {
--this.endTokenIndex;
} else break;
}
// Index into loc.tokens of the first token *after* this node.
// If loc.start.token === loc.end.token, the node contains no tokens,
// and the index is that of the next token following this node.
loc.end.token = this.endTokenIndex;
// In the unlikely event that loc.tokens[this.startTokenIndex] starts
// *after* loc.start, we need to rewind this.startTokenIndex first.
while (this.startTokenIndex > 0) {
var token = loc.tokens[this.startTokenIndex];
if (util.comparePos(loc.start, token.loc.start) < 0) {
--this.startTokenIndex;
}
else
break;
}
// In the unlikely event that loc.tokens[this.endTokenIndex - 1] ends
// *before* loc.end, we need to fast-forward this.endTokenIndex first.
while (this.endTokenIndex < loc.tokens.length) {
var token = loc.tokens[this.endTokenIndex];
if (util.comparePos(token.loc.end, loc.end) < 0) {
++this.endTokenIndex;
}
else
break;
}
// Increment this.startTokenIndex until we've found the first token
// contained by this node.
while (this.startTokenIndex < this.endTokenIndex) {
var token = loc.tokens[this.startTokenIndex];
if (util.comparePos(token.loc.start, loc.start) < 0) {
++this.startTokenIndex;
}
else
break;
}
// Index into loc.tokens of the first token within this node.
loc.start.token = this.startTokenIndex;
// Decrement this.endTokenIndex until we've found the first token after
// this node (not contained by the node).
while (this.endTokenIndex > this.startTokenIndex) {
var token = loc.tokens[this.endTokenIndex - 1];
if (util.comparePos(loc.end, token.loc.end) < 0) {
--this.endTokenIndex;
}
else
break;
}
// Index into loc.tokens of the first token *after* this node.
// If loc.start.token === loc.end.token, the node contains no tokens,
// and the index is that of the next token following this node.
loc.end.token = this.endTokenIndex;
};

@@ -1,111 +0,96 @@

var assert = require("assert");
var linesModule = require("./lines");
var types = require("./types");
var getFieldValue = types.getFieldValue;
var Node = types.namedTypes.Node;
var Printable = types.namedTypes.Printable;
var Expression = types.namedTypes.Expression;
var ReturnStatement = types.namedTypes.ReturnStatement;
var SourceLocation = types.namedTypes.SourceLocation;
var util = require("./util");
var comparePos = util.comparePos;
var FastPath = require("./fast-path");
var isObject = types.builtInTypes.object;
var isArray = types.builtInTypes.array;
var isString = types.builtInTypes.string;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var linesModule = __importStar(require("./lines"));
var types_1 = __importDefault(require("./types"));
var Printable = types_1.default.namedTypes.Printable;
var Expression = types_1.default.namedTypes.Expression;
var ReturnStatement = types_1.default.namedTypes.ReturnStatement;
var SourceLocation = types_1.default.namedTypes.SourceLocation;
var util_1 = require("./util");
var fast_path_1 = __importDefault(require("./fast-path"));
var isObject = types_1.default.builtInTypes.object;
var isArray = types_1.default.builtInTypes.array;
var isString = types_1.default.builtInTypes.string;
var riskyAdjoiningCharExp = /[0-9a-z_$]/i;
function Patcher(lines) {
assert.ok(this instanceof Patcher);
assert.ok(lines instanceof linesModule.Lines);
var self = this,
replacements = [];
self.replace = function(loc, lines) {
if (isString.check(lines))
lines = linesModule.fromString(lines);
replacements.push({
lines: lines,
start: loc.start,
end: loc.end
});
};
self.get = function(loc) {
// If no location is provided, return the complete Lines object.
loc = loc || {
start: { line: 1, column: 0 },
end: { line: lines.length,
column: lines.getLineLength(lines.length) }
var Patcher = function Patcher(lines) {
assert_1.default.ok(this instanceof Patcher);
assert_1.default.ok(lines instanceof linesModule.Lines);
var self = this, replacements = [];
self.replace = function (loc, lines) {
if (isString.check(lines))
lines = linesModule.fromString(lines);
replacements.push({
lines: lines,
start: loc.start,
end: loc.end
});
};
var sliceFrom = loc.start,
toConcat = [];
function pushSlice(from, to) {
assert.ok(comparePos(from, to) <= 0);
toConcat.push(lines.slice(from, to));
}
replacements.sort(function(a, b) {
return comparePos(a.start, b.start);
}).forEach(function(rep) {
if (comparePos(sliceFrom, rep.start) > 0) {
// Ignore nested replacement ranges.
} else {
pushSlice(sliceFrom, rep.start);
toConcat.push(rep.lines);
sliceFrom = rep.end;
}
});
pushSlice(sliceFrom, loc.end);
return linesModule.concat(toConcat);
};
}
self.get = function (loc) {
// If no location is provided, return the complete Lines object.
loc = loc || {
start: { line: 1, column: 0 },
end: { line: lines.length,
column: lines.getLineLength(lines.length) }
};
var sliceFrom = loc.start, toConcat = [];
function pushSlice(from, to) {
assert_1.default.ok(util_1.comparePos(from, to) <= 0);
toConcat.push(lines.slice(from, to));
}
replacements.sort(function (a, b) {
return util_1.comparePos(a.start, b.start);
}).forEach(function (rep) {
if (util_1.comparePos(sliceFrom, rep.start) > 0) {
// Ignore nested replacement ranges.
}
else {
pushSlice(sliceFrom, rep.start);
toConcat.push(rep.lines);
sliceFrom = rep.end;
}
});
pushSlice(sliceFrom, loc.end);
return linesModule.concat(toConcat);
};
};
exports.Patcher = Patcher;
var Pp = Patcher.prototype;
Pp.tryToReprintComments = function(newNode, oldNode, print) {
var patcher = this;
if (!newNode.comments &&
!oldNode.comments) {
// We were (vacuously) able to reprint all the comments!
return true;
}
var newPath = FastPath.from(newNode);
var oldPath = FastPath.from(oldNode);
newPath.stack.push("comments", getSurroundingComments(newNode));
oldPath.stack.push("comments", getSurroundingComments(oldNode));
var reprints = [];
var ableToReprintComments =
findArrayReprints(newPath, oldPath, reprints);
// No need to pop anything from newPath.stack or oldPath.stack, since
// newPath and oldPath are fresh local variables.
if (ableToReprintComments && reprints.length > 0) {
reprints.forEach(function(reprint) {
var oldComment = reprint.oldPath.getValue();
assert.ok(oldComment.leading || oldComment.trailing);
patcher.replace(
oldComment.loc,
// Comments can't have .comments, so it doesn't matter whether we
// print with comments or without.
print(reprint.newPath).indentTail(oldComment.loc.indent)
);
});
}
return ableToReprintComments;
Pp.tryToReprintComments = function (newNode, oldNode, print) {
var patcher = this;
if (!newNode.comments &&
!oldNode.comments) {
// We were (vacuously) able to reprint all the comments!
return true;
}
var newPath = fast_path_1.default.from(newNode);
var oldPath = fast_path_1.default.from(oldNode);
newPath.stack.push("comments", getSurroundingComments(newNode));
oldPath.stack.push("comments", getSurroundingComments(oldNode));
var reprints = [];
var ableToReprintComments = findArrayReprints(newPath, oldPath, reprints);
// No need to pop anything from newPath.stack or oldPath.stack, since
// newPath and oldPath are fresh local variables.
if (ableToReprintComments && reprints.length > 0) {
reprints.forEach(function (reprint) {
var oldComment = reprint.oldPath.getValue();
assert_1.default.ok(oldComment.leading || oldComment.trailing);
patcher.replace(oldComment.loc,
// Comments can't have .comments, so it doesn't matter whether we
// print with comments or without.
print(reprint.newPath).indentTail(oldComment.loc.indent));
});
}
return ableToReprintComments;
};
// Get all comments that are either leading or trailing, ignoring any

@@ -115,122 +100,101 @@ // comments that occur inside node.loc. Returns an empty array for nodes

function getSurroundingComments(node) {
var result = [];
if (node.comments &&
node.comments.length > 0) {
node.comments.forEach(function(comment) {
if (comment.leading || comment.trailing) {
result.push(comment);
}
});
}
return result;
var result = [];
if (node.comments &&
node.comments.length > 0) {
node.comments.forEach(function (comment) {
if (comment.leading || comment.trailing) {
result.push(comment);
}
});
}
return result;
}
Pp.deleteComments = function(node) {
if (!node.comments) {
return;
}
var patcher = this;
node.comments.forEach(function(comment) {
if (comment.leading) {
// Delete leading comments along with any trailing whitespace they
// might have.
patcher.replace({
start: comment.loc.start,
end: node.loc.lines.skipSpaces(
comment.loc.end, false, false)
}, "");
} else if (comment.trailing) {
// Delete trailing comments along with any leading whitespace they
// might have.
patcher.replace({
start: node.loc.lines.skipSpaces(
comment.loc.start, true, false),
end: comment.loc.end
}, "");
Pp.deleteComments = function (node) {
if (!node.comments) {
return;
}
});
};
exports.getReprinter = function(path) {
assert.ok(path instanceof FastPath);
// Make sure that this path refers specifically to a Node, rather than
// some non-Node subproperty of a Node.
var node = path.getValue();
if (!Printable.check(node))
return;
var orig = node.original;
var origLoc = orig && orig.loc;
var lines = origLoc && origLoc.lines;
var reprints = [];
if (!lines || !findReprints(path, reprints))
return;
return function(print) {
var patcher = new Patcher(lines);
reprints.forEach(function(reprint) {
var newNode = reprint.newPath.getValue();
var oldNode = reprint.oldPath.getValue();
SourceLocation.assert(oldNode.loc, true);
var needToPrintNewPathWithComments =
!patcher.tryToReprintComments(newNode, oldNode, print)
if (needToPrintNewPathWithComments) {
// Since we were not able to preserve all leading/trailing
// comments, we delete oldNode's comments, print newPath with
// comments, and then patch the resulting lines where oldNode used
// to be.
patcher.deleteComments(oldNode);
}
var newLines = print(reprint.newPath, {
includeComments: needToPrintNewPathWithComments,
// If the oldNode we're replacing already had parentheses, we may
// not need to print the new node with any extra parentheses,
// because the existing parentheses will suffice. However, if the
// newNode has a different type than the oldNode, let the printer
// decide if reprint.newPath needs parentheses, as usual.
avoidRootParens: (oldNode.type === newNode.type &&
reprint.oldPath.hasParens())
}).indentTail(oldNode.loc.indent);
var nls = needsLeadingSpace(lines, oldNode.loc, newLines);
var nts = needsTrailingSpace(lines, oldNode.loc, newLines);
// If we try to replace the argument of a ReturnStatement like
// return"asdf" with e.g. a literal null expression, we run the risk
// of ending up with returnnull, so we need to add an extra leading
// space in situations where that might happen. Likewise for
// "asdf"in obj. See #170.
if (nls || nts) {
var newParts = [];
nls && newParts.push(" ");
newParts.push(newLines);
nts && newParts.push(" ");
newLines = linesModule.concat(newParts);
}
patcher.replace(oldNode.loc, newLines);
var patcher = this;
node.comments.forEach(function (comment) {
if (comment.leading) {
// Delete leading comments along with any trailing whitespace they
// might have.
patcher.replace({
start: comment.loc.start,
end: node.loc.lines.skipSpaces(comment.loc.end, false, false)
}, "");
}
else if (comment.trailing) {
// Delete trailing comments along with any leading whitespace they
// might have.
patcher.replace({
start: node.loc.lines.skipSpaces(comment.loc.start, true, false),
end: comment.loc.end
}, "");
}
});
// Recall that origLoc is the .loc of an ancestor node that is
// guaranteed to contain all the reprinted nodes and comments.
const patchedLines = patcher.get(origLoc).indentTail(-orig.loc.indent);
if (path.needsParens()) {
return linesModule.concat(["(", patchedLines, ")"]);
}
return patchedLines;
};
};
function getReprinter(path) {
assert_1.default.ok(path instanceof fast_path_1.default);
// Make sure that this path refers specifically to a Node, rather than
// some non-Node subproperty of a Node.
var node = path.getValue();
if (!Printable.check(node))
return;
var orig = node.original;
var origLoc = orig && orig.loc;
var lines = origLoc && origLoc.lines;
var reprints = [];
if (!lines || !findReprints(path, reprints))
return;
return function (print) {
var patcher = new Patcher(lines);
reprints.forEach(function (reprint) {
var newNode = reprint.newPath.getValue();
var oldNode = reprint.oldPath.getValue();
SourceLocation.assert(oldNode.loc, true);
var needToPrintNewPathWithComments = !patcher.tryToReprintComments(newNode, oldNode, print);
if (needToPrintNewPathWithComments) {
// Since we were not able to preserve all leading/trailing
// comments, we delete oldNode's comments, print newPath with
// comments, and then patch the resulting lines where oldNode used
// to be.
patcher.deleteComments(oldNode);
}
var newLines = print(reprint.newPath, {
includeComments: needToPrintNewPathWithComments,
// If the oldNode we're replacing already had parentheses, we may
// not need to print the new node with any extra parentheses,
// because the existing parentheses will suffice. However, if the
// newNode has a different type than the oldNode, let the printer
// decide if reprint.newPath needs parentheses, as usual.
avoidRootParens: (oldNode.type === newNode.type &&
reprint.oldPath.hasParens())
}).indentTail(oldNode.loc.indent);
var nls = needsLeadingSpace(lines, oldNode.loc, newLines);
var nts = needsTrailingSpace(lines, oldNode.loc, newLines);
// If we try to replace the argument of a ReturnStatement like
// return"asdf" with e.g. a literal null expression, we run the risk
// of ending up with returnnull, so we need to add an extra leading
// space in situations where that might happen. Likewise for
// "asdf"in obj. See #170.
if (nls || nts) {
var newParts = [];
nls && newParts.push(" ");
newParts.push(newLines);
nts && newParts.push(" ");
newLines = linesModule.concat(newParts);
}
patcher.replace(oldNode.loc, newLines);
});
// Recall that origLoc is the .loc of an ancestor node that is
// guaranteed to contain all the reprinted nodes and comments.
var patchedLines = patcher.get(origLoc).indentTail(-orig.loc.indent);
if (path.needsParens()) {
return linesModule.concat(["(", patchedLines, ")"]);
}
return patchedLines;
};
}
exports.getReprinter = getReprinter;
;
// If the last character before oldLoc and the first character of newLines

@@ -240,18 +204,13 @@ // are both identifier characters, they must be separated by a space,

function needsLeadingSpace(oldLines, oldLoc, newLines) {
var posBeforeOldLoc = util.copyPos(oldLoc.start);
// The character just before the location occupied by oldNode.
var charBeforeOldLoc =
oldLines.prevPos(posBeforeOldLoc) &&
oldLines.charAt(posBeforeOldLoc);
// First character of the reprinted node.
var newFirstChar = newLines.charAt(newLines.firstPos());
return charBeforeOldLoc &&
riskyAdjoiningCharExp.test(charBeforeOldLoc) &&
newFirstChar &&
riskyAdjoiningCharExp.test(newFirstChar);
var posBeforeOldLoc = util_1.copyPos(oldLoc.start);
// The character just before the location occupied by oldNode.
var charBeforeOldLoc = oldLines.prevPos(posBeforeOldLoc) &&
oldLines.charAt(posBeforeOldLoc);
// First character of the reprinted node.
var newFirstChar = newLines.charAt(newLines.firstPos());
return charBeforeOldLoc &&
riskyAdjoiningCharExp.test(charBeforeOldLoc) &&
newFirstChar &&
riskyAdjoiningCharExp.test(newFirstChar);
}
// If the last character of newLines and the first character after oldLoc

@@ -261,222 +220,176 @@ // are both identifier characters, they must be separated by a space,

function needsTrailingSpace(oldLines, oldLoc, newLines) {
// The character just after the location occupied by oldNode.
var charAfterOldLoc = oldLines.charAt(oldLoc.end);
var newLastPos = newLines.lastPos();
// Last character of the reprinted node.
var newLastChar = newLines.prevPos(newLastPos) &&
newLines.charAt(newLastPos);
return newLastChar &&
riskyAdjoiningCharExp.test(newLastChar) &&
charAfterOldLoc &&
riskyAdjoiningCharExp.test(charAfterOldLoc);
// The character just after the location occupied by oldNode.
var charAfterOldLoc = oldLines.charAt(oldLoc.end);
var newLastPos = newLines.lastPos();
// Last character of the reprinted node.
var newLastChar = newLines.prevPos(newLastPos) &&
newLines.charAt(newLastPos);
return newLastChar &&
riskyAdjoiningCharExp.test(newLastChar) &&
charAfterOldLoc &&
riskyAdjoiningCharExp.test(charAfterOldLoc);
}
function findReprints(newPath, reprints) {
var newNode = newPath.getValue();
Printable.assert(newNode);
var oldNode = newNode.original;
Printable.assert(oldNode);
assert.deepEqual(reprints, []);
if (newNode.type !== oldNode.type) {
return false;
}
var oldPath = new FastPath(oldNode);
var canReprint = findChildReprints(newPath, oldPath, reprints);
if (!canReprint) {
// Make absolutely sure the calling code does not attempt to reprint
// any nodes.
reprints.length = 0;
}
return canReprint;
var newNode = newPath.getValue();
Printable.assert(newNode);
var oldNode = newNode.original;
Printable.assert(oldNode);
assert_1.default.deepEqual(reprints, []);
if (newNode.type !== oldNode.type) {
return false;
}
var oldPath = new fast_path_1.default(oldNode);
var canReprint = findChildReprints(newPath, oldPath, reprints);
if (!canReprint) {
// Make absolutely sure the calling code does not attempt to reprint
// any nodes.
reprints.length = 0;
}
return canReprint;
}
function findAnyReprints(newPath, oldPath, reprints) {
var newNode = newPath.getValue();
var oldNode = oldPath.getValue();
if (newNode === oldNode)
return true;
if (isArray.check(newNode))
return findArrayReprints(newPath, oldPath, reprints);
if (isObject.check(newNode))
return findObjectReprints(newPath, oldPath, reprints);
return false;
var newNode = newPath.getValue();
var oldNode = oldPath.getValue();
if (newNode === oldNode)
return true;
if (isArray.check(newNode))
return findArrayReprints(newPath, oldPath, reprints);
if (isObject.check(newNode))
return findObjectReprints(newPath, oldPath, reprints);
return false;
}
function findArrayReprints(newPath, oldPath, reprints) {
var newNode = newPath.getValue();
var oldNode = oldPath.getValue();
if (newNode === oldNode ||
newPath.valueIsDuplicate() ||
oldPath.valueIsDuplicate()) {
return true;
}
isArray.assert(newNode);
var len = newNode.length;
if (!(isArray.check(oldNode) &&
var newNode = newPath.getValue();
var oldNode = oldPath.getValue();
if (newNode === oldNode ||
newPath.valueIsDuplicate() ||
oldPath.valueIsDuplicate()) {
return true;
}
isArray.assert(newNode);
var len = newNode.length;
if (!(isArray.check(oldNode) &&
oldNode.length === len))
return false;
for (var i = 0; i < len; ++i) {
newPath.stack.push(i, newNode[i]);
oldPath.stack.push(i, oldNode[i]);
var canReprint = findAnyReprints(newPath, oldPath, reprints);
newPath.stack.length -= 2;
oldPath.stack.length -= 2;
if (!canReprint) {
return false;
return false;
for (var i = 0; i < len; ++i) {
newPath.stack.push(i, newNode[i]);
oldPath.stack.push(i, oldNode[i]);
var canReprint = findAnyReprints(newPath, oldPath, reprints);
newPath.stack.length -= 2;
oldPath.stack.length -= 2;
if (!canReprint) {
return false;
}
}
}
return true;
return true;
}
function findObjectReprints(newPath, oldPath, reprints) {
var newNode = newPath.getValue();
isObject.assert(newNode);
if (newNode.original === null) {
// If newNode.original node was set to null, reprint the node.
return false;
}
var oldNode = oldPath.getValue();
if (!isObject.check(oldNode))
return false;
if (newNode === oldNode ||
newPath.valueIsDuplicate() ||
oldPath.valueIsDuplicate()) {
return true;
}
if (Printable.check(newNode)) {
if (!Printable.check(oldNode)) {
return false;
var newNode = newPath.getValue();
isObject.assert(newNode);
if (newNode.original === null) {
// If newNode.original node was set to null, reprint the node.
return false;
}
// Here we need to decide whether the reprinted code for newNode is
// appropriate for patching into the location of oldNode.
if (newNode.type === oldNode.type) {
var childReprints = [];
if (findChildReprints(newPath, oldPath, childReprints)) {
reprints.push.apply(reprints, childReprints);
} else if (oldNode.loc) {
// If we have no .loc information for oldNode, then we won't be
// able to reprint it.
reprints.push({
oldPath: oldPath.copy(),
newPath: newPath.copy()
});
} else {
var oldNode = oldPath.getValue();
if (!isObject.check(oldNode))
return false;
}
return true;
if (newNode === oldNode ||
newPath.valueIsDuplicate() ||
oldPath.valueIsDuplicate()) {
return true;
}
if (Expression.check(newNode) &&
Expression.check(oldNode) &&
// If we have no .loc information for oldNode, then we won't be
// able to reprint it.
oldNode.loc) {
// If both nodes are subtypes of Expression, then we should be able
// to fill the location occupied by the old node with code printed
// for the new node with no ill consequences.
reprints.push({
oldPath: oldPath.copy(),
newPath: newPath.copy()
});
return true;
if (Printable.check(newNode)) {
if (!Printable.check(oldNode)) {
return false;
}
// Here we need to decide whether the reprinted code for newNode is
// appropriate for patching into the location of oldNode.
if (newNode.type === oldNode.type) {
var childReprints = [];
if (findChildReprints(newPath, oldPath, childReprints)) {
reprints.push.apply(reprints, childReprints);
}
else if (oldNode.loc) {
// If we have no .loc information for oldNode, then we won't be
// able to reprint it.
reprints.push({
oldPath: oldPath.copy(),
newPath: newPath.copy()
});
}
else {
return false;
}
return true;
}
if (Expression.check(newNode) &&
Expression.check(oldNode) &&
// If we have no .loc information for oldNode, then we won't be
// able to reprint it.
oldNode.loc) {
// If both nodes are subtypes of Expression, then we should be able
// to fill the location occupied by the old node with code printed
// for the new node with no ill consequences.
reprints.push({
oldPath: oldPath.copy(),
newPath: newPath.copy()
});
return true;
}
// The nodes have different types, and at least one of the types is
// not a subtype of the Expression type, so we cannot safely assume
// the nodes are syntactically interchangeable.
return false;
}
// The nodes have different types, and at least one of the types is
// not a subtype of the Expression type, so we cannot safely assume
// the nodes are syntactically interchangeable.
return false;
}
return findChildReprints(newPath, oldPath, reprints);
return findChildReprints(newPath, oldPath, reprints);
}
function findChildReprints(newPath, oldPath, reprints) {
var newNode = newPath.getValue();
var oldNode = oldPath.getValue();
isObject.assert(newNode);
isObject.assert(oldNode);
if (newNode.original === null) {
// If newNode.original node was set to null, reprint the node.
return false;
}
// If this node needs parentheses and will not be wrapped with
// parentheses when reprinted, then return false to skip reprinting and
// let it be printed generically.
if (newPath.needsParens() &&
! oldPath.hasParens()) {
return false;
}
var keys = util.getUnionOfKeys(oldNode, newNode);
if (oldNode.type === "File" ||
newNode.type === "File") {
// Don't bother traversing file.tokens, an often very large array
// returned by Babylon, and useless for our purposes.
delete keys.tokens;
}
// Don't bother traversing .loc objects looking for reprintable nodes.
delete keys.loc;
var originalReprintCount = reprints.length;
for (var k in keys) {
if (k.charAt(0) === "_") {
// Ignore "private" AST properties added by e.g. Babel plugins and
// parsers like Babylon.
continue;
var newNode = newPath.getValue();
var oldNode = oldPath.getValue();
isObject.assert(newNode);
isObject.assert(oldNode);
if (newNode.original === null) {
// If newNode.original node was set to null, reprint the node.
return false;
}
newPath.stack.push(k, types.getFieldValue(newNode, k));
oldPath.stack.push(k, types.getFieldValue(oldNode, k));
var canReprint = findAnyReprints(newPath, oldPath, reprints);
newPath.stack.length -= 2;
oldPath.stack.length -= 2;
if (!canReprint) {
return false;
// If this node needs parentheses and will not be wrapped with
// parentheses when reprinted, then return false to skip reprinting and
// let it be printed generically.
if (newPath.needsParens() &&
!oldPath.hasParens()) {
return false;
}
}
// Return statements might end up running into ASI issues due to
// comments inserted deep within the tree, so reprint them if anything
// changed within them.
if (ReturnStatement.check(newPath.getNode()) &&
reprints.length > originalReprintCount) {
return false;
}
return true;
var keys = util_1.getUnionOfKeys(oldNode, newNode);
if (oldNode.type === "File" ||
newNode.type === "File") {
// Don't bother traversing file.tokens, an often very large array
// returned by Babylon, and useless for our purposes.
delete keys.tokens;
}
// Don't bother traversing .loc objects looking for reprintable nodes.
delete keys.loc;
var originalReprintCount = reprints.length;
for (var k in keys) {
if (k.charAt(0) === "_") {
// Ignore "private" AST properties added by e.g. Babel plugins and
// parsers like Babylon.
continue;
}
newPath.stack.push(k, types_1.default.getFieldValue(newNode, k));
oldPath.stack.push(k, types_1.default.getFieldValue(oldNode, k));
var canReprint = findAnyReprints(newPath, oldPath, reprints);
newPath.stack.length -= 2;
oldPath.stack.length -= 2;
if (!canReprint) {
return false;
}
}
// Return statements might end up running into ASI issues due to
// comments inserted deep within the tree, so reprint them if anything
// changed within them.
if (ReturnStatement.check(newPath.getNode()) &&
reprints.length > originalReprintCount) {
return false;
}
return true;
}

@@ -0,1 +1,9 @@

"use strict";;
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// This module was originally created so that Recast could add its own

@@ -5,2 +13,5 @@ // custom types to the AST type system (in particular, the File type), but

// have much to do anymore. Still, it might prove useful in the future.
module.exports = require("ast-types");
var ast_types_1 = __importDefault(require("ast-types"));
exports.default = ast_types_1.default;
__export(require("ast-types"));
module.exports = exports["default"];

@@ -1,354 +0,332 @@

var assert = require("assert");
var types = require("./types");
var getFieldValue = types.getFieldValue;
var n = types.namedTypes;
var sourceMap = require("source-map");
var SourceMapConsumer = sourceMap.SourceMapConsumer;
var SourceMapGenerator = sourceMap.SourceMapGenerator;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var assert_1 = __importDefault(require("assert"));
var types_1 = __importDefault(require("./types"));
var n = types_1.default.namedTypes;
var source_map_1 = __importDefault(require("source-map"));
var SourceMapConsumer = source_map_1.default.SourceMapConsumer;
var SourceMapGenerator = source_map_1.default.SourceMapGenerator;
var hasOwn = Object.prototype.hasOwnProperty;
var util = exports;
function getOption(options, key, defaultValue) {
if (options && hasOwn.call(options, key)) {
return options[key];
}
return defaultValue;
if (options && hasOwn.call(options, key)) {
return options[key];
}
return defaultValue;
}
util.getOption = getOption;
exports.getOption = getOption;
function getUnionOfKeys() {
var result = {};
var argc = arguments.length;
for (var i = 0; i < argc; ++i) {
var keys = Object.keys(arguments[i]);
var keyCount = keys.length;
for (var j = 0; j < keyCount; ++j) {
result[keys[j]] = true;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
}
return result;
var result = {};
var argc = args.length;
for (var i = 0; i < argc; ++i) {
var keys = Object.keys(args[i]);
var keyCount = keys.length;
for (var j = 0; j < keyCount; ++j) {
result[keys[j]] = true;
}
}
return result;
}
util.getUnionOfKeys = getUnionOfKeys;
exports.getUnionOfKeys = getUnionOfKeys;
function comparePos(pos1, pos2) {
return (pos1.line - pos2.line) || (pos1.column - pos2.column);
return (pos1.line - pos2.line) || (pos1.column - pos2.column);
}
util.comparePos = comparePos;
exports.comparePos = comparePos;
function copyPos(pos) {
return {
line: pos.line,
column: pos.column
};
return {
line: pos.line,
column: pos.column
};
}
util.copyPos = copyPos;
util.composeSourceMaps = function(formerMap, latterMap) {
if (formerMap) {
if (!latterMap) {
return formerMap;
exports.copyPos = copyPos;
function composeSourceMaps(formerMap, latterMap) {
if (formerMap) {
if (!latterMap) {
return formerMap;
}
}
} else {
return latterMap || null;
}
var smcFormer = new SourceMapConsumer(formerMap);
var smcLatter = new SourceMapConsumer(latterMap);
var smg = new SourceMapGenerator({
file: latterMap.file,
sourceRoot: latterMap.sourceRoot
});
var sourcesToContents = {};
smcLatter.eachMapping(function(mapping) {
var origPos = smcFormer.originalPositionFor({
line: mapping.originalLine,
column: mapping.originalColumn
});
var sourceName = origPos.source;
if (sourceName === null) {
return;
else {
return latterMap || null;
}
smg.addMapping({
source: sourceName,
original: copyPos(origPos),
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn
},
name: mapping.name
var smcFormer = new SourceMapConsumer(formerMap);
var smcLatter = new SourceMapConsumer(latterMap);
var smg = new SourceMapGenerator({
file: latterMap.file,
sourceRoot: latterMap.sourceRoot
});
var sourceContent = smcFormer.sourceContentFor(sourceName);
if (sourceContent && !hasOwn.call(sourcesToContents, sourceName)) {
sourcesToContents[sourceName] = sourceContent;
smg.setSourceContent(sourceName, sourceContent);
var sourcesToContents = {};
smcLatter.eachMapping(function (mapping) {
var origPos = smcFormer.originalPositionFor({
line: mapping.originalLine,
column: mapping.originalColumn
});
var sourceName = origPos.source;
if (sourceName === null) {
return;
}
smg.addMapping({
source: sourceName,
original: copyPos(origPos),
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn
},
name: mapping.name
});
var sourceContent = smcFormer.sourceContentFor(sourceName);
if (sourceContent && !hasOwn.call(sourcesToContents, sourceName)) {
sourcesToContents[sourceName] = sourceContent;
smg.setSourceContent(sourceName, sourceContent);
}
});
return smg.toJSON();
}
exports.composeSourceMaps = composeSourceMaps;
;
function getTrueLoc(node, lines) {
// It's possible that node is newly-created (not parsed by Esprima),
// in which case it probably won't have a .loc property (or an
// .original property for that matter). That's fine; we'll just
// pretty-print it as usual.
if (!node.loc) {
return null;
}
});
return smg.toJSON();
};
util.getTrueLoc = function(node, lines) {
// It's possible that node is newly-created (not parsed by Esprima),
// in which case it probably won't have a .loc property (or an
// .original property for that matter). That's fine; we'll just
// pretty-print it as usual.
if (!node.loc) {
return null;
}
var result = {
start: node.loc.start,
end: node.loc.end
};
function include(node) {
expandLoc(result, node.loc);
}
// If the node is an export declaration and its .declaration has any
// decorators, their locations might contribute to the true start/end
// positions of the export declaration node.
if (node.declaration &&
node.declaration.decorators &&
util.isExportDeclaration(node)) {
node.declaration.decorators.forEach(include);
}
if (comparePos(result.start, result.end) < 0) {
// Trim leading whitespace.
result.start = copyPos(result.start);
lines.skipSpaces(result.start, false, true);
var result = {
start: node.loc.start,
end: node.loc.end
};
function include(node) {
expandLoc(result, node.loc);
}
// If the node is an export declaration and its .declaration has any
// decorators, their locations might contribute to the true start/end
// positions of the export declaration node.
if (node.declaration &&
node.declaration.decorators &&
isExportDeclaration(node)) {
node.declaration.decorators.forEach(include);
}
if (comparePos(result.start, result.end) < 0) {
// Trim trailing whitespace, if the end location is not already the
// same as the start location.
result.end = copyPos(result.end);
lines.skipSpaces(result.end, true, true);
// Trim leading whitespace.
result.start = copyPos(result.start);
lines.skipSpaces(result.start, false, true);
if (comparePos(result.start, result.end) < 0) {
// Trim trailing whitespace, if the end location is not already the
// same as the start location.
result.end = copyPos(result.end);
lines.skipSpaces(result.end, true, true);
}
}
}
// If the node has any comments, their locations might contribute to
// the true start/end positions of the node.
if (node.comments) {
node.comments.forEach(include);
}
return result;
};
// If the node has any comments, their locations might contribute to
// the true start/end positions of the node.
if (node.comments) {
node.comments.forEach(include);
}
return result;
}
exports.getTrueLoc = getTrueLoc;
;
function expandLoc(parentLoc, childLoc) {
if (parentLoc && childLoc) {
if (comparePos(childLoc.start, parentLoc.start) < 0) {
parentLoc.start = childLoc.start;
if (parentLoc && childLoc) {
if (comparePos(childLoc.start, parentLoc.start) < 0) {
parentLoc.start = childLoc.start;
}
if (comparePos(parentLoc.end, childLoc.end) < 0) {
parentLoc.end = childLoc.end;
}
}
if (comparePos(parentLoc.end, childLoc.end) < 0) {
parentLoc.end = childLoc.end;
}
}
}
util.fixFaultyLocations = function(node, lines) {
var loc = node.loc;
if (loc) {
if (loc.start.line < 1) {
loc.start.line = 1;
function fixFaultyLocations(node, lines) {
var loc = node.loc;
if (loc) {
if (loc.start.line < 1) {
loc.start.line = 1;
}
if (loc.end.line < 1) {
loc.end.line = 1;
}
}
if (loc.end.line < 1) {
loc.end.line = 1;
if (node.type === "File") {
// Babylon returns File nodes whose .loc.{start,end} do not include
// leading or trailing whitespace.
loc.start = lines.firstPos();
loc.end = lines.lastPos();
}
}
if (node.type === "File") {
// Babylon returns File nodes whose .loc.{start,end} do not include
// leading or trailing whitespace.
loc.start = lines.firstPos();
loc.end = lines.lastPos();
}
fixForLoopHead(node, lines);
fixTemplateLiteral(node, lines);
if (loc && node.decorators) {
// Expand the .loc of the node responsible for printing the decorators
// (here, the decorated node) so that it includes node.decorators.
node.decorators.forEach(function (decorator) {
expandLoc(loc, decorator.loc);
});
} else if (node.declaration && util.isExportDeclaration(node)) {
// Nullify .loc information for the child declaration so that we never
// try to reprint it without also reprinting the export declaration.
node.declaration.loc = null;
// Expand the .loc of the node responsible for printing the decorators
// (here, the export declaration) so that it includes node.decorators.
var decorators = node.declaration.decorators;
if (decorators) {
decorators.forEach(function (decorator) {
expandLoc(loc, decorator.loc);
});
fixForLoopHead(node, lines);
fixTemplateLiteral(node, lines);
if (loc && node.decorators) {
// Expand the .loc of the node responsible for printing the decorators
// (here, the decorated node) so that it includes node.decorators.
node.decorators.forEach(function (decorator) {
expandLoc(loc, decorator.loc);
});
}
} else if ((n.MethodDefinition && n.MethodDefinition.check(node)) ||
(n.Property.check(node) && (node.method || node.shorthand))) {
// If the node is a MethodDefinition or a .method or .shorthand
// Property, then the location information stored in
// node.value.loc is very likely untrustworthy (just the {body}
// part of a method, or nothing in the case of shorthand
// properties), so we null out that information to prevent
// accidental reuse of bogus source code during reprinting.
node.value.loc = null;
if (n.FunctionExpression.check(node.value)) {
// FunctionExpression method values should be anonymous,
// because their .id fields are ignored anyway.
node.value.id = null;
else if (node.declaration && isExportDeclaration(node)) {
// Nullify .loc information for the child declaration so that we never
// try to reprint it without also reprinting the export declaration.
node.declaration.loc = null;
// Expand the .loc of the node responsible for printing the decorators
// (here, the export declaration) so that it includes node.decorators.
var decorators = node.declaration.decorators;
if (decorators) {
decorators.forEach(function (decorator) {
expandLoc(loc, decorator.loc);
});
}
}
} else if (node.type === "ObjectTypeProperty") {
var loc = node.loc;
var end = loc && loc.end;
if (end) {
end = copyPos(end);
if (lines.prevPos(end) &&
lines.charAt(end) === ",") {
// Some parsers accidentally include trailing commas in the
// .loc.end information for ObjectTypeProperty nodes.
if ((end = lines.skipSpaces(end, true, true))) {
loc.end = end;
else if ((n.MethodDefinition && n.MethodDefinition.check(node)) ||
(n.Property.check(node) && (node.method || node.shorthand))) {
// If the node is a MethodDefinition or a .method or .shorthand
// Property, then the location information stored in
// node.value.loc is very likely untrustworthy (just the {body}
// part of a method, or nothing in the case of shorthand
// properties), so we null out that information to prevent
// accidental reuse of bogus source code during reprinting.
node.value.loc = null;
if (n.FunctionExpression.check(node.value)) {
// FunctionExpression method values should be anonymous,
// because their .id fields are ignored anyway.
node.value.id = null;
}
}
}
}
};
else if (node.type === "ObjectTypeProperty") {
var loc = node.loc;
var end = loc && loc.end;
if (end) {
end = copyPos(end);
if (lines.prevPos(end) &&
lines.charAt(end) === ",") {
// Some parsers accidentally include trailing commas in the
// .loc.end information for ObjectTypeProperty nodes.
if ((end = lines.skipSpaces(end, true, true))) {
loc.end = end;
}
}
}
}
}
exports.fixFaultyLocations = fixFaultyLocations;
;
function fixForLoopHead(node, lines) {
if (node.type !== "ForStatement") {
return;
}
function fix(child) {
var loc = child && child.loc;
var start = loc && loc.start;
var end = loc && copyPos(loc.end);
while (start && end && comparePos(start, end) < 0) {
lines.prevPos(end);
if (lines.charAt(end) === ";") {
// Update child.loc.end to *exclude* the ';' character.
loc.end.line = end.line;
loc.end.column = end.column;
} else {
break;
}
if (node.type !== "ForStatement") {
return;
}
}
fix(node.init);
fix(node.test);
fix(node.update);
function fix(child) {
var loc = child && child.loc;
var start = loc && loc.start;
var end = loc && copyPos(loc.end);
while (start && end && comparePos(start, end) < 0) {
lines.prevPos(end);
if (lines.charAt(end) === ";") {
// Update child.loc.end to *exclude* the ';' character.
loc.end.line = end.line;
loc.end.column = end.column;
}
else {
break;
}
}
}
fix(node.init);
fix(node.test);
fix(node.update);
}
function fixTemplateLiteral(node, lines) {
if (node.type !== "TemplateLiteral") {
return;
}
if (node.quasis.length === 0) {
// If there are no quasi elements, then there is nothing to fix.
return;
}
// node.loc is not present when using export default with a template literal
if (node.loc) {
// First we need to exclude the opening ` from the .loc of the first
// quasi element, in case the parser accidentally decided to include it.
var afterLeftBackTickPos = copyPos(node.loc.start);
assert.strictEqual(lines.charAt(afterLeftBackTickPos), "`");
assert.ok(lines.nextPos(afterLeftBackTickPos));
var firstQuasi = node.quasis[0];
if (comparePos(firstQuasi.loc.start, afterLeftBackTickPos) < 0) {
firstQuasi.loc.start = afterLeftBackTickPos;
if (node.type !== "TemplateLiteral") {
return;
}
// Next we need to exclude the closing ` from the .loc of the last quasi
// element, in case the parser accidentally decided to include it.
var rightBackTickPos = copyPos(node.loc.end);
assert.ok(lines.prevPos(rightBackTickPos));
assert.strictEqual(lines.charAt(rightBackTickPos), "`");
var lastQuasi = node.quasis[node.quasis.length - 1];
if (comparePos(rightBackTickPos, lastQuasi.loc.end) < 0) {
lastQuasi.loc.end = rightBackTickPos;
if (node.quasis.length === 0) {
// If there are no quasi elements, then there is nothing to fix.
return;
}
}
// Now we need to exclude ${ and } characters from the .loc's of all
// quasi elements, since some parsers accidentally include them.
node.expressions.forEach(function (expr, i) {
// Rewind from expr.loc.start over any whitespace and the ${ that
// precedes the expression. The position of the $ should be the same
// as the .loc.end of the preceding quasi element, but some parsers
// accidentally include the ${ in the .loc of the quasi element.
var dollarCurlyPos = lines.skipSpaces(expr.loc.start, true, false);
if (lines.prevPos(dollarCurlyPos) &&
lines.charAt(dollarCurlyPos) === "{" &&
lines.prevPos(dollarCurlyPos) &&
lines.charAt(dollarCurlyPos) === "$") {
var quasiBefore = node.quasis[i];
if (comparePos(dollarCurlyPos, quasiBefore.loc.end) < 0) {
quasiBefore.loc.end = dollarCurlyPos;
}
// node.loc is not present when using export default with a template literal
if (node.loc) {
// First we need to exclude the opening ` from the .loc of the first
// quasi element, in case the parser accidentally decided to include it.
var afterLeftBackTickPos = copyPos(node.loc.start);
assert_1.default.strictEqual(lines.charAt(afterLeftBackTickPos), "`");
assert_1.default.ok(lines.nextPos(afterLeftBackTickPos));
var firstQuasi = node.quasis[0];
if (comparePos(firstQuasi.loc.start, afterLeftBackTickPos) < 0) {
firstQuasi.loc.start = afterLeftBackTickPos;
}
// Next we need to exclude the closing ` from the .loc of the last quasi
// element, in case the parser accidentally decided to include it.
var rightBackTickPos = copyPos(node.loc.end);
assert_1.default.ok(lines.prevPos(rightBackTickPos));
assert_1.default.strictEqual(lines.charAt(rightBackTickPos), "`");
var lastQuasi = node.quasis[node.quasis.length - 1];
if (comparePos(rightBackTickPos, lastQuasi.loc.end) < 0) {
lastQuasi.loc.end = rightBackTickPos;
}
}
// Likewise, some parsers accidentally include the } that follows
// the expression in the .loc of the following quasi element.
var rightCurlyPos = lines.skipSpaces(expr.loc.end, false, false);
if (lines.charAt(rightCurlyPos) === "}") {
assert.ok(lines.nextPos(rightCurlyPos));
// Now rightCurlyPos is technically the position just after the }.
var quasiAfter = node.quasis[i + 1];
if (comparePos(quasiAfter.loc.start, rightCurlyPos) < 0) {
quasiAfter.loc.start = rightCurlyPos;
}
// Now we need to exclude ${ and } characters from the .loc's of all
// quasi elements, since some parsers accidentally include them.
node.expressions.forEach(function (expr, i) {
// Rewind from expr.loc.start over any whitespace and the ${ that
// precedes the expression. The position of the $ should be the same
// as the .loc.end of the preceding quasi element, but some parsers
// accidentally include the ${ in the .loc of the quasi element.
var dollarCurlyPos = lines.skipSpaces(expr.loc.start, true, false);
if (lines.prevPos(dollarCurlyPos) &&
lines.charAt(dollarCurlyPos) === "{" &&
lines.prevPos(dollarCurlyPos) &&
lines.charAt(dollarCurlyPos) === "$") {
var quasiBefore = node.quasis[i];
if (comparePos(dollarCurlyPos, quasiBefore.loc.end) < 0) {
quasiBefore.loc.end = dollarCurlyPos;
}
}
// Likewise, some parsers accidentally include the } that follows
// the expression in the .loc of the following quasi element.
var rightCurlyPos = lines.skipSpaces(expr.loc.end, false, false);
if (lines.charAt(rightCurlyPos) === "}") {
assert_1.default.ok(lines.nextPos(rightCurlyPos));
// Now rightCurlyPos is technically the position just after the }.
var quasiAfter = node.quasis[i + 1];
if (comparePos(quasiAfter.loc.start, rightCurlyPos) < 0) {
quasiAfter.loc.start = rightCurlyPos;
}
}
});
}
function isExportDeclaration(node) {
if (node)
switch (node.type) {
case "ExportDeclaration":
case "ExportDefaultDeclaration":
case "ExportDefaultSpecifier":
case "DeclareExportDeclaration":
case "ExportNamedDeclaration":
case "ExportAllDeclaration":
return true;
}
return false;
}
exports.isExportDeclaration = isExportDeclaration;
;
function getParentExportDeclaration(path) {
var parentNode = path.getParentNode();
if (path.getName() === "declaration" &&
isExportDeclaration(parentNode)) {
return parentNode;
}
});
return null;
}
util.isExportDeclaration = function (node) {
if (node) switch (node.type) {
case "ExportDeclaration":
case "ExportDefaultDeclaration":
case "ExportDefaultSpecifier":
case "DeclareExportDeclaration":
case "ExportNamedDeclaration":
case "ExportAllDeclaration":
return true;
}
return false;
};
util.getParentExportDeclaration = function (path) {
var parentNode = path.getParentNode();
if (path.getName() === "declaration" &&
util.isExportDeclaration(parentNode)) {
return parentNode;
}
return null;
};
util.isTrailingCommaEnabled = function(options, context) {
var trailingComma = options.trailingComma;
if (typeof trailingComma === "object") {
return !!trailingComma[context];
}
return !!trailingComma;
};
exports.getParentExportDeclaration = getParentExportDeclaration;
;
function isTrailingCommaEnabled(options, context) {
var trailingComma = options.trailingComma;
if (typeof trailingComma === "object") {
return !!trailingComma[context];
}
return !!trailingComma;
}
exports.isTrailingCommaEnabled = isTrailingCommaEnabled;
;

@@ -1,19 +0,21 @@

var types = require("./lib/types");
var parse = require("./lib/parser").parse;
var Printer = require("./lib/printer").Printer;
"use strict";;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var fs_1 = __importDefault(require("fs"));
var types_1 = __importDefault(require("./lib/types"));
var parser_1 = require("./lib/parser");
var printer_1 = require("./lib/printer");
function print(node, options) {
return new Printer(options).print(node);
return new printer_1.Printer(options).print(node);
}
function prettyPrint(node, options) {
return new Printer(options).printGenerically(node);
return new printer_1.Printer(options).printGenerically(node);
}
function run(transformer, options) {
return runFile(process.argv[2], transformer, options);
}
function runFile(path, transformer, options) {
require("fs").readFile(path, "utf-8", function(err, code) {
fs_1.default.readFile(path, "utf-8", function (err, code) {
if (err) {

@@ -23,19 +25,16 @@ console.error(err);

}
runString(code, transformer, options);
});
}
function defaultWriteback(output) {
process.stdout.write(output);
}
function runString(code, transformer, options) {
var writeback = options && options.writeback || defaultWriteback;
transformer(parse(code, options), function(node) {
transformer(parser_1.parse(code, options), function (node) {
writeback(print(node, options).code);
});
}
Object.defineProperties(exports, {
var main = {};
Object.defineProperties(main, {
/**

@@ -47,5 +46,4 @@ * Parse a string of code into an augmented syntax tree suitable for

enumerable: true,
value: parse
value: parser_1.parse
},
/**

@@ -66,5 +64,4 @@ * Traverse and potentially modify an abstract syntax tree using a

enumerable: true,
value: types.visit
value: types_1.default.visit
},
/**

@@ -78,3 +75,2 @@ * Reprint a modified syntax tree using as much of the original source

},
/**

@@ -87,3 +83,2 @@ * Print without attempting to reuse any original source code.

},
/**

@@ -94,5 +89,4 @@ * Customized version of require("ast-types").

enumerable: false,
value: types
value: types_1.default
},
/**

@@ -106,1 +100,3 @@ * Convenient command-line interface (see e.g. example/add-braces).

});
exports.default = main;
module.exports = exports["default"];
{
"author": "Ben Newman <bn@cs.stanford.edu>",
"name": "recast",
"version": "0.16.2",
"version": "0.17.0",
"description": "JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator",

@@ -23,5 +23,12 @@ "keywords": [

"main": "main.js",
"types": "main.d.ts",
"scripts": {
"test": "test/run.sh",
"debug": "test/run.sh --inspect-brk"
"tsc": "tsc --noEmit",
"mocha": "test/run.sh",
"debug": "test/run.sh --inspect-brk",
"test": "npm run tsc && npm run mocha",
"build": "tsc && ts-add-module-exports",
"clean": "ts-emit-clean",
"prepack": "npm run clean && npm run build",
"postpack": "npm run clean"
},

@@ -32,3 +39,3 @@ "browser": {

"dependencies": {
"ast-types": "0.11.7",
"ast-types": "0.12.0",
"esprima": "~4.0.0",

@@ -42,2 +49,6 @@ "private": "~0.1.5",

"@babel/preset-env": "^7.0.0-beta.54",
"@types/esprima": "^4.0.2",
"@types/glob": "^7.1.1",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.9",
"esprima-fb": "^15001.1001.0-dev-harmony-fb",

@@ -47,3 +58,7 @@ "flow-parser": "^0.83.0",

"mocha": "~5.2.0",
"reify": "^0.18.0"
"reify": "^0.18.0",
"ts-add-module-exports": "^1.0.0",
"ts-emit-clean": "^1.0.0",
"ts-node": "^7.0.1",
"typescript": "^3.1.6"
},

@@ -50,0 +65,0 @@ "engines": {

@@ -1,39 +0,42 @@

const getOption = require("../lib/util.js").getOption;
module.exports = function (options) {
// The goal here is to tolerate as much syntax as possible, since Recast
// is not in the business of forbidding anything. If you want your
// parser to be more restrictive for some reason, you can always pass
// your own parser object to recast.parse.
return {
sourceType: getOption(options, "sourceType", "module"),
strictMode: getOption(options, "strictMode", false),
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
startLine: 1,
tokens: true,
plugins: [
"asyncGenerators",
"bigInt",
"classPrivateMethods",
"classPrivateProperties",
"classProperties",
"decorators-legacy",
"doExpressions",
"dynamicImport",
"exportDefaultFrom",
"exportExtensions",
"exportNamespaceFrom",
"functionBind",
"functionSent",
"importMeta",
"nullishCoalescingOperator",
"numericSeparator",
"objectRestSpread",
"optionalCatchBinding",
"optionalChaining",
["pipelineOperator", { proposal: "minimal" }],
"throwExpressions",
]
};
};
"use strict";;
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("../lib/util");
function getBabelOptions(options) {
// The goal here is to tolerate as much syntax as possible, since Recast
// is not in the business of forbidding anything. If you want your
// parser to be more restrictive for some reason, you can always pass
// your own parser object to recast.parse.
return {
sourceType: util_1.getOption(options, "sourceType", "module"),
strictMode: util_1.getOption(options, "strictMode", false),
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
startLine: 1,
tokens: true,
plugins: [
"asyncGenerators",
"bigInt",
"classPrivateMethods",
"classPrivateProperties",
"classProperties",
"decorators-legacy",
"doExpressions",
"dynamicImport",
"exportDefaultFrom",
"exportExtensions",
"exportNamespaceFrom",
"functionBind",
"functionSent",
"importMeta",
"nullishCoalescingOperator",
"numericSeparator",
"objectRestSpread",
"optionalCatchBinding",
"optionalChaining",
["pipelineOperator", { proposal: "minimal" }],
"throwExpressions",
]
};
}
exports.default = getBabelOptions;
module.exports = exports["default"];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// This module is suitable for passing as options.parser when calling

@@ -10,27 +10,25 @@ // recast.parse to process JavaScript code with Acorn:

//
const getOption = require("../lib/util.js").getOption;
exports.parse = function parse(source, options) {
const comments = [];
const tokens = [];
const ast = require("acorn").parse(source, {
allowHashBang: true,
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
ecmaVersion: getOption(options, "ecmaVersion", 8),
sourceType: getOption(options, "sourceType", "module"),
locations: true,
onComment: comments,
onToken: tokens,
});
if (! ast.comments) {
ast.comments = comments;
}
if (! ast.tokens) {
ast.tokens = tokens;
}
return ast;
};
var util_1 = require("../lib/util");
function parse(source, options) {
var comments = [];
var tokens = [];
var ast = require("acorn").parse(source, {
allowHashBang: true,
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
ecmaVersion: util_1.getOption(options, "ecmaVersion", 8),
sourceType: util_1.getOption(options, "sourceType", "module"),
locations: true,
onComment: comments,
onToken: tokens,
});
if (!ast.comments) {
ast.comments = comments;
}
if (!ast.tokens) {
ast.tokens = tokens;
}
return ast;
}
exports.parse = parse;
;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var _babel_options_1 = __importDefault(require("./_babel_options"));
// Prefer the new @babel/parser package, but fall back to babylon if
// that's what's available.
const parser = exports.parser = function () {
try {
return require("@babel/parser");
} catch (e) {
return require("babylon");
}
exports.parser = function () {
try {
return require("@babel/parser");
}
catch (e) {
return require("babylon");
}
}();
// This module is suitable for passing as options.parser when calling

@@ -20,6 +24,8 @@ // recast.parse to process JavaScript code with Babel:

//
exports.parse = function (source, options) {
options = require("./_babel_options.js")(options);
options.plugins.push("jsx", "flow");
return parser.parse(source, options);
};
function parse(source, options) {
var babelOptions = _babel_options_1.default(options);
babelOptions.plugins.push("jsx", "flow");
return exports.parser.parse(source, babelOptions);
}
exports.parse = parse;
;
"use strict";
Object.assign(exports, require("./babel.js"));
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./babel"));
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// This module is suitable for passing as options.parser when calling

@@ -10,21 +10,20 @@ // recast.parse to process ECMAScript code with Esprima:

//
const getOption = require("../lib/util.js").getOption;
exports.parse = function (source, options) {
const comments = [];
const ast = require("esprima").parse(source, {
loc: true,
locations: true,
comment: true,
onComment: comments,
range: getOption(options, "range", false),
tolerant: getOption(options, "tolerant", true),
tokens: true
});
if (! Array.isArray(ast.comments)) {
ast.comments = comments;
}
return ast;
};
var util_1 = require("../lib/util");
function parse(source, options) {
var comments = [];
var ast = require("esprima").parse(source, {
loc: true,
locations: true,
comment: true,
onComment: comments,
range: util_1.getOption(options, "range", false),
tolerant: util_1.getOption(options, "tolerant", true),
tokens: true
});
if (!Array.isArray(ast.comments)) {
ast.comments = comments;
}
return ast;
}
exports.parse = parse;
;
"use strict";
const parser = require("./babel.js").parser;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var babel_1 = require("./babel");
var _babel_options_1 = __importDefault(require("./_babel_options"));
// This module is suitable for passing as options.parser when calling

@@ -12,6 +15,8 @@ // recast.parse to process Flow code:

//
exports.parse = function parse(source, options) {
options = require("./_babel_options.js")(options);
options.plugins.push("jsx", "flow");
return parser.parse(source, options);
};
function parse(source, options) {
var babelOptions = _babel_options_1.default(options);
babelOptions.plugins.push("jsx", "flow");
return babel_1.parser.parse(source, babelOptions);
}
exports.parse = parse;
;
"use strict";
const parser = require("./babel.js").parser;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var babel_1 = require("./babel");
var _babel_options_1 = __importDefault(require("./_babel_options"));
// This module is suitable for passing as options.parser when calling

@@ -12,6 +15,8 @@ // recast.parse to process TypeScript code:

//
exports.parse = function parse(source, options) {
options = require("./_babel_options.js")(options);
options.plugins.push("typescript");
return parser.parse(source, options);
};
function parse(source, options) {
var babelOptions = _babel_options_1.default(options);
babelOptions.plugins.push("typescript");
return babel_1.parser.parse(source, babelOptions);
}
exports.parse = parse;
;

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc