Comparing version 0.15.5 to 0.16.0
@@ -7,2 +7,3 @@ var assert = require("assert"); | ||
var isNumber = types.builtInTypes.number; | ||
var util = require("./util.js"); | ||
@@ -184,44 +185,85 @@ function FastPath(value) { | ||
function expressionStartsWithCurlyBrace(node) { | ||
// TODO detect when node is already wrapped in parentheses to avoid (admittedly harmless) wrapping in extra parentheses. | ||
if(node == null) return false; | ||
switch(node.type) { | ||
// expressions guaranteed to start with a { | ||
case "ObjectExpression": | ||
case "ObjectPattern": | ||
return true; | ||
// Returns true if the node at the tip of the path is wrapped with | ||
// parentheses, OR if the only reason the node needed parentheses was that | ||
// it couldn't be the first expression in the enclosing statement (see | ||
// FastPath#canBeFirstInStatement), and it has an opening `(` character. | ||
// For example, the FunctionExpression in `(function(){}())` appears to | ||
// need parentheses only because it's the first expression in the AST, but | ||
// since it happens to be preceded by a `(` (which is not apparent from | ||
// the AST but can be determined using FastPath#getPrevToken), there is no | ||
// ambiguity about how to parse it, so it counts as having parentheses, | ||
// even though it is not immediately followed by a `)`. | ||
FPp.hasParens = function () { | ||
const node = this.getNode(); | ||
// All expressions that comprise nested expressions | ||
case "BinaryExpression": | ||
case "AssignmentExpression": | ||
case "LogicalExpression": | ||
return expressionStartsWithCurlyBrace(node.left); | ||
const prevToken = this.getPrevToken(node); | ||
if (! prevToken) { | ||
return false; | ||
} | ||
case "MemberExpression": | ||
case "BindExpression": | ||
return expressionStartsWithCurlyBrace(node.object); | ||
const nextToken = this.getNextToken(node); | ||
if (! nextToken) { | ||
return false; | ||
} | ||
case "CallExpression": | ||
return expressionStartsWithCurlyBrace(node.callee); | ||
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; | ||
} | ||
case "UpdateExpression": | ||
case "UnaryExpression": | ||
return node.prefix === false && expressionStartsWithCurlyBrace(node.argument); | ||
// 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); | ||
case "TSNonNullExpression": | ||
return expressionStartsWithCurlyBrace(node.expression); | ||
if (justNeedsOpeningParen) { | ||
return true; | ||
} | ||
} | ||
case "ConditionalExpression": | ||
return expressionStartsWithCurlyBrace(node.test); | ||
return false; | ||
}; | ||
case "SequenceExpression": | ||
return expressionStartsWithCurlyBrace(node.expressions[0]); | ||
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; | ||
} | ||
} | ||
} | ||
return null; | ||
}; | ||
case "TaggedTemplateExpression": | ||
return expressionStartsWithCurlyBrace(node.tag); | ||
default: | ||
false; | ||
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; | ||
} | ||
} | ||
} | ||
} | ||
return null; | ||
}; | ||
@@ -268,6 +310,2 @@ // Inspired by require("ast-types").NodePath.prototype.needsParens, but | ||
if (parent.type === "ArrowFunctionExpression" && name === "body") { | ||
return expressionStartsWithCurlyBrace(node); | ||
} | ||
switch (node.type) { | ||
@@ -544,2 +582,8 @@ case "UnaryExpression": | ||
if (n.ArrowFunctionExpression.check(parent) && | ||
childName === "body") { | ||
assert.strictEqual(parent.body, child); | ||
return true; | ||
} | ||
if (n.SequenceExpression.check(parent) && | ||
@@ -546,0 +590,0 @@ parentName === "expressions" && |
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"), | ||
// 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, | ||
// 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, | ||
// 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, | ||
// 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", | ||
// 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. | ||
// 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.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, | ||
// 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 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 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 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 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, double quotes are used. | ||
quote: null, | ||
// 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 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 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, | ||
// 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, | ||
// 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, | ||
// 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 | ||
}, hasOwn = defaults.hasOwnProperty; | ||
@@ -99,30 +101,31 @@ | ||
exports.normalize = function(options) { | ||
options = options || defaults; | ||
options = options || defaults; | ||
function get(key) { | ||
return hasOwn.call(options, key) | ||
? options[key] | ||
: defaults[key]; | ||
} | ||
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"), | ||
}; | ||
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") | ||
}; | ||
}; |
@@ -40,2 +40,22 @@ "use strict"; | ||
// 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); | ||
} | ||
}); | ||
if (Array.isArray(ast.comments)) { | ||
@@ -80,2 +100,7 @@ comments = ast.comments; | ||
// 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 | ||
@@ -105,8 +130,11 @@ // attached to the Program node, as its children may have comments as | ||
// compared to the original. | ||
return new TreeCopier(lines).copy(file); | ||
return new TreeCopier(lines, tokens).copy(file); | ||
}; | ||
function TreeCopier(lines) { | ||
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; | ||
@@ -153,2 +181,5 @@ this.seen = new Map; | ||
const oldStartTokenIndex = this.startTokenIndex; | ||
const oldEndTokenIndex = this.endTokenIndex; | ||
if (loc) { | ||
@@ -166,4 +197,12 @@ // When node is a comment, we set node.loc.indent to | ||
// 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); | ||
} | ||
@@ -188,4 +227,57 @@ | ||
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 | ||
// contained by this loc, a binary search would be appropriate, but | ||
// because we maintain this.startTokenIndex and this.endTokenIndex as we | ||
// traverse the AST, we only need to make small (linear) adjustments to | ||
// those indexes with each recursive iteration. | ||
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; | ||
}; |
@@ -193,6 +193,12 @@ var assert = require("assert"); | ||
var newLines = print( | ||
reprint.newPath, | ||
needToPrintNewPathWithComments | ||
).indentTail(oldNode.loc.indent); | ||
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); | ||
@@ -220,3 +226,9 @@ var nls = needsLeadingSpace(lines, oldNode.loc, newLines); | ||
// guaranteed to contain all the reprinted nodes and comments. | ||
return patcher.get(origLoc).indentTail(-orig.loc.indent); | ||
const patchedLines = patcher.get(origLoc).indentTail(-orig.loc.indent); | ||
if (path.needsParens()) { | ||
return linesModule.concat(["(", patchedLines, ")"]); | ||
} | ||
return patchedLines; | ||
}; | ||
@@ -408,74 +420,2 @@ }; | ||
// This object is reused in hasOpeningParen and hasClosingParen to avoid | ||
// having to allocate a temporary object. | ||
var reusablePos = { line: 1, column: 0 }; | ||
var nonSpaceExp = /\S/; | ||
function hasOpeningParen(oldPath) { | ||
var oldNode = oldPath.getValue(); | ||
var loc = oldNode.loc; | ||
var lines = loc && loc.lines; | ||
if (lines) { | ||
var pos = reusablePos; | ||
pos.line = loc.start.line; | ||
pos.column = loc.start.column; | ||
while (lines.prevPos(pos)) { | ||
var ch = lines.charAt(pos); | ||
if (ch === "(") { | ||
// If we found an opening parenthesis but it occurred before the | ||
// start of the original subtree for this reprinting, then we must | ||
// not return true for hasOpeningParen(oldPath). | ||
return comparePos(oldPath.getRootValue().loc.start, pos) <= 0; | ||
} | ||
if (nonSpaceExp.test(ch)) { | ||
return false; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
function hasClosingParen(oldPath) { | ||
var oldNode = oldPath.getValue(); | ||
var loc = oldNode.loc; | ||
var lines = loc && loc.lines; | ||
if (lines) { | ||
var pos = reusablePos; | ||
pos.line = loc.end.line; | ||
pos.column = loc.end.column; | ||
do { | ||
var ch = lines.charAt(pos); | ||
if (ch === ")") { | ||
// If we found a closing parenthesis but it occurred after the end | ||
// of the original subtree for this reprinting, then we must not | ||
// return true for hasClosingParen(oldPath). | ||
return comparePos(pos, oldPath.getRootValue().loc.end) <= 0; | ||
} | ||
if (nonSpaceExp.test(ch)) { | ||
return false; | ||
} | ||
} while (lines.nextPos(pos)); | ||
} | ||
return false; | ||
} | ||
function hasParens(oldPath) { | ||
// This logic can technically be fooled if the node has parentheses but | ||
// there are comments intervening between the parentheses and the | ||
// node. In such cases the node will be harmlessly wrapped in an | ||
// additional layer of parentheses. | ||
return hasOpeningParen(oldPath) && hasClosingParen(oldPath); | ||
} | ||
function findChildReprints(newPath, oldPath, reprints) { | ||
@@ -493,25 +433,7 @@ var newNode = newPath.getValue(); | ||
// If this type of node cannot come lexically first in its enclosing | ||
// statement (e.g. a function expression or object literal), and it | ||
// seems to be doing so, then the only way we can ignore this problem | ||
// and save ourselves from falling back to the pretty printer is if an | ||
// opening parenthesis happens to precede the node. For example, | ||
// (function(){ ... }()); does not need to be reprinted, even though the | ||
// FunctionExpression comes lexically first in the enclosing | ||
// ExpressionStatement and fails the hasParens test, because the parent | ||
// CallExpression passes the hasParens test. If we relied on the | ||
// path.needsParens() && !hasParens(oldNode) check below, the absence of | ||
// a closing parenthesis after the FunctionExpression would trigger | ||
// pretty-printing unnecessarily. | ||
if (Node.check(newNode) && | ||
!newPath.canBeFirstInStatement() && | ||
newPath.firstInStatement() && | ||
!hasOpeningParen(oldPath)) { | ||
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(true) && !hasParens(oldPath)) { | ||
if (newPath.needsParens() && | ||
! oldPath.hasParens()) { | ||
return false; | ||
@@ -518,0 +440,0 @@ } |
{ | ||
"author": "Ben Newman <bn@cs.stanford.edu>", | ||
"name": "recast", | ||
"version": "0.16.0", | ||
"description": "JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator", | ||
@@ -15,3 +16,2 @@ "keywords": [ | ||
], | ||
"version": "0.15.5", | ||
"homepage": "http://github.com/benjamn/recast", | ||
@@ -32,3 +32,3 @@ "repository": { | ||
"dependencies": { | ||
"ast-types": "0.11.5", | ||
"ast-types": "0.11.6", | ||
"esprima": "~4.0.0", | ||
@@ -43,6 +43,6 @@ "private": "~0.1.5", | ||
"esprima-fb": "^15001.1001.0-dev-harmony-fb", | ||
"flow-parser": "^0.80.0", | ||
"flow-parser": "^0.83.0", | ||
"glob": "^7.1.2", | ||
"mocha": "~5.2.0", | ||
"reify": "^0.17.3" | ||
"reify": "^0.18.0" | ||
}, | ||
@@ -49,0 +49,0 @@ "engines": { |
"use strict"; | ||
// 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"); | ||
} | ||
}(); | ||
// This module is suitable for passing as options.parser when calling | ||
// recast.parse to process JavaScript code with Babel: | ||
// | ||
// const ast = recast.parse(source, { | ||
// parser: require("recast/parsers/babylon") | ||
// }); | ||
// | ||
exports.parse = function (source, options) { | ||
options = require("./_babylon_options.js")(options); | ||
options.plugins.push("jsx", "flow"); | ||
return parser.parse(source, options); | ||
}; | ||
Object.assign(exports, require("./babel.js")); |
@@ -21,3 +21,3 @@ "use strict"; | ||
tolerant: getOption(options, "tolerant", true), | ||
tokens: getOption(options, "tokens", true) | ||
tokens: true | ||
}); | ||
@@ -24,0 +24,0 @@ |
"use strict"; | ||
const parser = require("./babylon.js").parser; | ||
const parser = require("./babel.js").parser; | ||
@@ -13,5 +13,5 @@ // This module is suitable for passing as options.parser when calling | ||
exports.parse = function parse(source, options) { | ||
options = require("./_babylon_options.js")(options); | ||
options = require("./_babel_options.js")(options); | ||
options.plugins.push("jsx", "flow"); | ||
return parser.parse(source, options); | ||
}; |
"use strict"; | ||
const parser = require("./babylon.js").parser; | ||
const parser = require("./babel.js").parser; | ||
@@ -13,5 +13,5 @@ // This module is suitable for passing as options.parser when calling | ||
exports.parse = function parse(source, options) { | ||
options = require("./_babylon_options.js")(options); | ||
options = require("./_babel_options.js")(options); | ||
options.plugins.push("typescript"); | ||
return parser.parse(source, options); | ||
}; |
@@ -45,3 +45,3 @@ # recast, _v_. [![Build Status](https://travis-ci.org/benjamn/recast.svg?branch=master)](https://travis-ci.org/benjamn/recast) [![Join the chat at https://gitter.im/benjamn/recast](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/benjamn/recast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Greenkeeper badge](https://badges.greenkeeper.io/benjamn/recast.svg)](https://greenkeeper.io/) | ||
See [ast-types](https://github.com/benjamn/ast-types) (especially the [def/core.js](https://github.com/benjamn/ast-types/blob/master/def/core.js)) module for a thorough overview of the `ast` api. | ||
See [ast-types](https://github.com/benjamn/ast-types) (especially the [def/core.js](https://github.com/benjamn/ast-types/blob/master/def/core.js)) module for a thorough overview of the `ast` API. | ||
```js | ||
@@ -48,0 +48,0 @@ // Grab a reference to the function declaration we just parsed. |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
198339
27
5358
+ Addedast-types@0.11.6(transitive)
- Removedast-types@0.11.5(transitive)
Updatedast-types@0.11.6