Run prettier

This commit is contained in:
Brian Ng 2017-06-27 12:15:00 -05:00
parent 93cc22dae1
commit e4b35f680d
No known key found for this signature in database
GPG Key ID: 3F2380E1E1508CA9
307 changed files with 6742 additions and 4080 deletions

View File

@ -21,32 +21,41 @@ function swapSrcWithLib(srcPath) {
gulp.task("default", ["build"]); gulp.task("default", ["build"]);
gulp.task("build", function () { gulp.task("build", function() {
return gulp.src(scripts, { base: base }) return gulp
.pipe(plumber({ .src(scripts, { base: base })
errorHandler: function (err) { .pipe(
plumber({
errorHandler: function(err) {
gutil.log(err.stack); gutil.log(err.stack);
}, },
})) })
.pipe(newer({ )
.pipe(
newer({
dest: base, dest: base,
map: swapSrcWithLib, map: swapSrcWithLib,
})) })
.pipe(through.obj(function (file, enc, callback) { )
.pipe(
through.obj(function(file, enc, callback) {
gutil.log("Compiling", "'" + chalk.cyan(file.relative) + "'..."); gutil.log("Compiling", "'" + chalk.cyan(file.relative) + "'...");
callback(null, file); callback(null, file);
})) })
)
.pipe(babel()) .pipe(babel())
.pipe(through.obj(function (file, enc, callback) { .pipe(
through.obj(function(file, enc, callback) {
// Passing 'file.relative' because newer() above uses a relative path and this keeps it consistent. // Passing 'file.relative' because newer() above uses a relative path and this keeps it consistent.
file.path = path.resolve(file.base, swapSrcWithLib(file.relative)); file.path = path.resolve(file.base, swapSrcWithLib(file.relative));
callback(null, file); callback(null, file);
})) })
)
.pipe(gulp.dest(base)); .pipe(gulp.dest(base));
}); });
gulp.task("watch", ["build"], function () { gulp.task("watch", ["build"], function() {
watch(scripts, { debounceDelay: 200 }, function () { watch(scripts, { debounceDelay: 200 }, function() {
gulp.start("build"); gulp.start("build");
}); });
}); });

View File

@ -24,9 +24,21 @@ function collect(value, previousValue): Array<string> {
/* eslint-disable max-len */ /* eslint-disable max-len */
program.option("-e, --eval [script]", "Evaluate script"); program.option("-e, --eval [script]", "Evaluate script");
program.option("-p, --print [code]", "Evaluate script and print result"); program.option("-p, --print [code]", "Evaluate script and print result");
program.option("-o, --only [globs]", "A comma-separated list of glob patterns to compile", collect); program.option(
program.option("-i, --ignore [globs]", "A comma-separated list of glob patterns to skip compiling", collect); "-o, --only [globs]",
program.option("-x, --extensions [extensions]", "List of extensions to hook into [.es6,.js,.es,.jsx,.mjs]", collect); "A comma-separated list of glob patterns to compile",
collect,
);
program.option(
"-i, --ignore [globs]",
"A comma-separated list of glob patterns to skip compiling",
collect,
);
program.option(
"-x, --extensions [extensions]",
"List of extensions to hook into [.es6,.js,.es,.jsx,.mjs]",
collect,
);
program.option("-w, --plugins [string]", "", collect); program.option("-w, --plugins [string]", "", collect);
program.option("-b, --presets [string]", "", collect); program.option("-b, --presets [string]", "", collect);
/* eslint-enable max-len */ /* eslint-enable max-len */
@ -55,23 +67,28 @@ const replPlugin = ({ types: t }) => ({
VariableDeclaration(path) { VariableDeclaration(path) {
if (path.node.kind !== "var") { if (path.node.kind !== "var") {
throw path.buildCodeFrameError("Only `var` variables are supported in the REPL"); throw path.buildCodeFrameError(
"Only `var` variables are supported in the REPL",
);
} }
}, },
Program(path) { Program(path) {
if (path.get("body").some((child) => child.isExpressionStatement())) return; if (path.get("body").some(child => child.isExpressionStatement())) return;
// If the executed code doesn't evaluate to a value, // If the executed code doesn't evaluate to a value,
// prevent implicit strict mode from printing 'use strict'. // prevent implicit strict mode from printing 'use strict'.
path.pushContainer("body", t.expressionStatement(t.identifier("undefined"))); path.pushContainer(
"body",
t.expressionStatement(t.identifier("undefined")),
);
}, },
}, },
}); });
// //
const _eval = function (code, filename) { const _eval = function(code, filename) {
code = code.trim(); code = code.trim();
if (!code) return undefined; if (!code) return undefined;
@ -113,7 +130,7 @@ if (program.eval || program.print) {
let i = 0; let i = 0;
let ignoreNext = false; let ignoreNext = false;
args.some(function (arg, i2) { args.some(function(arg, i2) {
if (ignoreNext) { if (ignoreNext) {
ignoreNext = false; ignoreNext = false;
return; return;
@ -133,7 +150,9 @@ if (program.eval || program.print) {
// make the filename absolute // make the filename absolute
const filename = args[0]; const filename = args[0];
if (!path.isAbsolute(filename)) args[0] = path.join(process.cwd(), filename); if (!path.isAbsolute(filename)) {
args[0] = path.join(process.cwd(), filename);
}
// add back on node and concat the sliced args // add back on node and concat the sliced args
process.argv = ["node"].concat(args); process.argv = ["node"].concat(args);

View File

@ -10,8 +10,16 @@ function collect(value, previousValue): Array<string> {
return previousValue ? previousValue.concat(values) : values; return previousValue ? previousValue.concat(values) : values;
} }
commander.option("-l, --whitelist [whitelist]", "Whitelist of helpers to ONLY include", collect); commander.option(
commander.option("-t, --output-type [type]", "Type of output (global|umd|var)", "global"); "-l, --whitelist [whitelist]",
"Whitelist of helpers to ONLY include",
collect,
);
commander.option(
"-t, --output-type [type]",
"Type of output (global|umd|var)",
"global",
);
commander.usage("[options]"); commander.usage("[options]");
commander.parse(process.argv); commander.parse(process.argv);

View File

@ -33,7 +33,7 @@ function getNormalizedV8Flag(arg) {
return arg; return arg;
} }
getV8Flags(function (err, v8Flags) { getV8Flags(function(err, v8Flags) {
babelArgs.forEach(function(arg) { babelArgs.forEach(function(arg) {
const flag = arg.split("=")[0]; const flag = arg.split("=")[0];
@ -59,7 +59,10 @@ getV8Flags(function (err, v8Flags) {
break; break;
default: default:
if (v8Flags.indexOf(getNormalizedV8Flag(flag)) >= 0 || arg.indexOf("--trace") === 0) { if (
v8Flags.indexOf(getNormalizedV8Flag(flag)) >= 0 ||
arg.indexOf("--trace") === 0
) {
args.unshift(arg); args.unshift(arg);
} else { } else {
args.push(arg); args.push(arg);
@ -80,9 +83,11 @@ getV8Flags(function (err, v8Flags) {
if (err.code !== "MODULE_NOT_FOUND") throw err; if (err.code !== "MODULE_NOT_FOUND") throw err;
const child_process = require("child_process"); const child_process = require("child_process");
const proc = child_process.spawn(process.argv[0], args, { stdio: "inherit" }); const proc = child_process.spawn(process.argv[0], args, {
proc.on("exit", function (code, signal) { stdio: "inherit",
process.on("exit", function () { });
proc.on("exit", function(code, signal) {
process.on("exit", function() {
if (signal) { if (signal) {
process.kill(process.pid, signal); process.kill(process.pid, signal);
} else { } else {

View File

@ -6,19 +6,27 @@ import fs from "fs";
import * as util from "./util"; import * as util from "./util";
export default function (commander, filenames, opts) { export default function(commander, filenames, opts) {
function write(src, relative) { function write(src, relative) {
if (!util.isCompilableExtension(relative, commander.extensions)) return false; if (!util.isCompilableExtension(relative, commander.extensions)) {
return false;
}
// remove extension and then append back on .js // remove extension and then append back on .js
relative = relative.replace(/\.(\w*?)$/, "") + ".js"; relative = relative.replace(/\.(\w*?)$/, "") + ".js";
const dest = path.join(commander.outDir, relative); const dest = path.join(commander.outDir, relative);
const data = util.compile(src, defaults({ const data = util.compile(
src,
defaults(
{
sourceFileName: slash(path.relative(dest + "/..", src)), sourceFileName: slash(path.relative(dest + "/..", src)),
sourceMapTarget: path.basename(relative), sourceMapTarget: path.basename(relative),
}, opts)); },
opts,
),
);
if (!data) return false; if (!data) return false;
@ -55,7 +63,7 @@ export default function (commander, filenames, opts) {
if (stat.isDirectory(filename)) { if (stat.isDirectory(filename)) {
const dirname = filename; const dirname = filename;
util.readdir(dirname).forEach(function (filename) { util.readdir(dirname).forEach(function(filename) {
const src = path.join(dirname, filename); const src = path.join(dirname, filename);
handleFile(src, filename); handleFile(src, filename);
}); });
@ -71,7 +79,7 @@ export default function (commander, filenames, opts) {
if (commander.watch) { if (commander.watch) {
const chokidar = util.requireChokidar(); const chokidar = util.requireChokidar();
filenames.forEach(function (dirname) { filenames.forEach(function(dirname) {
const watcher = chokidar.watch(dirname, { const watcher = chokidar.watch(dirname, {
persistent: true, persistent: true,
ignoreInitial: true, ignoreInitial: true,
@ -81,8 +89,8 @@ export default function (commander, filenames, opts) {
}, },
}); });
["add", "change"].forEach(function (type) { ["add", "change"].forEach(function(type) {
watcher.on(type, function (filename) { watcher.on(type, function(filename) {
const relative = path.relative(dirname, filename) || filename; const relative = path.relative(dirname, filename) || filename;
try { try {
handleFile(filename, relative); handleFile(filename, relative);

View File

@ -7,14 +7,14 @@ import fs from "fs";
import * as util from "./util"; import * as util from "./util";
export default function (commander, filenames, opts) { export default function(commander, filenames, opts) {
if (commander.sourceMaps === "inline") { if (commander.sourceMaps === "inline") {
opts.sourceMaps = true; opts.sourceMaps = true;
} }
let results = []; let results = [];
const buildResult = function () { const buildResult = function() {
const map = new sourceMap.SourceMapGenerator({ const map = new sourceMap.SourceMapGenerator({
file: path.basename(commander.outFile || "") || "stdout", file: path.basename(commander.outFile || "") || "stdout",
sourceRoot: opts.sourceRoot, sourceRoot: opts.sourceRoot,
@ -23,14 +23,14 @@ export default function (commander, filenames, opts) {
let code = ""; let code = "";
let offset = 0; let offset = 0;
results.forEach(function (result) { results.forEach(function(result) {
code += result.code + "\n"; code += result.code + "\n";
if (result.map) { if (result.map) {
const consumer = new sourceMap.SourceMapConsumer(result.map); const consumer = new sourceMap.SourceMapConsumer(result.map);
const sources = new Set(); const sources = new Set();
consumer.eachMapping(function (mapping) { consumer.eachMapping(function(mapping) {
if (mapping.source != null) sources.add(mapping.source); if (mapping.source != null) sources.add(mapping.source);
map.addMapping({ map.addMapping({
@ -39,14 +39,17 @@ export default function (commander, filenames, opts) {
column: mapping.generatedColumn, column: mapping.generatedColumn,
}, },
source: mapping.source, source: mapping.source,
original: mapping.source == null ? null : { original:
mapping.source == null
? null
: {
line: mapping.originalLine, line: mapping.originalLine,
column: mapping.originalColumn, column: mapping.originalColumn,
}, },
}); });
}); });
sources.forEach((source) => { sources.forEach(source => {
const content = consumer.sourceContentFor(source, true); const content = consumer.sourceContentFor(source, true);
if (content !== null) { if (content !== null) {
map.setSourceContent(source, content); map.setSourceContent(source, content);
@ -59,7 +62,10 @@ export default function (commander, filenames, opts) {
// add the inline sourcemap comment if we've either explicitly asked for inline source // add the inline sourcemap comment if we've either explicitly asked for inline source
// maps, or we've requested them without any output file // maps, or we've requested them without any output file
if (commander.sourceMaps === "inline" || (!commander.outFile && commander.sourceMaps)) { if (
commander.sourceMaps === "inline" ||
(!commander.outFile && commander.sourceMaps)
) {
code += "\n" + convertSourceMap.fromObject(map).toComment(); code += "\n" + convertSourceMap.fromObject(map).toComment();
} }
@ -69,7 +75,7 @@ export default function (commander, filenames, opts) {
}; };
}; };
const output = function () { const output = function() {
const result = buildResult(); const result = buildResult();
if (commander.outFile) { if (commander.outFile) {
@ -86,36 +92,45 @@ export default function (commander, filenames, opts) {
} }
}; };
const stdin = function () { const stdin = function() {
let code = ""; let code = "";
process.stdin.setEncoding("utf8"); process.stdin.setEncoding("utf8");
process.stdin.on("readable", function () { process.stdin.on("readable", function() {
const chunk = process.stdin.read(); const chunk = process.stdin.read();
if (chunk !== null) code += chunk; if (chunk !== null) code += chunk;
}); });
process.stdin.on("end", function () { process.stdin.on("end", function() {
results.push(util.transform(commander.filename, code, defaults({ results.push(
util.transform(
commander.filename,
code,
defaults(
{
sourceFileName: "stdin", sourceFileName: "stdin",
}, opts))); },
opts,
),
),
);
output(); output();
}); });
}; };
const walk = function () { const walk = function() {
const _filenames = []; const _filenames = [];
results = []; results = [];
filenames.forEach(function (filename) { filenames.forEach(function(filename) {
if (!fs.existsSync(filename)) return; if (!fs.existsSync(filename)) return;
const stat = fs.statSync(filename); const stat = fs.statSync(filename);
if (stat.isDirectory()) { if (stat.isDirectory()) {
const dirname = filename; const dirname = filename;
util.readdirFilter(filename).forEach(function (filename) { util.readdirFilter(filename).forEach(function(filename) {
_filenames.push(path.join(dirname, filename)); _filenames.push(path.join(dirname, filename));
}); });
} else { } else {
@ -123,16 +138,25 @@ export default function (commander, filenames, opts) {
} }
}); });
_filenames.forEach(function (filename) { _filenames.forEach(function(filename) {
let sourceFilename = filename; let sourceFilename = filename;
if (commander.outFile) { if (commander.outFile) {
sourceFilename = path.relative(path.dirname(commander.outFile), sourceFilename); sourceFilename = path.relative(
path.dirname(commander.outFile),
sourceFilename,
);
} }
sourceFilename = slash(sourceFilename); sourceFilename = slash(sourceFilename);
const data = util.compile(filename, defaults({ const data = util.compile(
filename,
defaults(
{
sourceFileName: sourceFilename, sourceFileName: sourceFilename,
}, opts)); },
opts,
),
);
if (!data) return; if (!data) return;
@ -142,23 +166,26 @@ export default function (commander, filenames, opts) {
output(); output();
}; };
const files = function () { const files = function() {
if (!commander.skipInitialBuild) { if (!commander.skipInitialBuild) {
walk(); walk();
} }
if (commander.watch) { if (commander.watch) {
const chokidar = util.requireChokidar(); const chokidar = util.requireChokidar();
chokidar.watch(filenames, { chokidar
.watch(filenames, {
persistent: true, persistent: true,
ignoreInitial: true, ignoreInitial: true,
awaitWriteFinish: { awaitWriteFinish: {
stabilityThreshold: 50, stabilityThreshold: 50,
pollInterval: 10, pollInterval: 10,
}, },
}).on("all", function (type, filename) { })
if (!util.isCompilableExtension(filename, commander.extensions)) return; .on("all", function(type, filename) {
if (!util.isCompilableExtension(filename, commander.extensions)) {
return;
}
if (type === "add" || type === "change") { if (type === "add" || type === "change") {
util.log(type + " " + filename); util.log(type + " " + filename);

View File

@ -34,45 +34,117 @@ function collect(value, previousValue): Array<string> {
/* eslint-disable max-len */ /* eslint-disable max-len */
// Standard Babel input configs. // Standard Babel input configs.
commander.option("-f, --filename [filename]", "filename to use when reading from stdin - this will be used in source-maps, errors etc"); commander.option(
commander.option("--presets [list]", "comma-separated list of preset names", collect); "-f, --filename [filename]",
commander.option("--plugins [list]", "comma-separated list of plugin names", collect); "filename to use when reading from stdin - this will be used in source-maps, errors etc",
);
commander.option(
"--presets [list]",
"comma-separated list of preset names",
collect,
);
commander.option(
"--plugins [list]",
"comma-separated list of plugin names",
collect,
);
// Basic file input configuration. // Basic file input configuration.
commander.option("--source-type [script|module]", ""); commander.option("--source-type [script|module]", "");
commander.option("--no-babelrc", "Whether or not to look up .babelrc and .babelignore files"); commander.option(
commander.option("--ignore [list]", "list of glob paths to **not** compile", collect); "--no-babelrc",
commander.option("--only [list]", "list of glob paths to **only** compile", collect); "Whether or not to look up .babelrc and .babelignore files",
);
commander.option(
"--ignore [list]",
"list of glob paths to **not** compile",
collect,
);
commander.option(
"--only [list]",
"list of glob paths to **only** compile",
collect,
);
// Misc babel config. // Misc babel config.
commander.option("--no-highlight-code", "enable/disable ANSI syntax highlighting of code frames (on by default)"); commander.option(
"--no-highlight-code",
"enable/disable ANSI syntax highlighting of code frames (on by default)",
);
// General output formatting. // General output formatting.
commander.option("--no-comments", "write comments to generated output (true by default)"); commander.option(
commander.option("--retain-lines", "retain line numbers - will result in really ugly code"); "--no-comments",
commander.option("--compact [true|false|auto]", "do not include superfluous whitespace characters and line terminators", booleanify); "write comments to generated output (true by default)",
);
commander.option(
"--retain-lines",
"retain line numbers - will result in really ugly code",
);
commander.option(
"--compact [true|false|auto]",
"do not include superfluous whitespace characters and line terminators",
booleanify,
);
commander.option("--minified", "save as much bytes when printing [true|false]"); commander.option("--minified", "save as much bytes when printing [true|false]");
commander.option("--auxiliary-comment-before [string]", "print a comment before any injected non-user code"); commander.option(
commander.option("--auxiliary-comment-after [string]", "print a comment after any injected non-user code"); "--auxiliary-comment-before [string]",
"print a comment before any injected non-user code",
);
commander.option(
"--auxiliary-comment-after [string]",
"print a comment after any injected non-user code",
);
// General soucemap formatting. // General soucemap formatting.
commander.option("-s, --source-maps [true|false|inline|both]", "", booleanify); commander.option("-s, --source-maps [true|false|inline|both]", "", booleanify);
commander.option("--source-map-target [string]", "set `file` on returned source map"); commander.option(
commander.option("--source-file-name [string]", "set `sources[0]` on returned source map"); "--source-map-target [string]",
commander.option("--source-root [filename]", "the root from which all sources are relative"); "set `file` on returned source map",
);
commander.option(
"--source-file-name [string]",
"set `sources[0]` on returned source map",
);
commander.option(
"--source-root [filename]",
"the root from which all sources are relative",
);
// Config params for certain module output formats. // Config params for certain module output formats.
commander.option("--module-root [filename]", "optional prefix for the AMD module formatter that will be prepend to the filename on module definitions"); commander.option(
"--module-root [filename]",
"optional prefix for the AMD module formatter that will be prepend to the filename on module definitions",
);
commander.option("-M, --module-ids", "insert an explicit id for modules"); commander.option("-M, --module-ids", "insert an explicit id for modules");
commander.option("--module-id [string]", "specify a custom name for module ids"); commander.option(
"--module-id [string]",
"specify a custom name for module ids",
);
// "babel" command specific arguments that are not passed to babel-core. // "babel" command specific arguments that are not passed to babel-core.
commander.option("-x, --extensions [extensions]", "List of extensions to compile when a directory has been input [.es6,.js,.es,.jsx,.mjs]", collect); commander.option(
"-x, --extensions [extensions]",
"List of extensions to compile when a directory has been input [.es6,.js,.es,.jsx,.mjs]",
collect,
);
commander.option("-w, --watch", "Recompile files on changes"); commander.option("-w, --watch", "Recompile files on changes");
commander.option("--skip-initial-build", "Do not compile files before watching"); commander.option(
commander.option("-o, --out-file [out]", "Compile all input files into a single file"); "--skip-initial-build",
commander.option("-d, --out-dir [out]", "Compile an input directory of modules into an output directory"); "Do not compile files before watching",
commander.option("-D, --copy-files", "When compiling a directory copy over non-compilable files"); );
commander.option(
"-o, --out-file [out]",
"Compile all input files into a single file",
);
commander.option(
"-d, --out-dir [out]",
"Compile an input directory of modules into an output directory",
);
commander.option(
"-D, --copy-files",
"When compiling a directory copy over non-compilable files",
);
commander.option("-q, --quiet", "Don't log anything"); commander.option("-q, --quiet", "Don't log anything");
/* eslint-enable max-len */ /* eslint-enable max-len */
@ -84,7 +156,7 @@ commander.parse(process.argv);
const errors = []; const errors = [];
let filenames = commander.args.reduce(function (globbed, input) { let filenames = commander.args.reduce(function(globbed, input) {
let files = glob.sync(input); let files = glob.sync(input);
if (!files.length) files = [input]; if (!files.length) files = [input];
return globbed.concat(files); return globbed.concat(files);
@ -92,7 +164,7 @@ let filenames = commander.args.reduce(function (globbed, input) {
filenames = uniq(filenames); filenames = uniq(filenames);
filenames.forEach(function (filename) { filenames.forEach(function(filename) {
if (!fs.existsSync(filename)) { if (!fs.existsSync(filename)) {
errors.push(filename + " doesn't exist"); errors.push(filename + " doesn't exist");
} }

View File

@ -10,7 +10,7 @@ export function chmod(src, dest) {
} }
export function readdirFilter(filename) { export function readdirFilter(filename) {
return readdir(filename).filter(function (filename) { return readdir(filename).filter(function(filename) {
return isCompilableExtension(filename); return isCompilableExtension(filename);
}); });
} }
@ -20,7 +20,10 @@ export { readdir };
/** /**
* Test if a filename ends with a compilable extension. * Test if a filename ends with a compilable extension.
*/ */
export function isCompilableExtension(filename: string, altExts?: Array<string>): boolean { export function isCompilableExtension(
filename: string,
altExts?: Array<string>,
): boolean {
const exts = altExts || babel.DEFAULT_EXTENSIONS; const exts = altExts || babel.DEFAULT_EXTENSIONS;
const ext = path.extname(filename); const ext = path.extname(filename);
return includes(exts, ext); return includes(exts, ext);
@ -63,7 +66,7 @@ function toErrorStack(err) {
} }
} }
process.on("uncaughtException", function (err) { process.on("uncaughtException", function(err) {
console.error(toErrorStack(err)); console.error(toErrorStack(err));
process.exit(1); process.exit(1);
}); });
@ -74,7 +77,7 @@ export function requireChokidar() {
} catch (err) { } catch (err) {
console.error( console.error(
"The optional dependency chokidar failed to install and is required for " + "The optional dependency chokidar failed to install and is required for " +
"--watch. Chokidar is likely not supported on your platform." "--watch. Chokidar is likely not supported on your platform.",
); );
throw err; throw err;
} }

View File

@ -27,34 +27,39 @@ const pluginLocs = [
path.join(__dirname, "/../../babel-plugin-transform-es2015-modules-commonjs"), path.join(__dirname, "/../../babel-plugin-transform-es2015-modules-commonjs"),
].join(","); ].join(",");
const readDir = function (loc, filter) { const readDir = function(loc, filter) {
const files = {}; const files = {};
if (fs.existsSync(loc)) { if (fs.existsSync(loc)) {
readdir(loc, filter).forEach(function (filename) { readdir(loc, filter).forEach(function(filename) {
files[filename] = helper.readFile(path.join(loc, filename)); files[filename] = helper.readFile(path.join(loc, filename));
}); });
} }
return files; return files;
}; };
const saveInFiles = function (files) { const saveInFiles = function(files) {
// Place an empty .babelrc in each test so tests won't unexpectedly get to repo-level config. // Place an empty .babelrc in each test so tests won't unexpectedly get to repo-level config.
outputFileSync(".babelrc", "{}"); outputFileSync(".babelrc", "{}");
Object.keys(files).forEach(function (filename) { Object.keys(files).forEach(function(filename) {
const content = files[filename]; const content = files[filename];
outputFileSync(filename, content); outputFileSync(filename, content);
}); });
}; };
const assertTest = function (stdout, stderr, opts) { const assertTest = function(stdout, stderr, opts) {
const expectStderr = opts.stderr.trim(); const expectStderr = opts.stderr.trim();
stderr = stderr.trim(); stderr = stderr.trim();
if (opts.stderr) { if (opts.stderr) {
if (opts.stderrContains) { if (opts.stderrContains) {
assert.ok(includes(stderr, expectStderr), "stderr " + JSON.stringify(stderr) + assert.ok(
" didn't contain " + JSON.stringify(expectStderr)); includes(stderr, expectStderr),
"stderr " +
JSON.stringify(stderr) +
" didn't contain " +
JSON.stringify(expectStderr),
);
} else { } else {
chai.expect(stderr).to.equal(expectStderr, "stderr didn't match"); chai.expect(stderr).to.equal(expectStderr, "stderr didn't match");
} }
@ -68,8 +73,13 @@ const assertTest = function (stdout, stderr, opts) {
if (opts.stdout) { if (opts.stdout) {
if (opts.stdoutContains) { if (opts.stdoutContains) {
assert.ok(includes(stdout, expectStdout), "stdout " + JSON.stringify(stdout) + assert.ok(
" didn't contain " + JSON.stringify(expectStdout)); includes(stdout, expectStdout),
"stdout " +
JSON.stringify(stdout) +
" didn't contain " +
JSON.stringify(expectStdout),
);
} else { } else {
chai.expect(stdout).to.equal(expectStdout, "stdout didn't match"); chai.expect(stdout).to.equal(expectStdout, "stdout didn't match");
} }
@ -80,30 +90,34 @@ const assertTest = function (stdout, stderr, opts) {
if (opts.outFiles) { if (opts.outFiles) {
const actualFiles = readDir(path.join(tmpLoc)); const actualFiles = readDir(path.join(tmpLoc));
Object.keys(actualFiles).forEach(function (filename) { Object.keys(actualFiles).forEach(function(filename) {
if (!opts.inFiles.hasOwnProperty(filename)) { if (!opts.inFiles.hasOwnProperty(filename)) {
const expect = opts.outFiles[filename]; const expect = opts.outFiles[filename];
const actual = actualFiles[filename]; const actual = actualFiles[filename];
chai.expect(expect, "Output is missing: " + filename).to.not.be.undefined; chai.expect(expect, "Output is missing: " + filename).to.not.be
.undefined;
if (expect) { if (expect) {
chai.expect(actual).to.equal(expect, "Compiled output does not match: " + filename); chai
.expect(actual)
.to.equal(expect, "Compiled output does not match: " + filename);
} }
} }
}); });
Object.keys(opts.outFiles).forEach(function(filename) { Object.keys(opts.outFiles).forEach(function(filename) {
chai.expect(actualFiles, "Extraneous file in output: " + filename) chai
.expect(actualFiles, "Extraneous file in output: " + filename)
.to.contain.key(filename); .to.contain.key(filename);
}); });
} }
}; };
const buildTest = function (binName, testName, opts) { const buildTest = function(binName, testName, opts) {
const binLoc = path.join(__dirname, "../lib", binName); const binLoc = path.join(__dirname, "../lib", binName);
return function (callback) { return function(callback) {
clear(); clear();
saveInFiles(opts.inFiles); saveInFiles(opts.inFiles);
@ -124,15 +138,15 @@ const buildTest = function (binName, testName, opts) {
let stderr = ""; let stderr = "";
let stdout = ""; let stdout = "";
spawn.stderr.on("data", function (chunk) { spawn.stderr.on("data", function(chunk) {
stderr += chunk; stderr += chunk;
}); });
spawn.stdout.on("data", function (chunk) { spawn.stdout.on("data", function(chunk) {
stdout += chunk; stdout += chunk;
}); });
spawn.on("close", function () { spawn.on("close", function() {
let err; let err;
try { try {
@ -142,7 +156,8 @@ const buildTest = function (binName, testName, opts) {
} }
if (err) { if (err) {
err.message = args.map((arg) => `"${ arg }"`).join(" ") + ": " + err.message; err.message =
args.map(arg => `"${arg}"`).join(" ") + ": " + err.message;
} }
callback(err); callback(err);
@ -155,19 +170,19 @@ const buildTest = function (binName, testName, opts) {
}; };
}; };
const clear = function () { const clear = function() {
process.chdir(__dirname); process.chdir(__dirname);
if (fs.existsSync(tmpLoc)) rimraf.sync(tmpLoc); if (fs.existsSync(tmpLoc)) rimraf.sync(tmpLoc);
fs.mkdirSync(tmpLoc); fs.mkdirSync(tmpLoc);
process.chdir(tmpLoc); process.chdir(tmpLoc);
}; };
fs.readdirSync(fixtureLoc).forEach(function (binName) { fs.readdirSync(fixtureLoc).forEach(function(binName) {
if (binName[0] === ".") return; if (binName[0] === ".") return;
const suiteLoc = path.join(fixtureLoc, binName); const suiteLoc = path.join(fixtureLoc, binName);
describe("bin/" + binName, function () { describe("bin/" + binName, function() {
fs.readdirSync(suiteLoc).forEach(function (testName) { fs.readdirSync(suiteLoc).forEach(function(testName) {
if (testName[0] === ".") return; if (testName[0] === ".") return;
const testLoc = path.join(suiteLoc, testName); const testLoc = path.join(suiteLoc, testName);
@ -179,7 +194,7 @@ fs.readdirSync(fixtureLoc).forEach(function (binName) {
const optionsLoc = path.join(testLoc, "options.json"); const optionsLoc = path.join(testLoc, "options.json");
if (fs.existsSync(optionsLoc)) merge(opts, require(optionsLoc)); if (fs.existsSync(optionsLoc)) merge(opts, require(optionsLoc));
["stdout", "stdin", "stderr"].forEach(function (key) { ["stdout", "stdin", "stderr"].forEach(function(key) {
const loc = path.join(testLoc, key + ".txt"); const loc = path.join(testLoc, key + ".txt");
if (fs.existsSync(loc)) { if (fs.existsSync(loc)) {
opts[key] = helper.readFile(loc); opts[key] = helper.readFile(loc);

View File

@ -90,11 +90,11 @@ function getTokenType(match) {
*/ */
function highlight(defs: Object, text: string) { function highlight(defs: Object, text: string) {
return text.replace(jsTokens, function (...args) { return text.replace(jsTokens, function(...args) {
const type = getTokenType(args); const type = getTokenType(args);
const colorize = defs[type]; const colorize = defs[type];
if (colorize) { if (colorize) {
return args[0].split(NEWLINE).map((str) => colorize(str)).join("\n"); return args[0].split(NEWLINE).map(str => colorize(str)).join("\n");
} else { } else {
return args[0]; return args[0];
} }
@ -106,9 +106,15 @@ function highlight(defs: Object, text: string) {
*/ */
function getMarkerLines( function getMarkerLines(
loc: NodeLocation, source: Array<string>, opts: Object loc: NodeLocation,
source: Array<string>,
opts: Object,
): { start: number, end: number, markerLines: Object } { ): { start: number, end: number, markerLines: Object } {
const startLoc: Location = Object.assign({}, { column: 0, line: -1 }, loc.start); const startLoc: Location = Object.assign(
{},
{ column: 0, line: -1 },
loc.start,
);
const endLoc: Location = Object.assign({}, startLoc, loc.end); const endLoc: Location = Object.assign({}, startLoc, loc.end);
const linesAbove = opts.linesAbove || 2; const linesAbove = opts.linesAbove || 2;
const linesBelow = opts.linesBelow || 3; const linesBelow = opts.linesBelow || 3;
@ -165,12 +171,13 @@ function getMarkerLines(
return { start, end, markerLines }; return { start, end, markerLines };
} }
export function codeFrameColumns ( export function codeFrameColumns(
rawLines: string, rawLines: string,
loc: NodeLocation, loc: NodeLocation,
opts: Object = {}, opts: Object = {},
): string { ): string {
const highlighted = (opts.highlightCode && Chalk.supportsColor) || opts.forceColor; const highlighted =
(opts.highlightCode && Chalk.supportsColor) || opts.forceColor;
let chalk = Chalk; let chalk = Chalk;
if (opts.forceColor) { if (opts.forceColor) {
chalk = new Chalk.constructor({ enabled: true }); chalk = new Chalk.constructor({ enabled: true });
@ -186,7 +193,9 @@ export function codeFrameColumns (
const numberMaxWidth = String(end).length; const numberMaxWidth = String(end).length;
const frame = lines.slice(start, end).map((line, index) => { const frame = lines
.slice(start, end)
.map((line, index) => {
const number = start + 1 + index; const number = start + 1 + index;
const paddedNumber = ` ${number}`.slice(-numberMaxWidth); const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
const gutter = ` ${paddedNumber} | `; const gutter = ` ${paddedNumber} | `;
@ -194,7 +203,9 @@ export function codeFrameColumns (
if (hasMarker) { if (hasMarker) {
let markerLine = ""; let markerLine = "";
if (Array.isArray(hasMarker)) { if (Array.isArray(hasMarker)) {
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " "); const markerSpacing = line
.slice(0, Math.max(hasMarker[0] - 1, 0))
.replace(/[^\t]/g, " ");
const numberOfMarkers = hasMarker[1] || 1; const numberOfMarkers = hasMarker[1] || 1;
markerLine = [ markerLine = [
@ -213,7 +224,8 @@ export function codeFrameColumns (
} else { } else {
return ` ${maybeHighlight(defs.gutter, gutter)}${line}`; return ` ${maybeHighlight(defs.gutter, gutter)}${line}`;
} }
}).join("\n"); })
.join("\n");
if (highlighted) { if (highlighted) {
return chalk.reset(frame); return chalk.reset(frame);
@ -226,7 +238,7 @@ export function codeFrameColumns (
* Create a code frame, adding line numbers, code highlighting, and pointing to a given position. * Create a code frame, adding line numbers, code highlighting, and pointing to a given position.
*/ */
export default function ( export default function(
rawLines: string, rawLines: string,
lineNumber: number, lineNumber: number,
colNumber: ?number, colNumber: ?number,
@ -236,7 +248,7 @@ export default function (
deprecationWarningShown = true; deprecationWarningShown = true;
const deprecationError = new Error( const deprecationError = new Error(
"Passing lineNumber and colNumber is deprecated to babel-code-frame. Please use `codeFrameColumns`." "Passing lineNumber and colNumber is deprecated to babel-code-frame. Please use `codeFrameColumns`.",
); );
deprecationError.name = "DeprecationWarning"; deprecationError.name = "DeprecationWarning";
@ -249,7 +261,9 @@ export default function (
colNumber = Math.max(colNumber, 0); colNumber = Math.max(colNumber, 0);
const location: NodeLocation = { start: { column: colNumber, line: lineNumber } }; const location: NodeLocation = {
start: { column: colNumber, line: lineNumber },
};
return codeFrameColumns(rawLines, location, opts); return codeFrameColumns(rawLines, location, opts);
} }

View File

@ -2,35 +2,29 @@ import assert from "assert";
import chalk from "chalk"; import chalk from "chalk";
import codeFrame, { codeFrameColumns } from ".."; import codeFrame, { codeFrameColumns } from "..";
describe("babel-code-frame", function () { describe("babel-code-frame", function() {
it("basic usage", function () { it("basic usage", function() {
const rawLines = [ const rawLines = ["class Foo {", " constructor()", "};"].join("\n");
"class Foo {", assert.equal(
" constructor()", codeFrame(rawLines, 2, 16),
"};", [
].join("\n");
assert.equal(codeFrame(rawLines, 2, 16), [
" 1 | class Foo {", " 1 | class Foo {",
"> 2 | constructor()", "> 2 | constructor()",
" | ^", " | ^",
" 3 | };", " 3 | };",
].join("\n")); ].join("\n"),
);
}); });
it("optional column number", function () { it("optional column number", function() {
const rawLines = [ const rawLines = ["class Foo {", " constructor()", "};"].join("\n");
"class Foo {", assert.equal(
" constructor()", codeFrame(rawLines, 2, null),
"};", [" 1 | class Foo {", "> 2 | constructor()", " 3 | };"].join("\n"),
].join("\n"); );
assert.equal(codeFrame(rawLines, 2, null), [
" 1 | class Foo {",
"> 2 | constructor()",
" 3 | };",
].join("\n"));
}); });
it("maximum context lines and padding", function () { it("maximum context lines and padding", function() {
const rawLines = [ const rawLines = [
"/**", "/**",
" * Sums two numbers.", " * Sums two numbers.",
@ -44,7 +38,9 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 7, 2), [ assert.equal(
codeFrame(rawLines, 7, 2),
[
" 5 | * @param b Number", " 5 | * @param b Number",
" 6 | * @returns Number", " 6 | * @returns Number",
"> 7 | */", "> 7 | */",
@ -52,10 +48,11 @@ describe("babel-code-frame", function () {
" 8 | ", " 8 | ",
" 9 | function sum(a, b) {", " 9 | function sum(a, b) {",
" 10 | return a + b", " 10 | return a + b",
].join("\n")); ].join("\n"),
);
}); });
it("no unnecessary padding due to one-off errors", function () { it("no unnecessary padding due to one-off errors", function() {
const rawLines = [ const rawLines = [
"/**", "/**",
" * Sums two numbers.", " * Sums two numbers.",
@ -69,7 +66,9 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 6, 2), [ assert.equal(
codeFrame(rawLines, 6, 2),
[
" 4 | * @param a Number", " 4 | * @param a Number",
" 5 | * @param b Number", " 5 | * @param b Number",
"> 6 | * @returns Number", "> 6 | * @returns Number",
@ -77,35 +76,39 @@ describe("babel-code-frame", function () {
" 7 | */", " 7 | */",
" 8 | ", " 8 | ",
" 9 | function sum(a, b) {", " 9 | function sum(a, b) {",
].join("\n")); ].join("\n"),
);
}); });
it("tabs", function () { it("tabs", function() {
const rawLines = [ const rawLines = [
"\tclass Foo {", "\tclass Foo {",
"\t \t\t constructor\t(\t)", "\t \t\t constructor\t(\t)",
"\t};", "\t};",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 2, 25), [ assert.equal(
codeFrame(rawLines, 2, 25),
[
" 1 | \tclass Foo {", " 1 | \tclass Foo {",
"> 2 | \t \t\t constructor\t(\t)", "> 2 | \t \t\t constructor\t(\t)",
" | \t \t\t \t \t ^", " | \t \t\t \t \t ^",
" 3 | \t};", " 3 | \t};",
].join("\n")); ].join("\n"),
);
}); });
it("opts.highlightCode", function () { it("opts.highlightCode", function() {
const rawLines = "console.log('babel')"; const rawLines = "console.log('babel')";
const result = codeFrame(rawLines, 1, 9, { highlightCode: true }); const result = codeFrame(rawLines, 1, 9, { highlightCode: true });
const stripped = chalk.stripColor(result); const stripped = chalk.stripColor(result);
assert.ok(result.length > stripped.length); assert.ok(result.length > stripped.length);
assert.equal(stripped, [ assert.equal(
"> 1 | console.log('babel')", stripped,
" | ^", ["> 1 | console.log('babel')", " | ^"].join("\n"),
].join("\n")); );
}); });
it("opts.linesAbove", function () { it("opts.linesAbove", function() {
const rawLines = [ const rawLines = [
"/**", "/**",
" * Sums two numbers.", " * Sums two numbers.",
@ -119,17 +122,20 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 7, 2, { linesAbove: 1 }), [ assert.equal(
codeFrame(rawLines, 7, 2, { linesAbove: 1 }),
[
" 6 | * @returns Number", " 6 | * @returns Number",
"> 7 | */", "> 7 | */",
" | ^", " | ^",
" 8 | ", " 8 | ",
" 9 | function sum(a, b) {", " 9 | function sum(a, b) {",
" 10 | return a + b", " 10 | return a + b",
].join("\n")); ].join("\n"),
);
}); });
it("opts.linesBelow", function () { it("opts.linesBelow", function() {
const rawLines = [ const rawLines = [
"/**", "/**",
" * Sums two numbers.", " * Sums two numbers.",
@ -143,16 +149,19 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 7, 2, { linesBelow: 1 }), [ assert.equal(
codeFrame(rawLines, 7, 2, { linesBelow: 1 }),
[
" 5 | * @param b Number", " 5 | * @param b Number",
" 6 | * @returns Number", " 6 | * @returns Number",
"> 7 | */", "> 7 | */",
" | ^", " | ^",
" 8 | ", " 8 | ",
].join("\n")); ].join("\n"),
);
}); });
it("opts.linesAbove and opts.linesBelow", function () { it("opts.linesAbove and opts.linesBelow", function() {
const rawLines = [ const rawLines = [
"/**", "/**",
" * Sums two numbers.", " * Sums two numbers.",
@ -166,78 +175,82 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 7, 2, { linesAbove: 1, linesBelow: 1 }), [ assert.equal(
" 6 | * @returns Number", codeFrame(rawLines, 7, 2, { linesAbove: 1, linesBelow: 1 }),
"> 7 | */", [" 6 | * @returns Number", "> 7 | */", " | ^", " 8 | "].join(
" | ^", "\n",
" 8 | ", ),
].join("\n")); );
}); });
it("opts.forceColor", function() { it("opts.forceColor", function() {
const marker = chalk.red.bold; const marker = chalk.red.bold;
const gutter = chalk.grey; const gutter = chalk.grey;
const rawLines = [ const rawLines = ["", "", "", ""].join("\n");
"", assert.equal(
"", codeFrame(rawLines, 3, null, {
"", linesAbove: 1,
"", linesBelow: 1,
].join("\n"); forceColor: true,
assert.equal(codeFrame(rawLines, 3, null, { linesAbove: 1, linesBelow: 1, forceColor: true }), }),
chalk.reset([ chalk.reset(
[
" " + gutter(" 2 | "), " " + gutter(" 2 | "),
marker(">") + gutter(" 3 | "), marker(">") + gutter(" 3 | "),
" " + gutter(" 4 | "), " " + gutter(" 4 | "),
].join("\n")) ].join("\n"),
),
); );
}); });
it("basic usage, new API", function () { it("basic usage, new API", function() {
const rawLines = [ const rawLines = ["class Foo {", " constructor()", "};"].join("\n");
"class Foo {", assert.equal(
" constructor()", codeFrameColumns(rawLines, { start: { line: 2, column: 16 } }),
"};", [
].join("\n");
assert.equal(codeFrameColumns(rawLines, { start: { line: 2, column: 16 } }), [
" 1 | class Foo {", " 1 | class Foo {",
"> 2 | constructor()", "> 2 | constructor()",
" | ^", " | ^",
" 3 | };", " 3 | };",
].join("\n")); ].join("\n"),
);
}); });
it("mark multiple columns", function() { it("mark multiple columns", function() {
const rawLines = [ const rawLines = ["class Foo {", " constructor()", "};"].join("\n");
"class Foo {",
" constructor()",
"};",
].join("\n");
assert.equal( assert.equal(
codeFrameColumns(rawLines, { start: { line: 2, column: 3 }, end: { line: 2, column: 16 } }), [ codeFrameColumns(rawLines, {
start: { line: 2, column: 3 },
end: { line: 2, column: 16 },
}),
[
" 1 | class Foo {", " 1 | class Foo {",
"> 2 | constructor()", "> 2 | constructor()",
" | ^^^^^^^^^^^^^", " | ^^^^^^^^^^^^^",
" 3 | };", " 3 | };",
].join("\n")); ].join("\n"),
);
}); });
it("mark multiple columns across lines", function() { it("mark multiple columns across lines", function() {
const rawLines = [ const rawLines = ["class Foo {", " constructor() {", " }", "};"].join(
"class Foo {", "\n",
" constructor() {", );
" }",
"};",
].join("\n");
assert.equal( assert.equal(
codeFrameColumns(rawLines, { start: { line: 2, column: 17 }, end: { line: 3, column: 3 } }), [ codeFrameColumns(rawLines, {
start: { line: 2, column: 17 },
end: { line: 3, column: 3 },
}),
[
" 1 | class Foo {", " 1 | class Foo {",
"> 2 | constructor() {", "> 2 | constructor() {",
" | ^", " | ^",
"> 3 | }", "> 3 | }",
" | ^^^", " | ^^^",
" 4 | };", " 4 | };",
].join("\n")); ].join("\n"),
);
}); });
it("mark multiple columns across multiple lines", function() { it("mark multiple columns across multiple lines", function() {
@ -249,7 +262,11 @@ describe("babel-code-frame", function () {
"};", "};",
].join("\n"); ].join("\n");
assert.equal( assert.equal(
codeFrameColumns(rawLines, { start: { line: 2, column: 17 }, end: { line: 4, column: 3 } }), [ codeFrameColumns(rawLines, {
start: { line: 2, column: 17 },
end: { line: 4, column: 3 },
}),
[
" 1 | class Foo {", " 1 | class Foo {",
"> 2 | constructor() {", "> 2 | constructor() {",
" | ^", " | ^",
@ -258,7 +275,8 @@ describe("babel-code-frame", function () {
"> 4 | }", "> 4 | }",
" | ^^^", " | ^^^",
" 5 | };", " 5 | };",
].join("\n")); ].join("\n"),
);
}); });
it("mark across multiple lines without columns", function() { it("mark across multiple lines without columns", function() {
@ -270,12 +288,14 @@ describe("babel-code-frame", function () {
"};", "};",
].join("\n"); ].join("\n");
assert.equal( assert.equal(
codeFrameColumns(rawLines, { start: { line: 2 }, end: { line: 4 } }), [ codeFrameColumns(rawLines, { start: { line: 2 }, end: { line: 4 } }),
[
" 1 | class Foo {", " 1 | class Foo {",
"> 2 | constructor() {", "> 2 | constructor() {",
"> 3 | console.log(arguments);", "> 3 | console.log(arguments);",
"> 4 | }", "> 4 | }",
" 5 | };", " 5 | };",
].join("\n")); ].join("\n"),
);
}); });
}); });

View File

@ -7,14 +7,14 @@ import micromatch from "micromatch";
import { findConfigs, loadConfig } from "./loading/files"; import { findConfigs, loadConfig } from "./loading/files";
type ConfigItem = { type ConfigItem = {
type: "options"|"arguments", type: "options" | "arguments",
options: {}, options: {},
dirname: string, dirname: string,
alias: string, alias: string,
loc: string, loc: string,
}; };
export default function buildConfigChain(opts: {}): Array<ConfigItem>|null { export default function buildConfigChain(opts: {}): Array<ConfigItem> | null {
if (typeof opts.filename !== "string" && opts.filename != null) { if (typeof opts.filename !== "string" && opts.filename != null) {
throw new Error(".filename must be a string, null, or undefined"); throw new Error(".filename must be a string, null, or undefined");
} }
@ -44,9 +44,9 @@ export default function buildConfigChain(opts: {}): Array<ConfigItem>|null {
} }
class ConfigChainBuilder { class ConfigChainBuilder {
filename: string|null; filename: string | null;
configs: Array<ConfigItem>; configs: Array<ConfigItem>;
possibleDirs: null|Array<string>; possibleDirs: null | Array<string>;
constructor(filename) { constructor(filename) {
this.configs = []; this.configs = [];
@ -57,16 +57,14 @@ class ConfigChainBuilder {
/** /**
* Tests if a filename should be ignored based on "ignore" and "only" options. * Tests if a filename should be ignored based on "ignore" and "only" options.
*/ */
shouldIgnore( shouldIgnore(ignore: mixed, only: mixed, dirname: string): boolean {
ignore: mixed,
only: mixed,
dirname: string,
): boolean {
if (!this.filename) return false; if (!this.filename) return false;
if (ignore) { if (ignore) {
if (!Array.isArray(ignore)) { if (!Array.isArray(ignore)) {
throw new Error(`.ignore should be an array, ${JSON.stringify(ignore)} given`); throw new Error(
`.ignore should be an array, ${JSON.stringify(ignore)} given`,
);
} }
if (this.matchesPatterns(ignore, dirname)) return true; if (this.matchesPatterns(ignore, dirname)) return true;
@ -74,7 +72,9 @@ class ConfigChainBuilder {
if (only) { if (only) {
if (!Array.isArray(only)) { if (!Array.isArray(only)) {
throw new Error(`.only should be an array, ${JSON.stringify(only)} given`); throw new Error(
`.only should be an array, ${JSON.stringify(only)} given`,
);
} }
if (!this.matchesPatterns(only, dirname)) return true; if (!this.matchesPatterns(only, dirname)) return true;
@ -89,21 +89,27 @@ class ConfigChainBuilder {
*/ */
matchesPatterns(patterns: Array<mixed>, dirname: string) { matchesPatterns(patterns: Array<mixed>, dirname: string) {
const filename = this.filename; const filename = this.filename;
if (!filename) throw new Error("Assertion failure: .filename should always exist here"); if (!filename) {
throw new Error("Assertion failure: .filename should always exist here");
}
const res = []; const res = [];
const strings = []; const strings = [];
const fns = []; const fns = [];
patterns.forEach((pattern) => { patterns.forEach(pattern => {
if (typeof pattern === "string") strings.push(pattern); if (typeof pattern === "string") strings.push(pattern);
else if (typeof pattern === "function") fns.push(pattern); else if (typeof pattern === "function") fns.push(pattern);
else if (pattern instanceof RegExp) res.push(pattern); else if (pattern instanceof RegExp) res.push(pattern);
else throw new Error("Patterns must be a string, function, or regular expression"); else {
throw new Error(
"Patterns must be a string, function, or regular expression",
);
}
}); });
if (res.some((re) => re.test(filename))) return true; if (res.some(re => re.test(filename))) return true;
if (fns.some((fn) => fn(filename))) return true; if (fns.some(fn => fn(filename))) return true;
if (strings.length > 0) { if (strings.length > 0) {
let possibleDirs = this.possibleDirs; let possibleDirs = this.possibleDirs;
@ -123,7 +129,7 @@ class ConfigChainBuilder {
} }
} }
const absolutePatterns = strings.map((pattern) => { const absolutePatterns = strings.map(pattern => {
// Preserve the "!" prefix so that micromatch can use it for negation. // Preserve the "!" prefix so that micromatch can use it for negation.
const negate = pattern[0] === "!"; const negate = pattern[0] === "!";
if (negate) pattern = pattern.slice(1); if (negate) pattern = pattern.slice(1);
@ -131,7 +137,9 @@ class ConfigChainBuilder {
return (negate ? "!" : "") + path.resolve(dirname, pattern); return (negate ? "!" : "") + path.resolve(dirname, pattern);
}); });
if (micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0) { if (
micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0
) {
return true; return true;
} }
} }
@ -150,16 +158,16 @@ class ConfigChainBuilder {
}); });
} }
mergeConfig({ mergeConfig({ type, options: rawOpts, alias, dirname }) {
type,
options: rawOpts,
alias,
dirname,
}) {
// Bail out ASAP if this file is ignored so that we run as little logic as possible on ignored files. // Bail out ASAP if this file is ignored so that we run as little logic as possible on ignored files.
if (this.filename && this.shouldIgnore(rawOpts.ignore || null, rawOpts.only || null, dirname)) { if (
this.filename &&
this.shouldIgnore(rawOpts.ignore || null, rawOpts.only || null, dirname)
) {
// TODO(logan): This is a really cross way to bail out. Avoid this in rewrite. // TODO(logan): This is a really cross way to bail out. Avoid this in rewrite.
throw Object.assign((new Error("This file has been ignored."): any), { code: "BABEL_IGNORED_FILE" }); throw Object.assign((new Error("This file has been ignored."): any), {
code: "BABEL_IGNORED_FILE",
});
} }
const options = Object.assign({}, rawOpts); const options = Object.assign({}, rawOpts);
@ -168,13 +176,19 @@ class ConfigChainBuilder {
const envKey = getEnv(); const envKey = getEnv();
if (rawOpts.env != null && (typeof rawOpts.env !== "object" || Array.isArray(rawOpts.env))) { if (
rawOpts.env != null &&
(typeof rawOpts.env !== "object" || Array.isArray(rawOpts.env))
) {
throw new Error(".env block must be an object, null, or undefined"); throw new Error(".env block must be an object, null, or undefined");
} }
const envOpts = rawOpts.env && rawOpts.env[envKey]; const envOpts = rawOpts.env && rawOpts.env[envKey];
if (envOpts != null && (typeof envOpts !== "object" || Array.isArray(envOpts))) { if (
envOpts != null &&
(typeof envOpts !== "object" || Array.isArray(envOpts))
) {
throw new Error(".env[...] block must be an object, null, or undefined"); throw new Error(".env[...] block must be an object, null, or undefined");
} }
@ -196,11 +210,13 @@ class ConfigChainBuilder {
}); });
if (rawOpts.extends) { if (rawOpts.extends) {
if (typeof rawOpts.extends !== "string") throw new Error(".extends must be a string"); if (typeof rawOpts.extends !== "string") {
throw new Error(".extends must be a string");
}
const extendsConfig = loadConfig(rawOpts.extends, dirname); const extendsConfig = loadConfig(rawOpts.extends, dirname);
const existingConfig = this.configs.some((config) => { const existingConfig = this.configs.some(config => {
return config.alias === extendsConfig.filepath; return config.alias === extendsConfig.filepath;
}); });
if (!existingConfig) { if (!existingConfig) {
@ -214,4 +230,3 @@ class ConfigChainBuilder {
} }
} }
} }

View File

@ -13,7 +13,7 @@ type CacheConfiguratorObj = {
invalidate: <T>(handler: () => T) => T, invalidate: <T>(handler: () => T) => T,
}; };
type CacheEntry<ResultT> = Array<[ ResultT, () => boolean ]>; type CacheEntry<ResultT> = Array<[ResultT, () => boolean]>;
/** /**
* Given a function with a single argument, cache its results based on its argument and how it * Given a function with a single argument, cache its results based on its argument and how it
@ -22,7 +22,7 @@ type CacheEntry<ResultT> = Array<[ ResultT, () => boolean ]>;
export function makeStrongCache<ArgT, ResultT>( export function makeStrongCache<ArgT, ResultT>(
handler: (ArgT, CacheConfigurator) => ResultT, handler: (ArgT, CacheConfigurator) => ResultT,
autoPermacache?: boolean, autoPermacache?: boolean,
): (ArgT) => ResultT { ): ArgT => ResultT {
return makeCachedFunction(new Map(), handler, autoPermacache); return makeCachedFunction(new Map(), handler, autoPermacache);
} }
@ -34,22 +34,24 @@ export function makeStrongCache<ArgT, ResultT>(
export function makeWeakCache<ArgT: {}, ResultT>( export function makeWeakCache<ArgT: {}, ResultT>(
handler: (ArgT, CacheConfigurator) => ResultT, handler: (ArgT, CacheConfigurator) => ResultT,
autoPermacache?: boolean, autoPermacache?: boolean,
): (ArgT) => ResultT { ): ArgT => ResultT {
return makeCachedFunction(new WeakMap(), handler, autoPermacache); return makeCachedFunction(new WeakMap(), handler, autoPermacache);
} }
type CacheMap<ArgT, ResultT> = Map<ArgT, CacheEntry<ResultT>>|WeakMap<ArgT, CacheEntry<ResultT>>; type CacheMap<ArgT, ResultT> =
| Map<ArgT, CacheEntry<ResultT>>
| WeakMap<ArgT, CacheEntry<ResultT>>;
function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>( function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>(
callCache: Cache, callCache: Cache,
handler: (ArgT, CacheConfigurator) => ResultT, handler: (ArgT, CacheConfigurator) => ResultT,
autoPermacache: boolean = true, autoPermacache: boolean = true,
): (ArgT) => ResultT { ): ArgT => ResultT {
return function cachedFunction(arg) { return function cachedFunction(arg) {
let cachedValue: CacheEntry<ResultT>|void = callCache.get(arg); let cachedValue: CacheEntry<ResultT> | void = callCache.get(arg);
if (cachedValue) { if (cachedValue) {
for (const [ value, valid ] of cachedValue) { for (const [value, valid] of cachedValue) {
if (valid()) return value; if (valid()) return value;
} }
} }
@ -64,7 +66,8 @@ function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>(
if (!result.configured) { if (!result.configured) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
throw new Error([ throw new Error(
[
"Caching was left unconfigured. Babel's plugins, presets, and .babelrc.js files can be configured", "Caching was left unconfigured. Babel's plugins, presets, and .babelrc.js files can be configured",
"for various types of caching, using the first param of their handler functions:", "for various types of caching, using the first param of their handler functions:",
"", "",
@ -83,12 +86,12 @@ function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>(
"", "",
" // If testing for a specific env, we recommend specifics to avoid instantiating a plugin for", " // If testing for a specific env, we recommend specifics to avoid instantiating a plugin for",
" // any possible NODE_ENV value that might come up during plugin execution.", " // any possible NODE_ENV value that might come up during plugin execution.",
" var isProd = api.cache(() => process.env.NODE_ENV === \"production\");", ' var isProd = api.cache(() => process.env.NODE_ENV === "production");',
"", "",
" // .cache(fn) will perform a linear search though instances to find the matching plugin based", " // .cache(fn) will perform a linear search though instances to find the matching plugin based",
" // based on previous instantiated plugins. If you want to recreate the plugin and discard the", " // based on previous instantiated plugins. If you want to recreate the plugin and discard the",
" // previous instance whenever something changes, you may use:", " // previous instance whenever something changes, you may use:",
" var isProd = api.cache.invalidate(() => process.env.NODE_ENV === \"production\");", ' var isProd = api.cache.invalidate(() => process.env.NODE_ENV === "production");',
"", "",
" // Note, we also expose the following more-verbose versions of the above examples:", " // Note, we also expose the following more-verbose versions of the above examples:",
" api.cache.forever(); // api.cache(true)", " api.cache.forever(); // api.cache(true)",
@ -98,21 +101,18 @@ function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>(
" // Return the value that will be cached.", " // Return the value that will be cached.",
" return { };", " return { };",
"};", "};",
].join("\n")); ].join("\n"),
);
} }
if (!result.never) { if (!result.never) {
if (result.forever) { if (result.forever) {
cachedValue = [ cachedValue = [[value, () => true]];
[value, () => true],
];
} else if (result.invalidate) { } else if (result.invalidate) {
cachedValue = [ cachedValue = [[value, result.valid]];
[value, result.valid],
];
} else { } else {
cachedValue = cachedValue || []; cachedValue = cachedValue || [];
cachedValue.push([ value, result.valid ]); cachedValue.push([value, result.valid]);
} }
callCache.set(arg, cachedValue); callCache.set(arg, cachedValue);
} }
@ -121,7 +121,11 @@ function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>(
}; };
} }
function makeCacheConfig(): { cache: CacheConfigurator, result: *, deactivate: () => void } { function makeCacheConfig(): {
cache: CacheConfigurator,
result: *,
deactivate: () => void,
} {
const pairs = []; const pairs = [];
const result = { const result = {
@ -137,7 +141,8 @@ function makeCacheConfig(): { cache: CacheConfigurator, result: *, deactivate: (
active = false; active = false;
}; };
const cache: CacheConfigurator = Object.assign((function cacheFn(val) { const cache: CacheConfigurator = Object.assign(
(function cacheFn(val) {
if (typeof val === "boolean") { if (typeof val === "boolean") {
if (val) cache.forever(); if (val) cache.forever();
else cache.never(); else cache.never();
@ -145,43 +150,71 @@ function makeCacheConfig(): { cache: CacheConfigurator, result: *, deactivate: (
} }
return cache.using(val); return cache.using(val);
}: any), ({ }: any),
({
forever() { forever() {
if (!active) throw new Error("Cannot change caching after evaluation has completed."); if (!active) {
if (result.never) throw new Error("Caching has already been configured with .never()"); throw new Error(
"Cannot change caching after evaluation has completed.",
);
}
if (result.never) {
throw new Error("Caching has already been configured with .never()");
}
result.forever = true; result.forever = true;
result.configured = true; result.configured = true;
}, },
never() { never() {
if (!active) throw new Error("Cannot change caching after evaluation has completed."); if (!active) {
if (result.forever) throw new Error("Caching has already been configured with .forever()"); throw new Error(
"Cannot change caching after evaluation has completed.",
);
}
if (result.forever) {
throw new Error(
"Caching has already been configured with .forever()",
);
}
result.never = true; result.never = true;
result.configured = true; result.configured = true;
}, },
using<T>(handler: () => T): T { using<T>(handler: () => T): T {
if (!active) throw new Error("Cannot change caching after evaluation has completed."); if (!active) {
throw new Error(
"Cannot change caching after evaluation has completed.",
);
}
if (result.never || result.forever) { if (result.never || result.forever) {
throw new Error("Caching has already been configured with .never or .forever()"); throw new Error(
"Caching has already been configured with .never or .forever()",
);
} }
result.configured = true; result.configured = true;
const key = handler(); const key = handler();
pairs.push([ key, handler ]); pairs.push([key, handler]);
return key; return key;
}, },
invalidate<T>(handler: () => T): T { invalidate<T>(handler: () => T): T {
if (!active) throw new Error("Cannot change caching after evaluation has completed."); if (!active) {
throw new Error(
"Cannot change caching after evaluation has completed.",
);
}
if (result.never || result.forever) { if (result.never || result.forever) {
throw new Error("Caching has already been configured with .never or .forever()"); throw new Error(
"Caching has already been configured with .never or .forever()",
);
} }
result.invalidate = true; result.invalidate = true;
result.configured = true; result.configured = true;
const key = handler(); const key = handler();
pairs.push([ key, handler ]); pairs.push([key, handler]);
return key; return key;
}, },
}: CacheConfiguratorObj)); }: CacheConfiguratorObj),
);
return { cache, result, deactivate }; return { cache, result, deactivate };
} }

View File

@ -1,7 +1,5 @@
// @flow // @flow
export function getEnv(defaultValue: string = "development"): string { export function getEnv(defaultValue: string = "development"): string {
return process.env.BABEL_ENV return process.env.BABEL_ENV || process.env.NODE_ENV || defaultValue;
|| process.env.NODE_ENV
|| defaultValue;
} }

View File

@ -5,13 +5,13 @@ import manageOptions from "./option-manager";
export type ResolvedConfig = { export type ResolvedConfig = {
options: Object, options: Object,
passes: Array<Array<[ Plugin, ?{} ]>>, passes: Array<Array<[Plugin, ?{}]>>,
}; };
/** /**
* Standard API for loading Babel configuration data. Not for public consumption. * Standard API for loading Babel configuration data. Not for public consumption.
*/ */
export default function loadConfig(opts: mixed): ResolvedConfig|null { export default function loadConfig(opts: mixed): ResolvedConfig | null {
if (opts != null && typeof opts !== "object") { if (opts != null && typeof opts !== "object") {
throw new Error("Babel options must be an object, null, or undefined"); throw new Error("Babel options must be an object, null, or undefined");
} }

View File

@ -41,13 +41,16 @@ export function findConfigs(dirname: string): Array<ConfigFile> {
BABELRC_FILENAME, BABELRC_FILENAME,
BABELRC_JS_FILENAME, BABELRC_JS_FILENAME,
PACKAGE_FILENAME, PACKAGE_FILENAME,
].reduce((previousConfig: ConfigFile|null, name) => { ].reduce((previousConfig: ConfigFile | null, name) => {
const filepath = path.join(loc, name); const filepath = path.join(loc, name);
const config = readConfig(filepath); const config = readConfig(filepath);
if (config && previousConfig) { if (config && previousConfig) {
throw new Error(`Multiple configuration files found. Please remove one:\n- ${ throw new Error(
path.basename(previousConfig.filepath)}\n- ${name}\nfrom ${loc}`); `Multiple configuration files found. Please remove one:\n- ${path.basename(
previousConfig.filepath,
)}\n- ${name}\nfrom ${loc}`,
);
} }
return config || previousConfig; return config || previousConfig;
@ -73,7 +76,9 @@ export function loadConfig(name: string, dirname: string): ConfigFile {
const filepath = resolve.sync(name, { basedir: dirname }); const filepath = resolve.sync(name, { basedir: dirname });
const conf = readConfig(filepath); const conf = readConfig(filepath);
if (!conf) throw new Error(`Config file ${filepath} contains no configuration data`); if (!conf) {
throw new Error(`Config file ${filepath} contains no configuration data`);
}
return conf; return conf;
} }
@ -83,7 +88,9 @@ export function loadConfig(name: string, dirname: string): ConfigFile {
* throw if there are parsing errors while loading a config. * throw if there are parsing errors while loading a config.
*/ */
function readConfig(filepath) { function readConfig(filepath) {
return (path.extname(filepath) === ".js") ? readConfigJS(filepath) : readConfigFile(filepath); return path.extname(filepath) === ".js"
? readConfigJS(filepath)
: readConfigFile(filepath);
} }
const readConfigJS = makeStrongCache((filepath, cache) => { const readConfigJS = makeStrongCache((filepath, cache) => {
@ -96,7 +103,10 @@ const readConfigJS = makeStrongCache((filepath, cache) => {
try { try {
// $FlowIssue // $FlowIssue
const configModule = (require(filepath): mixed); const configModule = (require(filepath): mixed);
options = configModule && configModule.__esModule ? (configModule.default || undefined) : configModule; options =
configModule && configModule.__esModule
? configModule.default || undefined
: configModule;
} catch (err) { } catch (err) {
err.message = `${filepath}: Error while loading config - ${err.message}`; err.message = `${filepath}: Error while loading config - ${err.message}`;
throw err; throw err;
@ -113,7 +123,9 @@ const readConfigJS = makeStrongCache((filepath, cache) => {
} }
if (!options || typeof options !== "object" || Array.isArray(options)) { if (!options || typeof options !== "object" || Array.isArray(options)) {
throw new Error(`${filepath}: Configuration should be an exported JavaScript object.`); throw new Error(
`${filepath}: Configuration should be an exported JavaScript object.`,
);
} }
return { return {
@ -144,8 +156,12 @@ const readConfigFile = makeStaticFileCache((filepath, content) => {
if (!options) throw new Error(`${filepath}: No config detected`); if (!options) throw new Error(`${filepath}: No config detected`);
} }
if (typeof options !== "object") throw new Error(`${filepath}: Config returned typeof ${typeof options}`); if (typeof options !== "object") {
if (Array.isArray(options)) throw new Error(`${filepath}: Expected config object but found array`); throw new Error(`${filepath}: Config returned typeof ${typeof options}`);
}
if (Array.isArray(options)) {
throw new Error(`${filepath}: Expected config object but found array`);
}
return { return {
filepath, filepath,
@ -157,8 +173,8 @@ const readConfigFile = makeStaticFileCache((filepath, content) => {
const readIgnoreConfig = makeStaticFileCache((filepath, content) => { const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
const ignore = content const ignore = content
.split("\n") .split("\n")
.map((line) => line.replace(/#(.*?)$/, "").trim()) .map(line => line.replace(/#(.*?)$/, "").trim())
.filter((line) => !!line); .filter(line => !!line);
return { return {
filepath, filepath,
@ -167,7 +183,7 @@ const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
}; };
}); });
function makeStaticFileCache<T>(fn: (string, string) => T): (string) => T|null { function makeStaticFileCache<T>(fn: (string, string) => T): string => T | null {
return makeStrongCache((filepath, cache) => { return makeStrongCache((filepath, cache) => {
if (cache.invalidate(() => fileMtime(filepath)) === null) { if (cache.invalidate(() => fileMtime(filepath)) === null) {
cache.forever(); cache.forever();
@ -178,7 +194,7 @@ function makeStaticFileCache<T>(fn: (string, string) => T): (string) => T|null {
}); });
} }
function fileMtime(filepath: string): number|null { function fileMtime(filepath: string): number | null {
try { try {
return +fs.statSync(filepath).mtime; return +fs.statSync(filepath).mtime;
} catch (e) { } catch (e) {

View File

@ -16,27 +16,47 @@ export function loadConfig(name: string, dirname: string): ConfigFile {
} }
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
export function resolvePlugin(name: string, dirname: string): string|null { export function resolvePlugin(name: string, dirname: string): string | null {
return null; return null;
} }
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
export function resolvePreset(name: string, dirname: string): string|null { export function resolvePreset(name: string, dirname: string): string | null {
return null; return null;
} }
export function loadPlugin(name: string, dirname: string): { filepath: string, value: mixed } { export function loadPlugin(
throw new Error(`Cannot load plugin ${name} relative to ${dirname} in a browser`); name: string,
dirname: string,
): { filepath: string, value: mixed } {
throw new Error(
`Cannot load plugin ${name} relative to ${dirname} in a browser`,
);
} }
export function loadPreset(name: string, dirname: string): { filepath: string, value: mixed } { export function loadPreset(
throw new Error(`Cannot load preset ${name} relative to ${dirname} in a browser`); name: string,
dirname: string,
): { filepath: string, value: mixed } {
throw new Error(
`Cannot load preset ${name} relative to ${dirname} in a browser`,
);
} }
export function loadParser(name: string, dirname: string): { filepath: string, value: Function } { export function loadParser(
throw new Error(`Cannot load parser ${name} relative to ${dirname} in a browser`); name: string,
dirname: string,
): { filepath: string, value: Function } {
throw new Error(
`Cannot load parser ${name} relative to ${dirname} in a browser`,
);
} }
export function loadGenerator(name: string, dirname: string): { filepath: string, value: Function } { export function loadGenerator(
throw new Error(`Cannot load generator ${name} relative to ${dirname} in a browser`); name: string,
dirname: string,
): { filepath: string, value: Function } {
throw new Error(
`Cannot load generator ${name} relative to ${dirname} in a browser`,
);
} }

View File

@ -5,7 +5,7 @@ import typeof * as indexType from "./index";
// Kind of gross, but essentially asserting that the exports of this module are the same as the // Kind of gross, but essentially asserting that the exports of this module are the same as the
// exports of index-browser, since this file may be replaced at bundle time with index-browser. // exports of index-browser, since this file may be replaced at bundle time with index-browser.
((({}: any) : $Exact<indexBrowserType>): $Exact<indexType>); ((({}: any): $Exact<indexBrowserType>): $Exact<indexType>);
export * from "./configuration"; export * from "./configuration";
export * from "./plugins"; export * from "./plugins";

View File

@ -15,17 +15,22 @@ const BABEL_PRESET_ORG_RE = /^(@babel[/\/])(?!preset-|[^/\/]+[/\/])/;
const OTHER_PLUGIN_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-plugin-|[^/\/]+[/\/])/; const OTHER_PLUGIN_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-plugin-|[^/\/]+[/\/])/;
const OTHER_PRESET_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-preset-|[^/\/]+[/\/])/; const OTHER_PRESET_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-preset-|[^/\/]+[/\/])/;
export function resolvePlugin(name: string, dirname: string): string|null { export function resolvePlugin(name: string, dirname: string): string | null {
return resolveStandardizedName("plugin", name, dirname); return resolveStandardizedName("plugin", name, dirname);
} }
export function resolvePreset(name: string, dirname: string): string|null { export function resolvePreset(name: string, dirname: string): string | null {
return resolveStandardizedName("preset", name, dirname); return resolveStandardizedName("preset", name, dirname);
} }
export function loadPlugin(name: string, dirname: string): { filepath: string, value: mixed } { export function loadPlugin(
name: string,
dirname: string,
): { filepath: string, value: mixed } {
const filepath = resolvePlugin(name, dirname); const filepath = resolvePlugin(name, dirname);
if (!filepath) throw new Error(`Plugin ${name} not found relative to ${dirname}`); if (!filepath) {
throw new Error(`Plugin ${name} not found relative to ${dirname}`);
}
return { return {
filepath, filepath,
@ -33,9 +38,14 @@ export function loadPlugin(name: string, dirname: string): { filepath: string, v
}; };
} }
export function loadPreset(name: string, dirname: string): { filepath: string, value: mixed } { export function loadPreset(
name: string,
dirname: string,
): { filepath: string, value: mixed } {
const filepath = resolvePreset(name, dirname); const filepath = resolvePreset(name, dirname);
if (!filepath) throw new Error(`Preset ${name} not found relative to ${dirname}`); if (!filepath) {
throw new Error(`Preset ${name} not found relative to ${dirname}`);
}
return { return {
filepath, filepath,
@ -43,16 +53,23 @@ export function loadPreset(name: string, dirname: string): { filepath: string, v
}; };
} }
export function loadParser(name: string, dirname: string): { filepath: string, value: Function } { export function loadParser(
name: string,
dirname: string,
): { filepath: string, value: Function } {
const filepath = resolve.sync(name, { basedir: dirname }); const filepath = resolve.sync(name, { basedir: dirname });
const mod = requireModule(filepath); const mod = requireModule(filepath);
if (!mod) { if (!mod) {
throw new Error(`Parser ${name} relative to ${dirname} does not export an object`); throw new Error(
`Parser ${name} relative to ${dirname} does not export an object`,
);
} }
if (typeof mod.parse !== "function") { if (typeof mod.parse !== "function") {
throw new Error(`Parser ${name} relative to ${dirname} does not export a .parse function`); throw new Error(
`Parser ${name} relative to ${dirname} does not export a .parse function`,
);
} }
return { return {
@ -61,16 +78,23 @@ export function loadParser(name: string, dirname: string): { filepath: string, v
}; };
} }
export function loadGenerator(name: string, dirname: string): { filepath: string, value: Function } { export function loadGenerator(
name: string,
dirname: string,
): { filepath: string, value: Function } {
const filepath = resolve.sync(name, { basedir: dirname }); const filepath = resolve.sync(name, { basedir: dirname });
const mod = requireModule(filepath); const mod = requireModule(filepath);
if (!mod) { if (!mod) {
throw new Error(`Generator ${name} relative to ${dirname} does not export an object`); throw new Error(
`Generator ${name} relative to ${dirname} does not export an object`,
);
} }
if (typeof mod.print !== "function") { if (typeof mod.print !== "function") {
throw new Error(`Generator ${name} relative to ${dirname} does not export a .print function`); throw new Error(
`Generator ${name} relative to ${dirname} does not export a .print function`,
);
} }
return { return {
@ -79,24 +103,39 @@ export function loadGenerator(name: string, dirname: string): { filepath: string
}; };
} }
function standardizeName(type: "plugin"|"preset", name: string) { function standardizeName(type: "plugin" | "preset", name: string) {
// Let absolute and relative paths through. // Let absolute and relative paths through.
if (path.isAbsolute(name)) return name; if (path.isAbsolute(name)) return name;
const isPreset = type === "preset"; const isPreset = type === "preset";
return name return (
name
// foo -> babel-preset-foo // foo -> babel-preset-foo
.replace(isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE, `babel-${type}-`) .replace(
isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE,
`babel-${type}-`,
)
// @babel/es2015 -> @babel/preset-es2015 // @babel/es2015 -> @babel/preset-es2015
.replace(isPreset ? BABEL_PRESET_ORG_RE : BABEL_PLUGIN_ORG_RE, `$1${type}-`) .replace(
isPreset ? BABEL_PRESET_ORG_RE : BABEL_PLUGIN_ORG_RE,
`$1${type}-`,
)
// @foo/mypreset -> @foo/babel-preset-mypreset // @foo/mypreset -> @foo/babel-preset-mypreset
.replace(isPreset ? OTHER_PRESET_ORG_RE : OTHER_PLUGIN_ORG_RE, `$1babel-${type}-`) .replace(
isPreset ? OTHER_PRESET_ORG_RE : OTHER_PLUGIN_ORG_RE,
`$1babel-${type}-`,
)
// module:mypreset -> mypreset // module:mypreset -> mypreset
.replace(EXACT_RE, ""); .replace(EXACT_RE, "")
);
} }
function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname: string = process.cwd()) { function resolveStandardizedName(
type: "plugin" | "preset",
name: string,
dirname: string = process.cwd(),
) {
const standardizedName = standardizeName(type, name); const standardizedName = standardizeName(type, name);
try { try {
@ -109,7 +148,7 @@ function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname:
try { try {
resolve.sync(name, { basedir: dirname }); resolve.sync(name, { basedir: dirname });
resolvedOriginal = true; resolvedOriginal = true;
} catch (e2) { } } catch (e2) {}
if (resolvedOriginal) { if (resolvedOriginal) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
@ -119,9 +158,11 @@ function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname:
let resolvedBabel = false; let resolvedBabel = false;
try { try {
resolve.sync(standardizeName(type, "@babel/" + name), { basedir: dirname }); resolve.sync(standardizeName(type, "@babel/" + name), {
basedir: dirname,
});
resolvedBabel = true; resolvedBabel = true;
} catch (e2) { } } catch (e2) {}
if (resolvedBabel) { if (resolvedBabel) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
@ -133,7 +174,7 @@ function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname:
try { try {
resolve.sync(standardizeName(oppositeType, name), { basedir: dirname }); resolve.sync(standardizeName(oppositeType, name), { basedir: dirname });
resolvedOppositeType = true; resolvedOppositeType = true;
} catch (e2) { } } catch (e2) {}
if (resolvedOppositeType) { if (resolvedOppositeType) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len

View File

@ -11,14 +11,19 @@ import path from "path";
import traverse from "babel-traverse"; import traverse from "babel-traverse";
import clone from "lodash/clone"; import clone from "lodash/clone";
import { loadPlugin, loadPreset, loadParser, loadGenerator } from "./loading/files"; import {
loadPlugin,
loadPreset,
loadParser,
loadGenerator,
} from "./loading/files";
type MergeOptions = { type MergeOptions = {
+type: "arguments"|"options"|"preset", +type: "arguments" | "options" | "preset",
options: {}, options: {},
alias: string, alias: string,
loc: string, loc: string,
dirname: string dirname: string,
}; };
const optionNames = new Set([ const optionNames = new Set([
@ -74,8 +79,8 @@ const ALLOWED_PLUGIN_KEYS = new Set([
export default function manageOptions(opts: {}): { export default function manageOptions(opts: {}): {
options: Object, options: Object,
passes: Array<Array<[ Plugin, ?{} ]>>, passes: Array<Array<[Plugin, ?{}]>>,
}|null { } | null {
return new OptionManager().init(opts); return new OptionManager().init(opts);
} }
@ -100,9 +105,12 @@ class OptionManager {
mergeOptions(config: MergeOptions, pass?: Array<[Plugin, ?{}]>) { mergeOptions(config: MergeOptions, pass?: Array<[Plugin, ?{}]>) {
const result = loadConfig(config); const result = loadConfig(config);
const plugins = result.plugins.map((descriptor) => loadPluginDescriptor(descriptor)); const plugins = result.plugins.map(descriptor =>
const presets = result.presets.map((descriptor) => loadPresetDescriptor(descriptor)); loadPluginDescriptor(descriptor),
);
const presets = result.presets.map(descriptor =>
loadPresetDescriptor(descriptor),
);
if ( if (
config.options.passPerPreset != null && config.options.passPerPreset != null &&
@ -148,7 +156,8 @@ class OptionManager {
// There are a few case where thrown errors will try to annotate themselves multiple times, so // There are a few case where thrown errors will try to annotate themselves multiple times, so
// to keep things simple we just bail out if re-wrapping the message. // to keep things simple we just bail out if re-wrapping the message.
if (!/^\[BABEL\]/.test(e.message)) { if (!/^\[BABEL\]/.test(e.message)) {
const filename = typeof opts.filename === "string" ? opts.filename : null; const filename =
typeof opts.filename === "string" ? opts.filename : null;
e.message = `[BABEL] ${filename || "unknown"}: ${e.message}`; e.message = `[BABEL] ${filename || "unknown"}: ${e.message}`;
} }
@ -160,9 +169,10 @@ class OptionManager {
// Tack the passes onto the object itself so that, if this object is passed back to Babel a second time, // Tack the passes onto the object itself so that, if this object is passed back to Babel a second time,
// it will be in the right structure to not change behavior. // it will be in the right structure to not change behavior.
opts.plugins = this.passes[0]; opts.plugins = this.passes[0];
opts.presets = this.passes.slice(1) opts.presets = this.passes
.filter((plugins) => plugins.length > 0) .slice(1)
.map((plugins) => ({ plugins })); .filter(plugins => plugins.length > 0)
.map(plugins => ({ plugins }));
if (opts.inputSourceMap) { if (opts.inputSourceMap) {
opts.sourceMaps = true; opts.sourceMaps = true;
@ -199,7 +209,7 @@ class OptionManager {
} }
type BasicDescriptor = { type BasicDescriptor = {
value: {}|Function, value: {} | Function,
options: ?{}, options: ?{},
dirname: string, dirname: string,
alias: string, alias: string,
@ -209,19 +219,28 @@ type BasicDescriptor = {
/** /**
* Load and validate the given config into a set of options, plugins, and presets. * Load and validate the given config into a set of options, plugins, and presets.
*/ */
function loadConfig(config): { function loadConfig(
config,
): {
options: {}, options: {},
plugins: Array<BasicDescriptor>, plugins: Array<BasicDescriptor>,
presets: Array<BasicDescriptor>, presets: Array<BasicDescriptor>,
} { } {
const options = normalizeOptions(config); const options = normalizeOptions(config);
if (config.options.plugins != null && !Array.isArray(config.options.plugins)) { if (
config.options.plugins != null &&
!Array.isArray(config.options.plugins)
) {
throw new Error(".plugins should be an array, null, or undefined"); throw new Error(".plugins should be an array, null, or undefined");
} }
const plugins = (config.options.plugins || []).map((plugin, index) => { const plugins = (config.options.plugins || []).map((plugin, index) => {
const { filepath, value, options } = normalizePair(plugin, loadPlugin, config.dirname); const { filepath, value, options } = normalizePair(
plugin,
loadPlugin,
config.dirname,
);
return { return {
alias: filepath || `${config.loc}$${index}`, alias: filepath || `${config.loc}$${index}`,
@ -232,12 +251,19 @@ function loadConfig(config): {
}; };
}); });
if (config.options.presets != null && !Array.isArray(config.options.presets)) { if (
config.options.presets != null &&
!Array.isArray(config.options.presets)
) {
throw new Error(".presets should be an array, null, or undefined"); throw new Error(".presets should be an array, null, or undefined");
} }
const presets = (config.options.presets || []).map((preset, index) => { const presets = (config.options.presets || []).map((preset, index) => {
const { filepath, value, options } = normalizePair(preset, loadPreset, config.dirname); const { filepath, value, options } = normalizePair(
preset,
loadPreset,
config.dirname,
);
return { return {
alias: filepath || `${config.loc}$${index}`, alias: filepath || `${config.loc}$${index}`,
@ -255,7 +281,9 @@ function loadConfig(config): {
* Load a generic plugin/preset from the given descriptor loaded from the config object. * Load a generic plugin/preset from the given descriptor loaded from the config object.
*/ */
function loadDescriptor(descriptor, skipOptions) { function loadDescriptor(descriptor, skipOptions) {
if (typeof descriptor.value !== "function") return { value: descriptor.value, descriptor }; if (typeof descriptor.value !== "function") {
return { value: descriptor.value, descriptor };
}
const { value, options } = descriptor; const { value, options } = descriptor;
let item; let item;
@ -266,7 +294,9 @@ function loadDescriptor(descriptor, skipOptions) {
item = value(context, options, { dirname: descriptor.dirname }); item = value(context, options, { dirname: descriptor.dirname });
} }
} catch (e) { } catch (e) {
if (descriptor.alias) e.message += ` (While processing: ${JSON.stringify(descriptor.alias)})`; if (descriptor.alias) {
e.message += ` (While processing: ${JSON.stringify(descriptor.alias)})`;
}
throw e; throw e;
} }
@ -282,26 +312,37 @@ function loadDescriptor(descriptor, skipOptions) {
*/ */
const PLUGIN_CACHE = new WeakMap(); const PLUGIN_CACHE = new WeakMap();
function loadPluginDescriptor(descriptor) { function loadPluginDescriptor(descriptor) {
if (descriptor.value instanceof Plugin) return [ descriptor.value, descriptor.options ]; if (descriptor.value instanceof Plugin) {
return [descriptor.value, descriptor.options];
}
let result = PLUGIN_CACHE.get(descriptor.value); let result = PLUGIN_CACHE.get(descriptor.value);
if (!result) { if (!result) {
result = instantiatePlugin(loadDescriptor(descriptor, true /* skipOptions */)); result = instantiatePlugin(
loadDescriptor(descriptor, true /* skipOptions */),
);
PLUGIN_CACHE.set(descriptor.value, result); PLUGIN_CACHE.set(descriptor.value, result);
} }
return [ result, descriptor.options]; return [result, descriptor.options];
} }
function instantiatePlugin({ value: pluginObj, descriptor }) { function instantiatePlugin({ value: pluginObj, descriptor }) {
Object.keys(pluginObj).forEach((key) => { Object.keys(pluginObj).forEach(key => {
if (!ALLOWED_PLUGIN_KEYS.has(key)) { if (!ALLOWED_PLUGIN_KEYS.has(key)) {
throw new Error(messages.get("pluginInvalidProperty", descriptor.alias, key)); throw new Error(
messages.get("pluginInvalidProperty", descriptor.alias, key),
);
} }
}); });
if (pluginObj.visitor && (pluginObj.visitor.enter || pluginObj.visitor.exit)) { if (
throw new Error("Plugins aren't allowed to specify catch-all enter/exit handlers. " + pluginObj.visitor &&
"Please target individual nodes."); (pluginObj.visitor.enter || pluginObj.visitor.exit)
) {
throw new Error(
"Plugins aren't allowed to specify catch-all enter/exit handlers. " +
"Please target individual nodes.",
);
} }
const plugin = Object.assign({}, pluginObj, { const plugin = Object.assign({}, pluginObj, {
@ -325,8 +366,14 @@ function instantiatePlugin({ value: pluginObj, descriptor }) {
plugin.pre = chain(inherits.pre, plugin.pre); plugin.pre = chain(inherits.pre, plugin.pre);
plugin.post = chain(inherits.post, plugin.post); plugin.post = chain(inherits.post, plugin.post);
plugin.manipulateOptions = chain(inherits.manipulateOptions, plugin.manipulateOptions); plugin.manipulateOptions = chain(
plugin.visitor = traverse.visitors.merge([inherits.visitor, plugin.visitor]); inherits.manipulateOptions,
plugin.manipulateOptions,
);
plugin.visitor = traverse.visitors.merge([
inherits.visitor,
plugin.visitor,
]);
} }
return new Plugin(plugin, descriptor.alias); return new Plugin(plugin, descriptor.alias);
@ -371,10 +418,18 @@ function normalizeOptions(config) {
} }
if (type === "preset") { if (type === "preset") {
if (options.only !== undefined) throw new Error(`${alias}.only is not supported in a preset`); if (options.only !== undefined) {
if (options.ignore !== undefined) throw new Error(`${alias}.ignore is not supported in a preset`); throw new Error(`${alias}.only is not supported in a preset`);
if (options.extends !== undefined) throw new Error(`${alias}.extends is not supported in a preset`); }
if (options.env !== undefined) throw new Error(`${alias}.env is not supported in a preset`); if (options.ignore !== undefined) {
throw new Error(`${alias}.ignore is not supported in a preset`);
}
if (options.extends !== undefined) {
throw new Error(`${alias}.extends is not supported in a preset`);
}
if (options.env !== undefined) {
throw new Error(`${alias}.env is not supported in a preset`);
}
} }
if (options.sourceMap !== undefined) { if (options.sourceMap !== undefined) {
@ -390,7 +445,10 @@ function normalizeOptions(config) {
// check for an unknown option // check for an unknown option
if (!optionNames.has(key)) { if (!optionNames.has(key)) {
if (removed[key]) { if (removed[key]) {
throw new ReferenceError(`Using removed Babel 5 option: ${alias}.${key} - ${removed[key].message}`); throw new ReferenceError(
`Using removed Babel 5 option: ${alias}.${key} - ${removed[key]
.message}`,
);
} else { } else {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const unknownOptErr = `Unknown option: ${alias}.${key}. Check out http://babeljs.io/docs/usage/options/ for more information about options.`; const unknownOptErr = `Unknown option: ${alias}.${key}. Check out http://babeljs.io/docs/usage/options/ for more information about options.`;
@ -402,12 +460,21 @@ function normalizeOptions(config) {
if (options.parserOpts && typeof options.parserOpts.parser === "string") { if (options.parserOpts && typeof options.parserOpts.parser === "string") {
options.parserOpts = Object.assign({}, options.parserOpts); options.parserOpts = Object.assign({}, options.parserOpts);
options.parserOpts.parser = loadParser(options.parserOpts.parser, config.dirname).value; options.parserOpts.parser = loadParser(
options.parserOpts.parser,
config.dirname,
).value;
} }
if (options.generatorOpts && typeof options.generatorOpts.generator === "string") { if (
options.generatorOpts &&
typeof options.generatorOpts.generator === "string"
) {
options.generatorOpts = Object.assign({}, options.generatorOpts); options.generatorOpts = Object.assign({}, options.generatorOpts);
options.generatorOpts.generator = loadGenerator(options.generatorOpts.generator, config.dirname).value; options.generatorOpts.generator = loadGenerator(
options.generatorOpts.generator,
config.dirname,
).value;
} }
delete options.passPerPreset; delete options.passPerPreset;
@ -420,16 +487,22 @@ function normalizeOptions(config) {
/** /**
* Given a plugin/preset item, resolve it into a standard format. * Given a plugin/preset item, resolve it into a standard format.
*/ */
function normalizePair(pair: mixed, resolver, dirname): { function normalizePair(
filepath: string|null, pair: mixed,
value: {}|Function, resolver,
dirname,
): {
filepath: string | null,
value: {} | Function,
options: ?{}, options: ?{},
} { } {
let options; let options;
let value = pair; let value = pair;
if (Array.isArray(pair)) { if (Array.isArray(pair)) {
if (pair.length > 2) { if (pair.length > 2) {
throw new Error(`Unexpected extra options ${JSON.stringify(pair.slice(2))}.`); throw new Error(
`Unexpected extra options ${JSON.stringify(pair.slice(2))}.`,
);
} }
[value, options] = pair; [value, options] = pair;
@ -437,10 +510,7 @@ function normalizePair(pair: mixed, resolver, dirname): {
let filepath = null; let filepath = null;
if (typeof value === "string") { if (typeof value === "string") {
({ ({ filepath, value } = resolver(value, dirname));
filepath,
value,
} = resolver(value, dirname));
} }
if (!value) { if (!value) {
@ -456,11 +526,15 @@ function normalizePair(pair: mixed, resolver, dirname): {
} }
if (typeof value !== "object" && typeof value !== "function") { if (typeof value !== "object" && typeof value !== "function") {
throw new Error(`Unsupported format: ${typeof value}. Expected an object or a function.`); throw new Error(
`Unsupported format: ${typeof value}. Expected an object or a function.`,
);
} }
if (options != null && typeof options !== "object") { if (options != null && typeof options !== "object") {
throw new Error("Plugin/Preset options must be an object, null, or undefined"); throw new Error(
"Plugin/Preset options must be an object, null, or undefined",
);
} }
return { filepath, value, options }; return { filepath, value, options };

View File

@ -5,8 +5,13 @@ export default class Plugin {
if (plugin.name != null && typeof plugin.name !== "string") { if (plugin.name != null && typeof plugin.name !== "string") {
throw new Error("Plugin .name must be a string, null, or undefined"); throw new Error("Plugin .name must be a string, null, or undefined");
} }
if (plugin.manipulateOptions != null && typeof plugin.manipulateOptions !== "function") { if (
throw new Error("Plugin .manipulateOptions must be a function, null, or undefined"); plugin.manipulateOptions != null &&
typeof plugin.manipulateOptions !== "function"
) {
throw new Error(
"Plugin .manipulateOptions must be a function, null, or undefined",
);
} }
if (plugin.post != null && typeof plugin.post !== "function") { if (plugin.post != null && typeof plugin.post !== "function") {
throw new Error("Plugin .post must be a function, null, or undefined"); throw new Error("Plugin .post must be a function, null, or undefined");

View File

@ -2,52 +2,58 @@
/* eslint max-len: "off" */ /* eslint max-len: "off" */
export default { export default {
"auxiliaryComment": { auxiliaryComment: {
"message": "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`", message: "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`",
}, },
"blacklist": { blacklist: {
"message": "Put the specific transforms you want in the `plugins` option", message: "Put the specific transforms you want in the `plugins` option",
}, },
"breakConfig": { breakConfig: {
"message": "This is not a necessary option in Babel 6", message: "This is not a necessary option in Babel 6",
}, },
"experimental": { experimental: {
"message": "Put the specific transforms you want in the `plugins` option", message: "Put the specific transforms you want in the `plugins` option",
}, },
"externalHelpers": { externalHelpers: {
"message": "Use the `external-helpers` plugin instead. Check out http://babeljs.io/docs/plugins/external-helpers/", message:
"Use the `external-helpers` plugin instead. Check out http://babeljs.io/docs/plugins/external-helpers/",
}, },
"extra": { extra: {
"message": "", message: "",
}, },
"jsxPragma": { jsxPragma: {
"message": "use the `pragma` option in the `react-jsx` plugin . Check out http://babeljs.io/docs/plugins/transform-react-jsx/", message:
"use the `pragma` option in the `react-jsx` plugin . Check out http://babeljs.io/docs/plugins/transform-react-jsx/",
}, },
// "keepModuleIdExtensions": { // "keepModuleIdExtensions": {
// "message": "" // "message": ""
// }, // },
"loose": { loose: {
"message": "Specify the `loose` option for the relevant plugin you are using or use a preset that sets the option.", message:
"Specify the `loose` option for the relevant plugin you are using or use a preset that sets the option.",
}, },
"metadataUsedHelpers": { metadataUsedHelpers: {
"message": "Not required anymore as this is enabled by default", message: "Not required anymore as this is enabled by default",
}, },
"modules": { modules: {
"message": "Use the corresponding module transform plugin in the `plugins` option. Check out http://babeljs.io/docs/plugins/#modules", message:
"Use the corresponding module transform plugin in the `plugins` option. Check out http://babeljs.io/docs/plugins/#modules",
}, },
"nonStandard": { nonStandard: {
"message": "Use the `react-jsx` and `flow-strip-types` plugins to support JSX and Flow. Also check out the react preset http://babeljs.io/docs/plugins/preset-react/", message:
"Use the `react-jsx` and `flow-strip-types` plugins to support JSX and Flow. Also check out the react preset http://babeljs.io/docs/plugins/preset-react/",
}, },
"optional": { optional: {
"message": "Put the specific transforms you want in the `plugins` option", message: "Put the specific transforms you want in the `plugins` option",
}, },
"sourceMapName": { sourceMapName: {
"message": "Use the `sourceMapTarget` option", message: "Use the `sourceMapTarget` option",
}, },
"stage": { stage: {
"message": "Check out the corresponding stage-x presets http://babeljs.io/docs/plugins/#presets", message:
"Check out the corresponding stage-x presets http://babeljs.io/docs/plugins/#presets",
}, },
"whitelist": { whitelist: {
"message": "Put the specific transforms you want in the `plugins` option", message: "Put the specific transforms you want in the `plugins` option",
}, },
}; };

View File

@ -12,7 +12,7 @@ export template from "babel-template";
import loadConfig from "./config"; import loadConfig from "./config";
export function loadOptions(opts): Object|null { export function loadOptions(opts): Object | null {
const config = loadConfig(opts); const config = loadConfig(opts);
return config ? config.options : null; return config ? config.options : null;
@ -41,4 +41,10 @@ export {
* Recommended set of compilable extensions. Not used in babel-core directly, but meant as * Recommended set of compilable extensions. Not used in babel-core directly, but meant as
* as an easy source for tooling making use of babel-core. * as an easy source for tooling making use of babel-core.
*/ */
export const DEFAULT_EXTENSIONS = Object.freeze([".js", ".jsx", ".es6", ".es", ".mjs"]); export const DEFAULT_EXTENSIONS = Object.freeze([
".js",
".jsx",
".es6",
".es",
".mjs",
]);

View File

@ -20,17 +20,29 @@ const buildUmdWrapper = template(`
function buildGlobal(namespace, builder) { function buildGlobal(namespace, builder) {
const body = []; const body = [];
const container = t.functionExpression(null, [t.identifier("global")], t.blockStatement(body)); const container = t.functionExpression(
null,
[t.identifier("global")],
t.blockStatement(body),
);
const tree = t.program([ const tree = t.program([
t.expressionStatement(t.callExpression(container, [helpers.get("selfGlobal")]))]); t.expressionStatement(
t.callExpression(container, [helpers.get("selfGlobal")]),
),
]);
body.push(t.variableDeclaration("var", [ body.push(
t.variableDeclaration("var", [
t.variableDeclarator( t.variableDeclarator(
namespace, namespace,
t.assignmentExpression("=", t.memberExpression(t.identifier("global"), namespace), t.assignmentExpression(
t.objectExpression([])) "=",
t.memberExpression(t.identifier("global"), namespace),
t.objectExpression([]),
), ),
])); ),
]),
);
builder(body); builder(body);
@ -39,9 +51,11 @@ function buildGlobal(namespace, builder) {
function buildUmd(namespace, builder) { function buildUmd(namespace, builder) {
const body = []; const body = [];
body.push(t.variableDeclaration("var", [ body.push(
t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.identifier("global")), t.variableDeclarator(namespace, t.identifier("global")),
])); ]),
);
builder(body); builder(body);
@ -51,7 +65,7 @@ function buildUmd(namespace, builder) {
BROWSER_ARGUMENTS: t.assignmentExpression( BROWSER_ARGUMENTS: t.assignmentExpression(
"=", "=",
t.memberExpression(t.identifier("root"), namespace), t.memberExpression(t.identifier("root"), namespace),
t.objectExpression([]) t.objectExpression([]),
), ),
COMMON_ARGUMENTS: t.identifier("exports"), COMMON_ARGUMENTS: t.identifier("exports"),
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]), AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
@ -63,31 +77,39 @@ function buildUmd(namespace, builder) {
function buildVar(namespace, builder) { function buildVar(namespace, builder) {
const body = []; const body = [];
body.push(t.variableDeclaration("var", [ body.push(
t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.objectExpression([])), t.variableDeclarator(namespace, t.objectExpression([])),
])); ]),
);
builder(body); builder(body);
body.push(t.expressionStatement(namespace)); body.push(t.expressionStatement(namespace));
return t.program(body); return t.program(body);
} }
function buildHelpers(body, namespace, whitelist) { function buildHelpers(body, namespace, whitelist) {
helpers.list.forEach(function (name) { helpers.list.forEach(function(name) {
if (whitelist && whitelist.indexOf(name) < 0) return; if (whitelist && whitelist.indexOf(name) < 0) return;
const key = t.identifier(name); const key = t.identifier(name);
body.push(t.expressionStatement( body.push(
t.assignmentExpression("=", t.memberExpression(namespace, key), helpers.get(name)) t.expressionStatement(
)); t.assignmentExpression(
"=",
t.memberExpression(namespace, key),
helpers.get(name),
),
),
);
}); });
} }
export default function ( export default function(
whitelist?: Array<string>, whitelist?: Array<string>,
outputType: "global" | "umd" | "var" = "global", outputType: "global" | "umd" | "var" = "global",
) { ) {
const namespace = t.identifier("babelHelpers"); const namespace = t.identifier("babelHelpers");
const builder = function (body) { const builder = function(body) {
return buildHelpers(body, namespace, whitelist); return buildHelpers(body, namespace, whitelist);
}; };

View File

@ -45,7 +45,7 @@ export default class File extends Store {
// passed babel-core's export object, which loads this file, and this 'loadConfig' loading plugins. // passed babel-core's export object, which loads this file, and this 'loadConfig' loading plugins.
INTERNAL_PLUGINS = loadConfig({ INTERNAL_PLUGINS = loadConfig({
babelrc: false, babelrc: false,
plugins: [ blockHoistPlugin ], plugins: [blockHoistPlugin],
}).passes[0]; }).passes[0];
} }
@ -61,7 +61,7 @@ export default class File extends Store {
}; };
for (const pluginPairs of passes) { for (const pluginPairs of passes) {
for (const [ plugin ] of pluginPairs) { for (const [plugin] of pluginPairs) {
if (plugin.manipulateOptions) { if (plugin.manipulateOptions) {
plugin.manipulateOptions(this.opts, this.parserOpts, this); plugin.manipulateOptions(this.opts, this.parserOpts, this);
} }
@ -150,7 +150,7 @@ export default class File extends Store {
if (opts.sourceRoot != null) { if (opts.sourceRoot != null) {
// remove sourceRoot from filename // remove sourceRoot from filename
const sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?"); const sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "/?");
filenameRelative = filenameRelative.replace(sourceRootRegEx, ""); filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
} }
@ -172,17 +172,25 @@ export default class File extends Store {
resolveModuleSource(source: string): string { resolveModuleSource(source: string): string {
const resolveModuleSource = this.opts.resolveModuleSource; const resolveModuleSource = this.opts.resolveModuleSource;
if (resolveModuleSource) source = resolveModuleSource(source, this.opts.filename); if (resolveModuleSource) {
source = resolveModuleSource(source, this.opts.filename);
}
return source; return source;
} }
addImport(source: string, imported: string, name?: string = imported): Object { addImport(
source: string,
imported: string,
name?: string = imported,
): Object {
const alias = `${source}:${imported}`; const alias = `${source}:${imported}`;
let id = this.dynamicImportIds[alias]; let id = this.dynamicImportIds[alias];
if (!id) { if (!id) {
source = this.resolveModuleSource(source); source = this.resolveModuleSource(source);
id = this.dynamicImportIds[alias] = this.scope.generateUidIdentifier(name); id = this.dynamicImportIds[alias] = this.scope.generateUidIdentifier(
name,
);
const specifiers = []; const specifiers = [];
@ -222,7 +230,9 @@ export default class File extends Store {
} }
const ref = getHelper(name); const ref = getHelper(name);
const uid = this.declarations[name] = this.scope.generateUidIdentifier(name); const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
name,
));
if (t.isFunctionExpression(ref) && !ref.id) { if (t.isFunctionExpression(ref) && !ref.id) {
ref.body._compact = true; ref.body._compact = true;
@ -257,7 +267,9 @@ export default class File extends Store {
const declar = this.declarations[name]; const declar = this.declarations[name];
if (declar) return declar; if (declar) return declar;
const uid = this.declarations[name] = this.scope.generateUidIdentifier("templateObject"); const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
"templateObject",
));
const helperId = this.addHelper(helperName); const helperId = this.addHelper(helperName);
const init = t.callExpression(helperId, [strings, raw]); const init = t.callExpression(helperId, [strings, raw]);
@ -270,7 +282,11 @@ export default class File extends Store {
return uid; return uid;
} }
buildCodeFrameError(node: Object, msg: string, Error: typeof Error = SyntaxError): Error { buildCodeFrameError(
node: Object,
msg: string,
Error: typeof Error = SyntaxError,
): Error {
const loc = node && (node.loc || node._loc); const loc = node && (node.loc || node._loc);
const err = new Error(msg); const err = new Error(msg);
@ -280,7 +296,8 @@ export default class File extends Store {
} else { } else {
traverse(node, errorVisitor, this.scope, err); traverse(node, errorVisitor, this.scope, err);
err.message += " (This is an error on an internal node. Probably an internal error"; err.message +=
" (This is an error on an internal node. Probably an internal error";
if (err.loc) { if (err.loc) {
err.message += ". Location has been estimated."; err.message += ". Location has been estimated.";
@ -308,7 +325,7 @@ export default class File extends Store {
// single source file to a single output file. // single source file to a single output file.
const source = outputMapConsumer.sources[0]; const source = outputMapConsumer.sources[0];
inputMapConsumer.eachMapping(function (mapping) { inputMapConsumer.eachMapping(function(mapping) {
const generatedPosition = outputMapConsumer.generatedPositionFor({ const generatedPosition = outputMapConsumer.generatedPositionFor({
line: mapping.generatedLine, line: mapping.generatedLine,
column: mapping.generatedColumn, column: mapping.generatedColumn,
@ -318,7 +335,10 @@ export default class File extends Store {
mergedGenerator.addMapping({ mergedGenerator.addMapping({
source: mapping.source, source: mapping.source,
original: mapping.source == null ? null : { original:
mapping.source == null
? null
: {
line: mapping.originalLine, line: mapping.originalLine,
column: mapping.originalColumn, column: mapping.originalColumn,
}, },
@ -385,15 +405,15 @@ export default class File extends Store {
const passes = []; const passes = [];
const visitors = []; const visitors = [];
for (const [ plugin, pluginOpts ] of pluginPairs.concat(INTERNAL_PLUGINS)) { for (const [plugin, pluginOpts] of pluginPairs.concat(INTERNAL_PLUGINS)) {
const pass = new PluginPass(this, plugin.key, pluginOpts); const pass = new PluginPass(this, plugin.key, pluginOpts);
passPairs.push([ plugin, pass ]); passPairs.push([plugin, pass]);
passes.push(pass); passes.push(pass);
visitors.push(plugin.visitor); visitors.push(plugin.visitor);
} }
for (const [ plugin, pass ] of passPairs) { for (const [plugin, pass] of passPairs) {
const fn = plugin.pre; const fn = plugin.pre;
if (fn) fn.call(pass, this); if (fn) fn.call(pass, this);
} }
@ -401,16 +421,19 @@ export default class File extends Store {
debug(this.opts, "Start transform traverse"); debug(this.opts, "Start transform traverse");
// merge all plugin visitors into a single visitor // merge all plugin visitors into a single visitor
const visitor = traverse.visitors.merge(visitors, passes, this.opts.wrapPluginVisitorMethod); const visitor = traverse.visitors.merge(
visitors,
passes,
this.opts.wrapPluginVisitorMethod,
);
traverse(this.ast, visitor, this.scope); traverse(this.ast, visitor, this.scope);
debug(this.opts, "End transform traverse"); debug(this.opts, "End transform traverse");
for (const [ plugin, pass ] of passPairs) { for (const [plugin, pass] of passPairs) {
const fn = plugin.post; const fn = plugin.post;
if (fn) fn.call(pass, this); if (fn) fn.call(pass, this);
} }
} }
return this.generate(); return this.generate();
@ -428,7 +451,7 @@ export default class File extends Store {
err._babel = true; err._babel = true;
} }
let message = err.message = `${this.opts.filename}: ${err.message}`; let message = (err.message = `${this.opts.filename}: ${err.message}`);
const loc = err.loc; const loc = err.loc;
if (loc) { if (loc) {
@ -530,8 +553,11 @@ export default class File extends Store {
debug(this.opts, "Generation start"); debug(this.opts, "Generation start");
const _result = gen(ast, opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : opts, const _result = gen(
this.code); ast,
opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : opts,
this.code,
);
result.code = _result.code; result.code = _result.code;
result.map = _result.map; result.map = _result.map;

View File

@ -5,7 +5,11 @@ import * as t from "babel-types";
import File from "./file"; import File from "./file";
import loadConfig from "../config"; import loadConfig from "../config";
export function analyse(code: string, opts: Object = {}, visitor?: Object): ?BabelFileMetadata { export function analyse(
code: string,
opts: Object = {},
visitor?: Object,
): ?BabelFileMetadata {
opts.code = false; opts.code = false;
if (visitor) { if (visitor) {
opts.plugins = opts.plugins || []; opts.plugins = opts.plugins || [];
@ -19,14 +23,18 @@ export function transform(code: string, opts?: Object): BabelFileResult {
if (config === null) return null; if (config === null) return null;
const file = new File(config); const file = new File(config);
return file.wrap(code, function () { return file.wrap(code, function() {
file.addCode(code); file.addCode(code);
file.parseCode(code); file.parseCode(code);
return file.transform(); return file.transform();
}); });
} }
export function transformFromAst(ast: Object, code: string, opts: Object): BabelFileResult { export function transformFromAst(
ast: Object,
code: string,
opts: Object,
): BabelFileResult {
const config = loadConfig(opts); const config = loadConfig(opts);
if (config === null) return null; if (config === null) return null;
@ -37,14 +45,18 @@ export function transformFromAst(ast: Object, code: string, opts: Object): Babel
} }
const file = new File(config); const file = new File(config);
return file.wrap(code, function () { return file.wrap(code, function() {
file.addCode(code); file.addCode(code);
file.addAst(ast); file.addAst(ast);
return file.transform(); return file.transform();
}); });
} }
export function transformFile(filename: string, opts?: Object, callback: Function) { export function transformFile(
filename: string,
opts?: Object,
callback: Function,
) {
if (typeof opts === "function") { if (typeof opts === "function") {
callback = opts; callback = opts;
opts = {}; opts = {};
@ -54,13 +66,13 @@ export function transformFile(filename: string, opts?: Object, callback: Functio
const config = loadConfig(opts); const config = loadConfig(opts);
if (config === null) return callback(null, null); if (config === null) return callback(null, null);
fs.readFile(filename, function (err, code) { fs.readFile(filename, function(err, code) {
let result; let result;
if (!err) { if (!err) {
try { try {
const file = new File(config); const file = new File(config);
result = file.wrap(code, function () { result = file.wrap(code, function() {
file.addCode(code); file.addCode(code);
file.parseCode(code); file.parseCode(code);
return file.transform(); return file.transform();
@ -78,7 +90,10 @@ export function transformFile(filename: string, opts?: Object, callback: Functio
}); });
} }
export function transformFileSync(filename: string, opts?: Object = {}): string { export function transformFileSync(
filename: string,
opts?: Object = {},
): string {
opts.filename = filename; opts.filename = filename;
const config = loadConfig(opts); const config = loadConfig(opts);
if (config === null) return null; if (config === null) return null;
@ -86,7 +101,7 @@ export function transformFileSync(filename: string, opts?: Object = {}): string
const code = fs.readFileSync(filename, "utf8"); const code = fs.readFileSync(filename, "utf8");
const file = new File(config); const file = new File(config);
return file.wrap(code, function () { return file.wrap(code, function() {
file.addCode(code); file.addCode(code);
file.parseCode(code); file.parseCode(code);
return file.transform(); return file.transform();

View File

@ -17,7 +17,7 @@ function assertNotIgnored(result) {
// shim // shim
function transformAsync(code, opts) { function transformAsync(code, opts) {
return { return {
then: function (resolve) { then: function(resolve) {
resolve(babel.transform(code, opts)); resolve(babel.transform(code, opts));
}, },
}; };
@ -55,11 +55,14 @@ describe("parser and generator options", function() {
it("experimental syntax", function() { it("experimental syntax", function() {
const experimental = "var a: number = 1;"; const experimental = "var a: number = 1;";
assert.deepEqual(newTransform(experimental).ast, babel.transform(experimental, { assert.deepEqual(
newTransform(experimental).ast,
babel.transform(experimental, {
parserOpts: { parserOpts: {
plugins: ["flow"], plugins: ["flow"],
}, },
}).ast); }).ast,
);
assert.equal(newTransform(experimental).code, experimental); assert.equal(newTransform(experimental).code, experimental);
function newTransformWithPlugins(string) { function newTransformWithPlugins(string) {
@ -74,126 +77,158 @@ describe("parser and generator options", function() {
}); });
} }
assert.deepEqual(newTransformWithPlugins(experimental).ast, babel.transform(experimental, { assert.deepEqual(
newTransformWithPlugins(experimental).ast,
babel.transform(experimental, {
parserOpts: { parserOpts: {
plugins: ["flow"], plugins: ["flow"],
}, },
}).ast); }).ast,
);
assert.equal(newTransformWithPlugins(experimental).code, experimental); assert.equal(newTransformWithPlugins(experimental).code, experimental);
}); });
it("other options", function() { it("other options", function() {
const experimental = "if (true) {\n import a from 'a';\n}"; const experimental = "if (true) {\n import a from 'a';\n}";
assert.notEqual(newTransform(experimental).ast, babel.transform(experimental, { assert.notEqual(
newTransform(experimental).ast,
babel.transform(experimental, {
parserOpts: { parserOpts: {
allowImportExportEverywhere: true, allowImportExportEverywhere: true,
}, },
}).ast); }).ast,
);
assert.equal(newTransform(experimental).code, experimental); assert.equal(newTransform(experimental).code, experimental);
}); });
}); });
describe("api", function () { describe("api", function() {
it("analyze", function () { it("analyze", function() {
assert.equal(babel.analyse("foobar;").marked.length, 0); assert.equal(babel.analyse("foobar;").marked.length, 0);
assert.equal(babel.analyse("foobar;", { assert.equal(
plugins: [new Plugin({ babel.analyse("foobar;", {
plugins: [
new Plugin({
visitor: { visitor: {
Program: function (path) { Program: function(path) {
path.mark("category", "foobar"); path.mark("category", "foobar");
}, },
}, },
})], }),
}).marked[0].message, "foobar"); ],
}).marked[0].message,
"foobar",
);
assert.equal(babel.analyse("foobar;", {}, { assert.equal(
Program: function (path) { babel.analyse(
"foobar;",
{},
{
Program: function(path) {
path.mark("category", "foobar"); path.mark("category", "foobar");
}, },
}).marked[0].message, "foobar");
});
it("exposes the resolvePlugin method", function() {
assert.throws(() => babel.resolvePlugin("nonexistent-plugin"),
/Cannot find module 'babel-plugin-nonexistent-plugin'/);
});
it("exposes the resolvePreset method", function() {
assert.throws(() => babel.resolvePreset("nonexistent-preset"),
/Cannot find module 'babel-preset-nonexistent-preset'/);
});
it("transformFile", function (done) {
babel.transformFile(__dirname + "/fixtures/api/file.js", {
babelrc: false,
}, function (err, res) {
if (err) return done(err);
assert.equal(res.code, "foo();");
done();
});
});
it("transformFileSync", function () {
assert.equal(babel.transformFileSync(__dirname + "/fixtures/api/file.js", {
babelrc: false,
}).code, "foo();");
});
it("options throw on falsy true", function () {
return assert.throws(
function () {
babel.transform("", {
plugins: [__dirname + "/../../babel-plugin-syntax-jsx", false],
});
}, },
/Error: \[BABEL\] unknown: Unexpected falsy value: false/ ).marked[0].message,
"foobar",
); );
}); });
it("options merge backwards", function () { it("exposes the resolvePlugin method", function() {
assert.throws(
() => babel.resolvePlugin("nonexistent-plugin"),
/Cannot find module 'babel-plugin-nonexistent-plugin'/,
);
});
it("exposes the resolvePreset method", function() {
assert.throws(
() => babel.resolvePreset("nonexistent-preset"),
/Cannot find module 'babel-preset-nonexistent-preset'/,
);
});
it("transformFile", function(done) {
babel.transformFile(
__dirname + "/fixtures/api/file.js",
{
babelrc: false,
},
function(err, res) {
if (err) return done(err);
assert.equal(res.code, "foo();");
done();
},
);
});
it("transformFileSync", function() {
assert.equal(
babel.transformFileSync(__dirname + "/fixtures/api/file.js", {
babelrc: false,
}).code,
"foo();",
);
});
it("options throw on falsy true", function() {
return assert.throws(function() {
babel.transform("", {
plugins: [__dirname + "/../../babel-plugin-syntax-jsx", false],
});
}, /Error: \[BABEL\] unknown: Unexpected falsy value: false/);
});
it("options merge backwards", function() {
return transformAsync("", { return transformAsync("", {
presets: [__dirname + "/../../babel-preset-es2015"], presets: [__dirname + "/../../babel-preset-es2015"],
plugins: [__dirname + "/../../babel-plugin-syntax-jsx"], plugins: [__dirname + "/../../babel-plugin-syntax-jsx"],
}).then(function (result) { }).then(function(result) {
assert.ok(result.options.plugins[0][0].manipulateOptions.toString().indexOf("jsx") >= 0); assert.ok(
result.options.plugins[0][0].manipulateOptions
.toString()
.indexOf("jsx") >= 0,
);
}); });
}); });
it("option wrapPluginVisitorMethod", function () { it("option wrapPluginVisitorMethod", function() {
let calledRaw = 0; let calledRaw = 0;
let calledIntercept = 0; let calledIntercept = 0;
babel.transform("function foo() { bar(foobar); }", { babel.transform("function foo() { bar(foobar); }", {
wrapPluginVisitorMethod: function (pluginAlias, visitorType, callback) { wrapPluginVisitorMethod: function(pluginAlias, visitorType, callback) {
if (pluginAlias !== "foobar") { if (pluginAlias !== "foobar") {
return callback; return callback;
} }
assert.equal(visitorType, "enter"); assert.equal(visitorType, "enter");
return function () { return function() {
calledIntercept++; calledIntercept++;
return callback.apply(this, arguments); return callback.apply(this, arguments);
}; };
}, },
plugins: [new Plugin({ plugins: [
new Plugin({
name: "foobar", name: "foobar",
visitor: { visitor: {
"Program|Identifier": function () { "Program|Identifier": function() {
calledRaw++; calledRaw++;
}, },
}, },
})], }),
],
}); });
assert.equal(calledRaw, 4); assert.equal(calledRaw, 4);
assert.equal(calledIntercept, 4); assert.equal(calledIntercept, 4);
}); });
it("pass per preset", function () { it("pass per preset", function() {
let aliasBaseType = null; let aliasBaseType = null;
function execTest(passPerPreset) { function execTest(passPerPreset) {
@ -201,13 +236,15 @@ describe("api", function () {
passPerPreset: passPerPreset, passPerPreset: passPerPreset,
presets: [ presets: [
// First preset with our plugin, "before" // First preset with our plugin, "before"
function () { function() {
return { return {
plugins: [ plugins: [
new Plugin({ new Plugin({
visitor: { visitor: {
Function: function (path) { Function: function(path) {
const alias = path.scope.getProgramParent().path.get("body")[0].node; const alias = path.scope
.getProgramParent()
.path.get("body")[0].node;
if (!babel.types.isTypeAlias(alias)) return; if (!babel.types.isTypeAlias(alias)) return;
// In case of `passPerPreset` being `false`, the // In case of `passPerPreset` being `false`, the
@ -230,11 +267,12 @@ describe("api", function () {
require(__dirname + "/../../babel-preset-es2015"), require(__dirname + "/../../babel-preset-es2015"),
// Third preset for Flow. // Third preset for Flow.
function () { function() {
return { return {
plugins: [ plugins: [
require(__dirname + "/../../babel-plugin-syntax-flow"), require(__dirname + "/../../babel-plugin-syntax-flow"),
require(__dirname + "/../../babel-plugin-transform-flow-strip-types"), require(__dirname +
"/../../babel-plugin-transform-flow-strip-types"),
], ],
}; };
}, },
@ -248,13 +286,16 @@ describe("api", function () {
assert.equal(aliasBaseType, "NumberTypeAnnotation"); assert.equal(aliasBaseType, "NumberTypeAnnotation");
assert.deepEqual([ assert.deepEqual(
"\"use strict\";", [
'"use strict";',
"", "",
"var x = function x(y) {", "var x = function x(y) {",
" return y;", " return y;",
"};", "};",
].join("\n"), result.code); ].join("\n"),
result.code,
);
// 2. passPerPreset: false // 2. passPerPreset: false
@ -264,14 +305,16 @@ describe("api", function () {
assert.equal(aliasBaseType, null); assert.equal(aliasBaseType, null);
assert.deepEqual([ assert.deepEqual(
"\"use strict\";", [
'"use strict";',
"", "",
"var x = function x(y) {", "var x = function x(y) {",
" return y;", " return y;",
"};", "};",
].join("\n"), result.code); ].join("\n"),
result.code,
);
}); });
it("complex plugin and preset ordering", function() { it("complex plugin and preset ordering", function() {
@ -279,7 +322,10 @@ describe("api", function () {
return { return {
visitor: { visitor: {
Program(path) { Program(path) {
path.pushContainer("body", babel.types.expressionStatement(babel.types.identifier(str))); path.pushContainer(
"body",
babel.types.expressionStatement(babel.types.identifier(str)),
);
}, },
}, },
}; };
@ -290,32 +336,31 @@ describe("api", function () {
} }
const result = babel.transform("", { const result = babel.transform("", {
filename: path.join(__dirname, "fixtures", "config", "complex-plugin-config", "file.js"), filename: path.join(
presets: [ __dirname,
pushPreset("argone"), "fixtures",
pushPreset("argtwo"), "config",
], "complex-plugin-config",
"file.js",
),
presets: [pushPreset("argone"), pushPreset("argtwo")],
env: { env: {
development: { development: {
passPerPreset: true, passPerPreset: true,
presets: [ presets: [pushPreset("argthree"), pushPreset("argfour")],
pushPreset("argthree"),
pushPreset("argfour"),
],
env: { env: {
development: { development: {
passPerPreset: true, passPerPreset: true,
presets: [ presets: [pushPreset("argfive"), pushPreset("argsix")],
pushPreset("argfive"),
pushPreset("argsix"),
],
}, },
}, },
}, },
}, },
}); });
assert.equal(result.code, [ assert.equal(
result.code,
[
"argtwo;", "argtwo;",
"argone;", "argone;",
"eleven;", "eleven;",
@ -342,13 +387,15 @@ describe("api", function () {
"eight;", "eight;",
"nine;", "nine;",
"ten;", "ten;",
].join("\n")); ].join("\n"),
);
}); });
it("source map merging", function () { it("source map merging", function() {
const result = babel.transform([ const result = babel.transform(
[
/* eslint-disable max-len */ /* eslint-disable max-len */
"function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }", 'function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }',
"", "",
"let Foo = function Foo() {", "let Foo = function Foo() {",
" _classCallCheck(this, Foo);", " _classCallCheck(this, Foo);",
@ -356,222 +403,278 @@ describe("api", function () {
"", "",
"//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZG91dCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztJQUFNLEdBQUcsWUFBSCxHQUFHO3dCQUFILEdBQUciLCJmaWxlIjoidW5kZWZpbmVkIiwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRm9vIHt9XG4iXX0=", "//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZG91dCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztJQUFNLEdBQUcsWUFBSCxHQUFHO3dCQUFILEdBQUciLCJmaWxlIjoidW5kZWZpbmVkIiwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRm9vIHt9XG4iXX0=",
/* eslint-enable max-len */ /* eslint-enable max-len */
].join("\n"), { ].join("\n"),
{
sourceMap: true, sourceMap: true,
}); },
);
assert.deepEqual([ assert.deepEqual(
[
"function _classCallCheck(instance, Constructor) {", "function _classCallCheck(instance, Constructor) {",
" if (!(instance instanceof Constructor)) {", " if (!(instance instanceof Constructor)) {",
" throw new TypeError(\"Cannot call a class as a function\");", ' throw new TypeError("Cannot call a class as a function");',
" }", " }",
"}", "}",
"", "",
"let Foo = function Foo() {", "let Foo = function Foo() {",
" _classCallCheck(this, Foo);", " _classCallCheck(this, Foo);",
"};", "};",
].join("\n"), result.code); ].join("\n"),
result.code,
);
const consumer = new sourceMap.SourceMapConsumer(result.map); const consumer = new sourceMap.SourceMapConsumer(result.map);
assert.deepEqual(consumer.originalPositionFor({ assert.deepEqual(
consumer.originalPositionFor({
line: 7, line: 7,
column: 4, column: 4,
}), { }),
{
name: null, name: null,
source: "stdout", source: "stdout",
line: 1, line: 1,
column: 6, column: 6,
}); },
);
}); });
it("code option false", function () { it("code option false", function() {
return transformAsync("foo('bar');", { code: false }).then(function (result) { return transformAsync("foo('bar');", { code: false }).then(function(
result,
) {
assert.ok(!result.code); assert.ok(!result.code);
}); });
}); });
it("ast option false", function () { it("ast option false", function() {
return transformAsync("foo('bar');", { ast: false }).then(function (result) { return transformAsync("foo('bar');", { ast: false }).then(function(result) {
assert.ok(!result.ast); assert.ok(!result.ast);
}); });
}); });
it("auxiliaryComment option", function () { it("auxiliaryComment option", function() {
return transformAsync("class Foo {}", { return transformAsync("class Foo {}", {
auxiliaryCommentBefore: "before", auxiliaryCommentBefore: "before",
auxiliaryCommentAfter: "after", auxiliaryCommentAfter: "after",
plugins: [function (babel) { plugins: [
function(babel) {
const t = babel.types; const t = babel.types;
return { return {
visitor: { visitor: {
Program: function (path) { Program: function(path) {
path.unshiftContainer("body", t.expressionStatement(t.identifier("start"))); path.unshiftContainer(
path.pushContainer("body", t.expressionStatement(t.identifier("end"))); "body",
t.expressionStatement(t.identifier("start")),
);
path.pushContainer(
"body",
t.expressionStatement(t.identifier("end")),
);
}, },
}, },
}; };
}], },
}).then(function (result) { ],
assert.equal(result.code, }).then(function(result) {
"/*before*/start;\n/*after*/class Foo {}\n/*before*/end;\n/*after*/"); assert.equal(
result.code,
"/*before*/start;\n/*after*/class Foo {}\n/*before*/end;\n/*after*/",
);
}); });
}); });
it("modules metadata", function () { it("modules metadata", function() {
return Promise.all([ return Promise.all([
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
transformAsync("import { externalName as localName } from \"external\";").then(function (result) { transformAsync(
'import { externalName as localName } from "external";',
).then(function(result) {
assert.deepEqual(result.metadata.modules.imports[0], { assert.deepEqual(result.metadata.modules.imports[0], {
source: "external", source: "external",
imported: ["externalName"], imported: ["externalName"],
specifiers: [{ specifiers: [
{
kind: "named", kind: "named",
imported: "externalName", imported: "externalName",
local: "localName", local: "localName",
}], },
],
}); });
}), }),
transformAsync("import * as localName2 from \"external\";").then(function (result) { transformAsync('import * as localName2 from "external";').then(function(
result,
) {
assert.deepEqual(result.metadata.modules.imports[0], { assert.deepEqual(result.metadata.modules.imports[0], {
source: "external", source: "external",
imported: ["*"], imported: ["*"],
specifiers: [{ specifiers: [
{
kind: "namespace", kind: "namespace",
local: "localName2", local: "localName2",
}], },
],
}); });
}), }),
transformAsync("import localName3 from \"external\";").then(function (result) { transformAsync('import localName3 from "external";').then(function(
result,
) {
assert.deepEqual(result.metadata.modules.imports[0], { assert.deepEqual(result.metadata.modules.imports[0], {
source: "external", source: "external",
imported: ["default"], imported: ["default"],
specifiers: [{ specifiers: [
{
kind: "named", kind: "named",
imported: "default", imported: "default",
local: "localName3", local: "localName3",
}], },
],
}); });
}), }),
transformAsync("import localName from \"./array\";", { transformAsync('import localName from "./array";', {
resolveModuleSource: function() { resolveModuleSource: function() {
return "override-source"; return "override-source";
}, },
}).then(function (result) { }).then(function(result) {
assert.deepEqual(result.metadata.modules.imports, [ assert.deepEqual(result.metadata.modules.imports, [
{ {
source: "override-source", source: "override-source",
imported: ["default"], imported: ["default"],
specifiers: [ specifiers: [
{ {
"kind": "named", kind: "named",
"imported": "default", imported: "default",
"local": "localName", local: "localName",
}, },
], ],
}, },
]); ]);
}), }),
transformAsync("export * as externalName1 from \"external\";", { transformAsync('export * as externalName1 from "external";', {
plugins: [require("../../babel-plugin-syntax-export-extensions")], plugins: [require("../../babel-plugin-syntax-export-extensions")],
}).then(function (result) { }).then(function(result) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: ["externalName1"], exported: ["externalName1"],
specifiers: [{ specifiers: [
{
kind: "external-namespace", kind: "external-namespace",
exported: "externalName1", exported: "externalName1",
source: "external", source: "external",
}], },
],
}); });
}), }),
transformAsync("export externalName2 from \"external\";", { transformAsync('export externalName2 from "external";', {
plugins: [require("../../babel-plugin-syntax-export-extensions")], plugins: [require("../../babel-plugin-syntax-export-extensions")],
}).then(function (result) { }).then(function(result) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: ["externalName2"], exported: ["externalName2"],
specifiers: [{ specifiers: [
{
kind: "external", kind: "external",
local: "externalName2", local: "externalName2",
exported: "externalName2", exported: "externalName2",
source: "external", source: "external",
}], },
],
}); });
}), }),
transformAsync("export function namedFunction() {}").then(function (result) { transformAsync("export function namedFunction() {}").then(function(
result,
) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: ["namedFunction"], exported: ["namedFunction"],
specifiers: [{ specifiers: [
{
kind: "local", kind: "local",
local: "namedFunction", local: "namedFunction",
exported: "namedFunction", exported: "namedFunction",
}], },
],
}); });
}), }),
transformAsync("export var foo = \"bar\";").then(function (result) { transformAsync('export var foo = "bar";').then(function(result) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
"exported": ["foo"], exported: ["foo"],
specifiers: [{ specifiers: [
{
kind: "local", kind: "local",
local: "foo", local: "foo",
exported: "foo", exported: "foo",
}], },
],
}); });
}), }),
transformAsync("export { localName as externalName3 };").then(function (result) { transformAsync("export { localName as externalName3 };").then(function(
result,
) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: ["externalName3"], exported: ["externalName3"],
specifiers: [{ specifiers: [
{
kind: "local", kind: "local",
local: "localName", local: "localName",
exported: "externalName3", exported: "externalName3",
}], },
],
}); });
}), }),
transformAsync("export { externalName4 } from \"external\";").then(function (result) { transformAsync('export { externalName4 } from "external";').then(function(
result,
) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: ["externalName4"], exported: ["externalName4"],
specifiers: [{ specifiers: [
{
kind: "external", kind: "external",
local: "externalName4", local: "externalName4",
exported: "externalName4", exported: "externalName4",
source: "external", source: "external",
}], },
],
}); });
}), }),
transformAsync("export * from \"external\";").then(function (result) { transformAsync('export * from "external";').then(function(result) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: [], exported: [],
specifiers: [{ specifiers: [
{
kind: "external-all", kind: "external-all",
source: "external", source: "external",
}], },
],
}); });
}), }),
transformAsync("export default function defaultFunction() {}").then(function (result) { transformAsync(
"export default function defaultFunction() {}",
).then(function(result) {
assert.deepEqual(result.metadata.modules.exports, { assert.deepEqual(result.metadata.modules.exports, {
exported: ["defaultFunction"], exported: ["defaultFunction"],
specifiers: [{ specifiers: [
{
kind: "local", kind: "local",
local: "defaultFunction", local: "defaultFunction",
exported: "default", exported: "default",
}], },
],
}); });
}), }),
]); ]);
}); });
it("ignore option", function () { it("ignore option", function() {
return Promise.all([ return Promise.all([
transformAsync("", { transformAsync("", {
ignore: ["/foo"], ignore: ["/foo"],
@ -610,7 +713,7 @@ describe("api", function () {
]); ]);
}); });
it("only option", function () { it("only option", function() {
return Promise.all([ return Promise.all([
transformAsync("", { transformAsync("", {
only: ["/foo"], only: ["/foo"],
@ -649,23 +752,23 @@ describe("api", function () {
]); ]);
}); });
describe("env option", function () { describe("env option", function() {
const oldBabelEnv = process.env.BABEL_ENV; const oldBabelEnv = process.env.BABEL_ENV;
const oldNodeEnv = process.env.NODE_ENV; const oldNodeEnv = process.env.NODE_ENV;
setup(function () { setup(function() {
// Tests need to run with the default and specific values for these. They // Tests need to run with the default and specific values for these. They
// need to be cleared for each test. // need to be cleared for each test.
delete process.env.BABEL_ENV; delete process.env.BABEL_ENV;
delete process.env.NODE_ENV; delete process.env.NODE_ENV;
}); });
suiteTeardown(function () { suiteTeardown(function() {
process.env.BABEL_ENV = oldBabelEnv; process.env.BABEL_ENV = oldBabelEnv;
process.env.NODE_ENV = oldNodeEnv; process.env.NODE_ENV = oldNodeEnv;
}); });
it("default", function () { it("default", function() {
const result = babel.transform("foo;", { const result = babel.transform("foo;", {
env: { env: {
development: { code: false }, development: { code: false },
@ -675,7 +778,7 @@ describe("api", function () {
assert.equal(result.code, undefined); assert.equal(result.code, undefined);
}); });
it("BABEL_ENV", function () { it("BABEL_ENV", function() {
process.env.BABEL_ENV = "foo"; process.env.BABEL_ENV = "foo";
const result = babel.transform("foo;", { const result = babel.transform("foo;", {
env: { env: {
@ -685,7 +788,7 @@ describe("api", function () {
assert.equal(result.code, undefined); assert.equal(result.code, undefined);
}); });
it("NODE_ENV", function () { it("NODE_ENV", function() {
process.env.NODE_ENV = "foo"; process.env.NODE_ENV = "foo";
const result = babel.transform("foo;", { const result = babel.transform("foo;", {
env: { env: {
@ -696,41 +799,43 @@ describe("api", function () {
}); });
}); });
it("resolveModuleSource option", function () { it("resolveModuleSource option", function() {
/* eslint-disable max-len */ /* eslint-disable max-len */
const actual = "import foo from \"foo-import-default\";\nimport \"foo-import-bare\";\nexport { foo } from \"foo-export-named\";"; const actual =
const expected = "import foo from \"resolved/foo-import-default\";\nimport \"resolved/foo-import-bare\";\nexport { foo } from \"resolved/foo-export-named\";"; 'import foo from "foo-import-default";\nimport "foo-import-bare";\nexport { foo } from "foo-export-named";';
const expected =
'import foo from "resolved/foo-import-default";\nimport "resolved/foo-import-bare";\nexport { foo } from "resolved/foo-export-named";';
/* eslint-enable max-len */ /* eslint-enable max-len */
return transformAsync(actual, { return transformAsync(actual, {
resolveModuleSource: function (originalSource) { resolveModuleSource: function(originalSource) {
return "resolved/" + originalSource; return "resolved/" + originalSource;
}, },
}).then(function (result) { }).then(function(result) {
assert.equal(result.code.trim(), expected); assert.equal(result.code.trim(), expected);
}); });
}); });
describe("buildExternalHelpers", function () { describe("buildExternalHelpers", function() {
it("all", function () { it("all", function() {
const script = buildExternalHelpers(); const script = buildExternalHelpers();
assert.ok(script.indexOf("classCallCheck") >= -1); assert.ok(script.indexOf("classCallCheck") >= -1);
assert.ok(script.indexOf("inherits") >= 0); assert.ok(script.indexOf("inherits") >= 0);
}); });
it("whitelist", function () { it("whitelist", function() {
const script = buildExternalHelpers(["inherits"]); const script = buildExternalHelpers(["inherits"]);
assert.ok(script.indexOf("classCallCheck") === -1); assert.ok(script.indexOf("classCallCheck") === -1);
assert.ok(script.indexOf("inherits") >= 0); assert.ok(script.indexOf("inherits") >= 0);
}); });
it("empty whitelist", function () { it("empty whitelist", function() {
const script = buildExternalHelpers([]); const script = buildExternalHelpers([]);
assert.ok(script.indexOf("classCallCheck") === -1); assert.ok(script.indexOf("classCallCheck") === -1);
assert.ok(script.indexOf("inherits") === -1); assert.ok(script.indexOf("inherits") === -1);
}); });
it("underscored", function () { it("underscored", function() {
const script = buildExternalHelpers(["typeof"]); const script = buildExternalHelpers(["typeof"]);
assert.ok(script.indexOf("typeof") >= 0); assert.ok(script.indexOf("typeof") >= 0);
}); });

View File

@ -5,7 +5,9 @@ import vm from "vm";
describe("browserify", function() { describe("browserify", function() {
it("babel/register may be used without breaking browserify", function(done) { it("babel/register may be used without breaking browserify", function(done) {
const bundler = browserify(path.join(__dirname, "fixtures/browserify/register.js")); const bundler = browserify(
path.join(__dirname, "fixtures/browserify/register.js"),
);
bundler.bundle(function(err, bundle) { bundler.bundle(function(err, bundle) {
if (err) return done(err); if (err) return done(err);

View File

@ -27,7 +27,6 @@ describe("caching API", () => {
return { arg, count: count++ }; return { arg, count: count++ };
}); });
assert.deepEqual(fn("one"), { arg: "one", count: 0 }); assert.deepEqual(fn("one"), { arg: "one", count: 0 });
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
@ -210,48 +209,97 @@ describe("caching API", () => {
return { arg, val, val2, count: count++ }; return { arg, val, val2, count: count++ };
}); });
assert.deepEqual(fn("one"), { arg: "one", val: "default", val2: "another", count: 0 }); assert.deepEqual(fn("one"), {
arg: "one",
val: "default",
val2: "another",
count: 0,
});
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
assert.deepEqual(fn("two"), { arg: "two", val: "default", val2: "another", count: 1 }); assert.deepEqual(fn("two"), {
arg: "two",
val: "default",
val2: "another",
count: 1,
});
assert.equal(fn("two"), fn("two")); assert.equal(fn("two"), fn("two"));
other = "new"; other = "new";
assert.deepEqual(fn("one"), { arg: "one", val: "new", val2: "another", count: 2 }); assert.deepEqual(fn("one"), {
arg: "one",
val: "new",
val2: "another",
count: 2,
});
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
assert.deepEqual(fn("two"), { arg: "two", val: "new", val2: "another", count: 3 }); assert.deepEqual(fn("two"), {
arg: "two",
val: "new",
val2: "another",
count: 3,
});
assert.equal(fn("two"), fn("two")); assert.equal(fn("two"), fn("two"));
other = "default"; other = "default";
assert.deepEqual(fn("one"), { arg: "one", val: "default", val2: "another", count: 4 }); assert.deepEqual(fn("one"), {
arg: "one",
val: "default",
val2: "another",
count: 4,
});
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
assert.deepEqual(fn("two"), { arg: "two", val: "default", val2: "another", count: 5 }); assert.deepEqual(fn("two"), {
arg: "two",
val: "default",
val2: "another",
count: 5,
});
assert.equal(fn("two"), fn("two")); assert.equal(fn("two"), fn("two"));
other = "new"; other = "new";
assert.deepEqual(fn("one"), { arg: "one", val: "new", val2: "another", count: 6 }); assert.deepEqual(fn("one"), {
arg: "one",
val: "new",
val2: "another",
count: 6,
});
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
assert.deepEqual(fn("two"), { arg: "two", val: "new", val2: "another", count: 7 }); assert.deepEqual(fn("two"), {
arg: "two",
val: "new",
val2: "another",
count: 7,
});
assert.equal(fn("two"), fn("two")); assert.equal(fn("two"), fn("two"));
another = "second"; another = "second";
assert.deepEqual(fn("one"), { arg: "one", val: "new", val2: "second", count: 8 }); assert.deepEqual(fn("one"), {
arg: "one",
val: "new",
val2: "second",
count: 8,
});
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
assert.deepEqual(fn("two"), { arg: "two", val: "new", val2: "second", count: 9 }); assert.deepEqual(fn("two"), {
arg: "two",
val: "new",
val2: "second",
count: 9,
});
assert.equal(fn("two"), fn("two")); assert.equal(fn("two"), fn("two"));
}); });
it("should throw if caching is never configured and not defaulting", () => { it("should throw if caching is never configured and not defaulting", () => {
const fn = makeStrongCache(() => { }, false /* autoPermacache */); const fn = makeStrongCache(() => {}, false /* autoPermacache */);
assert.throws(() => fn(), /Error: Caching was left unconfigured./); assert.throws(() => fn(), /Error: Caching was left unconfigured./);
}); });
@ -259,7 +307,7 @@ describe("caching API", () => {
it("should auto-permacache by default", () => { it("should auto-permacache by default", () => {
let count = 0; let count = 0;
const fn = makeStrongCache((arg) => ({ arg, count: count++ })); const fn = makeStrongCache(arg => ({ arg, count: count++ }));
assert.deepEqual(fn("one"), { arg: "one", count: 0 }); assert.deepEqual(fn("one"), { arg: "one", count: 0 });
assert.equal(fn("one"), fn("one")); assert.equal(fn("one"), fn("one"));
@ -333,7 +381,10 @@ describe("caching API", () => {
it("should throw if you configure .forever after exiting", () => { it("should throw if you configure .forever after exiting", () => {
const fn = makeStrongCache((arg, cache) => cache); const fn = makeStrongCache((arg, cache) => cache);
assert.throws(() => fn().forever(), /Cannot change caching after evaluation/); assert.throws(
() => fn().forever(),
/Cannot change caching after evaluation/,
);
}); });
it("should throw if you configure .never after exiting", () => { it("should throw if you configure .never after exiting", () => {
@ -345,12 +396,18 @@ describe("caching API", () => {
it("should throw if you configure .using after exiting", () => { it("should throw if you configure .using after exiting", () => {
const fn = makeStrongCache((arg, cache) => cache); const fn = makeStrongCache((arg, cache) => cache);
assert.throws(() => fn().using(() => null), /Cannot change caching after evaluation/); assert.throws(
() => fn().using(() => null),
/Cannot change caching after evaluation/,
);
}); });
it("should throw if you configure .invalidate after exiting", () => { it("should throw if you configure .invalidate after exiting", () => {
const fn = makeStrongCache((arg, cache) => cache); const fn = makeStrongCache((arg, cache) => cache);
assert.throws(() => fn().invalidate(() => null), /Cannot change caching after evaluation/); assert.throws(
() => fn().invalidate(() => null),
/Cannot change caching after evaluation/,
);
}); });
}); });

View File

@ -4,7 +4,7 @@ import buildConfigChain from "../lib/config/build-config-chain";
function fixture() { function fixture() {
const args = [__dirname, "fixtures", "config"]; const args = [__dirname, "fixtures", "config"];
for (let i = 0; i < arguments.length; i ++) { for (let i = 0; i < arguments.length; i++) {
args.push(arguments[i]); args.push(arguments[i]);
} }
return path.join.apply(path, args); return path.join.apply(path, args);
@ -14,11 +14,11 @@ function base() {
return process.cwd(); return process.cwd();
} }
describe("buildConfigChain", function () { describe("buildConfigChain", function() {
let oldBabelEnv; let oldBabelEnv;
let oldNodeEnv; let oldNodeEnv;
beforeEach(function () { beforeEach(function() {
oldBabelEnv = process.env.BABEL_ENV; oldBabelEnv = process.env.BABEL_ENV;
oldNodeEnv = process.env.NODE_ENV; oldNodeEnv = process.env.NODE_ENV;
@ -26,7 +26,7 @@ describe("buildConfigChain", function () {
delete process.env.NODE_ENV; delete process.env.NODE_ENV;
}); });
afterEach(function () { afterEach(function() {
process.env.BABEL_ENV = oldBabelEnv; process.env.BABEL_ENV = oldBabelEnv;
process.env.NODE_ENV = oldNodeEnv; process.env.NODE_ENV = oldNodeEnv;
}); });
@ -52,7 +52,7 @@ describe("buildConfigChain", function () {
}); });
}); });
it("dir1", function () { it("dir1", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("dir1", "src.js"), filename: fixture("dir1", "src.js"),
}); });
@ -61,9 +61,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["extended"],
"extended",
],
}, },
alias: fixture("extended.babelrc.json"), alias: fixture("extended.babelrc.json"),
loc: fixture("extended.babelrc.json"), loc: fixture("extended.babelrc.json"),
@ -72,9 +70,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["root"],
"root",
],
}, },
alias: fixture(".babelrc"), alias: fixture(".babelrc"),
loc: fixture(".babelrc"), loc: fixture(".babelrc"),
@ -83,9 +79,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -105,7 +99,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("dir2", function () { it("dir2", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("dir2", "src.js"), filename: fixture("dir2", "src.js"),
}); });
@ -114,9 +108,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -125,9 +117,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["dir2"],
"dir2",
],
}, },
alias: fixture("dir2", ".babelrc"), alias: fixture("dir2", ".babelrc"),
loc: fixture("dir2", ".babelrc"), loc: fixture("dir2", ".babelrc"),
@ -147,7 +137,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("dir3", function () { it("dir3", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("dir3", "src.js"), filename: fixture("dir3", "src.js"),
}); });
@ -156,9 +146,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["extended"],
"extended",
],
}, },
alias: fixture("extended.babelrc.json"), alias: fixture("extended.babelrc.json"),
loc: fixture("extended.babelrc.json"), loc: fixture("extended.babelrc.json"),
@ -167,9 +155,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["root"],
"root",
],
}, },
alias: fixture(".babelrc"), alias: fixture(".babelrc"),
loc: fixture(".babelrc"), loc: fixture(".babelrc"),
@ -178,9 +164,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -200,7 +184,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("env - base", function () { it("env - base", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("env", "src.js"), filename: fixture("env", "src.js"),
}); });
@ -209,9 +193,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -220,9 +202,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["env-base"],
"env-base",
],
}, },
alias: fixture("env", ".babelrc"), alias: fixture("env", ".babelrc"),
loc: fixture("env", ".babelrc"), loc: fixture("env", ".babelrc"),
@ -242,7 +222,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("env - foo", function () { it("env - foo", function() {
process.env.NODE_ENV = "foo"; process.env.NODE_ENV = "foo";
const chain = buildConfigChain({ const chain = buildConfigChain({
@ -253,9 +233,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -264,9 +242,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["env-base"],
"env-base",
],
}, },
alias: fixture("env", ".babelrc"), alias: fixture("env", ".babelrc"),
loc: fixture("env", ".babelrc"), loc: fixture("env", ".babelrc"),
@ -275,9 +251,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["env-foo"],
"env-foo",
],
}, },
alias: fixture("env", ".babelrc.env.foo"), alias: fixture("env", ".babelrc.env.foo"),
loc: fixture("env", ".babelrc.env.foo"), loc: fixture("env", ".babelrc.env.foo"),
@ -297,7 +271,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("env - bar", function () { it("env - bar", function() {
process.env.NODE_ENV = "foo"; // overridden process.env.NODE_ENV = "foo"; // overridden
process.env.NODE_ENV = "bar"; process.env.NODE_ENV = "bar";
@ -309,9 +283,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -320,9 +292,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["env-base"],
"env-base",
],
}, },
alias: fixture("env", ".babelrc"), alias: fixture("env", ".babelrc"),
loc: fixture("env", ".babelrc"), loc: fixture("env", ".babelrc"),
@ -331,9 +301,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["env-bar"],
"env-bar",
],
}, },
alias: fixture("env", ".babelrc.env.bar"), alias: fixture("env", ".babelrc.env.bar"),
loc: fixture("env", ".babelrc.env.bar"), loc: fixture("env", ".babelrc.env.bar"),
@ -353,8 +321,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("env - foo", function() {
it("env - foo", function () {
process.env.NODE_ENV = "foo"; process.env.NODE_ENV = "foo";
const chain = buildConfigChain({ const chain = buildConfigChain({
@ -394,7 +361,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("js-config", function () { it("js-config", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("js-config", "src.js"), filename: fixture("js-config", "src.js"),
}); });
@ -403,9 +370,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -414,10 +379,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["foo", "bar"],
"foo",
"bar",
],
}, },
alias: fixture("js-config", ".babelrc.js"), alias: fixture("js-config", ".babelrc.js"),
loc: fixture("js-config", ".babelrc.js"), loc: fixture("js-config", ".babelrc.js"),
@ -437,7 +399,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("js-config-function", function () { it("js-config-function", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("js-config-function", "src.js"), filename: fixture("js-config-function", "src.js"),
}); });
@ -446,9 +408,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -477,7 +437,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("js-config-default - should read transpiled export default", function () { it("js-config-default - should read transpiled export default", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("js-config-default", "src.js"), filename: fixture("js-config-default", "src.js"),
}); });
@ -486,9 +446,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -497,10 +455,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["foo", "bar"],
"foo",
"bar",
],
}, },
alias: fixture("js-config-default", ".babelrc.js"), alias: fixture("js-config-default", ".babelrc.js"),
loc: fixture("js-config-default", ".babelrc.js"), loc: fixture("js-config-default", ".babelrc.js"),
@ -519,7 +474,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("js-config-extended", function () { it("js-config-extended", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("js-config-extended", "src.js"), filename: fixture("js-config-extended", "src.js"),
}); });
@ -528,9 +483,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -539,9 +492,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["extended"],
"extended",
],
}, },
alias: fixture("extended.babelrc.json"), alias: fixture("extended.babelrc.json"),
loc: fixture("extended.babelrc.json"), loc: fixture("extended.babelrc.json"),
@ -550,10 +501,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["foo", "bar"],
"foo",
"bar",
],
}, },
alias: fixture("js-config-extended", ".babelrc.js"), alias: fixture("js-config-extended", ".babelrc.js"),
loc: fixture("js-config-extended", ".babelrc.js"), loc: fixture("js-config-extended", ".babelrc.js"),
@ -573,8 +521,10 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); });
it("json-pkg-config-no-babel - should not throw if" + it(
" package.json doesn't contain a `babel` field", function () { "json-pkg-config-no-babel - should not throw if" +
" package.json doesn't contain a `babel` field",
function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("json-pkg-config-no-babel", "src.js"), filename: fixture("json-pkg-config-no-babel", "src.js"),
}); });
@ -583,9 +533,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -594,9 +542,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
plugins: [ plugins: ["json"],
"json",
],
}, },
alias: fixture("json-pkg-config-no-babel", ".babelrc"), alias: fixture("json-pkg-config-no-babel", ".babelrc"),
loc: fixture("json-pkg-config-no-babel", ".babelrc"), loc: fixture("json-pkg-config-no-babel", ".babelrc"),
@ -614,9 +560,10 @@ describe("buildConfigChain", function () {
]; ];
assert.deepEqual(chain, expected); assert.deepEqual(chain, expected);
}); },
);
it("should not ignore file matching negated file pattern", function () { it("should not ignore file matching negated file pattern", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("ignore-negate", "src.js"), filename: fixture("ignore-negate", "src.js"),
}); });
@ -625,9 +572,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -636,10 +581,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["*", "!src.js"],
"*",
"!src.js",
],
}, },
alias: fixture("ignore-negate", ".babelrc"), alias: fixture("ignore-negate", ".babelrc"),
loc: fixture("ignore-negate", ".babelrc"), loc: fixture("ignore-negate", ".babelrc"),
@ -665,7 +607,7 @@ describe("buildConfigChain", function () {
assert.equal(chain2, null); assert.equal(chain2, null);
}); });
it("should not ignore file matching negated folder pattern", function () { it("should not ignore file matching negated folder pattern", function() {
const chain = buildConfigChain({ const chain = buildConfigChain({
filename: fixture("ignore-negate-folder", "folder", "src.js"), filename: fixture("ignore-negate-folder", "folder", "src.js"),
}); });
@ -674,9 +616,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore",
],
}, },
alias: fixture(".babelignore"), alias: fixture(".babelignore"),
loc: fixture(".babelignore"), loc: fixture(".babelignore"),
@ -685,10 +625,7 @@ describe("buildConfigChain", function () {
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["*", "!folder"],
"*",
"!folder",
],
}, },
alias: fixture("ignore-negate-folder", ".babelrc"), alias: fixture("ignore-negate-folder", ".babelrc"),
loc: fixture("ignore-negate-folder", ".babelrc"), loc: fixture("ignore-negate-folder", ".babelrc"),
@ -714,83 +651,71 @@ describe("buildConfigChain", function () {
assert.equal(chain2, null); assert.equal(chain2, null);
}); });
it("js-json-config - should throw an error if both a .babelrc" + it(
" and a .babelrc.js are present", function () { "js-json-config - should throw an error if both a .babelrc" +
assert.throws( " and a .babelrc.js are present",
function () { function() {
assert.throws(function() {
buildConfigChain({ buildConfigChain({
filename: fixture("js-json-config", "src.js"), filename: fixture("js-json-config", "src.js"),
}); });
}, /Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*\.babelrc\.js/);
}, },
/Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*\.babelrc\.js/
); );
});
it("js-pkg-config - should throw an error if both a .babelrc.js" + it(
" and a package.json with a babel field are present", function () { "js-pkg-config - should throw an error if both a .babelrc.js" +
assert.throws( " and a package.json with a babel field are present",
function () { function() {
assert.throws(function() {
buildConfigChain({ buildConfigChain({
filename: fixture("js-pkg-config", "src.js"), filename: fixture("js-pkg-config", "src.js"),
}); });
}, /Multiple configuration files found\.(.|\n)*\.babelrc\.js(.|\n)*package\.json/);
}, },
/Multiple configuration files found\.(.|\n)*\.babelrc\.js(.|\n)*package\.json/
); );
});
it("json-pkg-config - should throw an error if both a .babelrc" + it(
" and a package.json with a babel field are present", function () { "json-pkg-config - should throw an error if both a .babelrc" +
assert.throws( " and a package.json with a babel field are present",
function () { function() {
assert.throws(function() {
buildConfigChain({ buildConfigChain({
filename: fixture("json-pkg-config", "src.js"), filename: fixture("json-pkg-config", "src.js"),
}); });
}, /Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*package\.json/);
}, },
/Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*package\.json/
); );
});
it("js-config-error", function () { it("js-config-error", function() {
assert.throws( assert.throws(function() {
function () {
buildConfigChain({ buildConfigChain({
filename: fixture("js-config-error", "src.js"), filename: fixture("js-config-error", "src.js"),
}); });
}, }, /Error while loading config/);
/Error while loading config/
);
}); });
it("js-config-error2", function () { it("js-config-error2", function() {
assert.throws( assert.throws(function() {
function () {
buildConfigChain({ buildConfigChain({
filename: fixture("js-config-error2", "src.js"), filename: fixture("js-config-error2", "src.js"),
}); });
}, }, /Configuration should be an exported JavaScript object/);
/Configuration should be an exported JavaScript object/
);
}); });
it("js-config-error3", function () { it("js-config-error3", function() {
assert.throws( assert.throws(function() {
function () {
buildConfigChain({ buildConfigChain({
filename: fixture("js-config-error3", "src.js"), filename: fixture("js-config-error3", "src.js"),
}); });
}, }, /Configuration should be an exported JavaScript object/);
/Configuration should be an exported JavaScript object/
);
}); });
it("json-config-error", function () { it("json-config-error", function() {
assert.throws( assert.throws(function() {
function () {
buildConfigChain({ buildConfigChain({
filename: fixture("json-config-error", "src.js"), filename: fixture("json-config-error", "src.js"),
}); });
}, }, /Error while parsing config/);
/Error while parsing config/
);
}); });
}); });

View File

@ -2,20 +2,23 @@ import traverse from "babel-traverse";
import assert from "assert"; import assert from "assert";
import { parse } from "babylon"; import { parse } from "babylon";
describe("evaluation", function () { describe("evaluation", function() {
function addTest(code, type, value, notConfident) { function addTest(code, type, value, notConfident) {
it(type + ": " + code, function () { it(type + ": " + code, function() {
const visitor = {}; const visitor = {};
visitor[type] = function (path) { visitor[type] = function(path) {
const evaluate = path.evaluate(); const evaluate = path.evaluate();
assert.equal(evaluate.confident, !notConfident); assert.equal(evaluate.confident, !notConfident);
assert.deepEqual(evaluate.value, value); assert.deepEqual(evaluate.value, value);
}; };
traverse(parse(code, { traverse(
parse(code, {
plugins: ["*"], plugins: ["*"],
}), visitor); }),
visitor,
);
}); });
} }
@ -56,14 +59,39 @@ describe("evaluation", function () {
addTest("'abc' === 'xyz' || 1 === 1", "LogicalExpression", true); addTest("'abc' === 'xyz' || 1 === 1", "LogicalExpression", true);
addTest("'abc' === 'xyz' || 1 === 10", "LogicalExpression", false); addTest("'abc' === 'xyz' || 1 === 10", "LogicalExpression", false);
addTest("'abc' === 'abc' || config.flag === 1", "LogicalExpression", true); addTest("'abc' === 'abc' || config.flag === 1", "LogicalExpression", true);
addTest("obj.a === 'abc' || config.flag === 1", "LogicalExpression", undefined, true); addTest(
"obj.a === 'abc' || config.flag === 1",
"LogicalExpression",
undefined,
true,
);
addTest("'abc' !== 'abc' && config.flag === 1", "LogicalExpression", false); addTest("'abc' !== 'abc' && config.flag === 1", "LogicalExpression", false);
addTest("obj.a === 'abc' && 1 === 1", "LogicalExpression", undefined, true); addTest("obj.a === 'abc' && 1 === 1", "LogicalExpression", undefined, true);
addTest("'abc' === 'abc' && (1 === 1 || config.flag)", "LogicalExpression", true); addTest(
addTest("'abc' === 'xyz' || (1 === 1 && config.flag)", "LogicalExpression", undefined, true); "'abc' === 'abc' && (1 === 1 || config.flag)",
addTest("'abc' === 'xyz' || (1 === 1 && 'four' === 'four')", "LogicalExpression", true); "LogicalExpression",
addTest("'abc' === 'abc' && (1 === 1 && 'four' === 'four')", "LogicalExpression", true); true,
);
addTest(
"'abc' === 'xyz' || (1 === 1 && config.flag)",
"LogicalExpression",
undefined,
true,
);
addTest(
"'abc' === 'xyz' || (1 === 1 && 'four' === 'four')",
"LogicalExpression",
true,
);
addTest(
"'abc' === 'abc' && (1 === 1 && 'four' === 'four')",
"LogicalExpression",
true,
);
addTest("({})", "ObjectExpression", {}); addTest("({})", "ObjectExpression", {});
addTest("({a: '1'})", "ObjectExpression", { a: "1" }); addTest("({a: '1'})", "ObjectExpression", { a: "1" });
addTest("({['a' + 'b']: 10 * 20, 'z': [1, 2, 3]})", "ObjectExpression", { ab: 200, z: [1, 2, 3] }); addTest("({['a' + 'b']: 10 * 20, 'z': [1, 2, 3]})", "ObjectExpression", {
ab: 200,
z: [1, 2, 3],
});
}); });

View File

@ -6,55 +6,51 @@ describe("option-manager", () => {
it("throws for babel 5 plugin", () => { it("throws for babel 5 plugin", () => {
return assert.throws(() => { return assert.throws(() => {
manageOptions({ manageOptions({
plugins: [ plugins: [({ Plugin }) => new Plugin("object-assign", {})],
({ Plugin }) => new Plugin("object-assign", {}),
],
}); });
}, /Babel 5 plugin is being run with Babel 6/); }, /Babel 5 plugin is being run with Babel 6/);
}); });
describe("mergeOptions", () => { describe("mergeOptions", () => {
it("throws for removed babel 5 options", () => { it("throws for removed babel 5 options", () => {
return assert.throws( return assert.throws(() => {
() => {
manageOptions({ manageOptions({
"randomOption": true, randomOption: true,
}); });
}, }, /Unknown option: base.randomOption/);
/Unknown option: base.randomOption/
);
}); });
it("throws for removed babel 5 options", () => { it("throws for removed babel 5 options", () => {
return assert.throws( return assert.throws(
() => { () => {
manageOptions({ manageOptions({
"auxiliaryComment": true, auxiliaryComment: true,
"blacklist": true, blacklist: true,
}); });
}, },
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
/Using removed Babel 5 option: base.auxiliaryComment - Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`/ /Using removed Babel 5 option: base.auxiliaryComment - Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`/,
); );
}); });
it("throws for resolved but erroring preset", () => { it("throws for resolved but erroring preset", () => {
return assert.throws( return assert.throws(() => {
() => {
manageOptions({ manageOptions({
"presets": [path.join(__dirname, "fixtures/option-manager/not-a-preset")], presets: [
path.join(__dirname, "fixtures/option-manager/not-a-preset"),
],
}); });
}, }, /While processing: .*option-manager(?:\/|\\\\)not-a-preset\.js/);
/While processing: .*option-manager(?:\/|\\\\)not-a-preset\.js/
);
}); });
}); });
describe("presets", function () { describe("presets", function() {
function presetTest(name) { function presetTest(name) {
it(name, function () { it(name, function() {
const { options, passes } = manageOptions({ const { options, passes } = manageOptions({
"presets": [path.join(__dirname, "fixtures/option-manager/presets", name)], presets: [
path.join(__dirname, "fixtures/option-manager/presets", name),
],
}); });
assert.equal(true, Array.isArray(options.plugins)); assert.equal(true, Array.isArray(options.plugins));
@ -65,10 +61,16 @@ describe("option-manager", () => {
} }
function presetThrowsTest(name, msg) { function presetThrowsTest(name, msg) {
it(name, function () { it(name, function() {
assert.throws(() => manageOptions({ assert.throws(
"presets": [path.join(__dirname, "fixtures/option-manager/presets", name)], () =>
}), msg); manageOptions({
presets: [
path.join(__dirname, "fixtures/option-manager/presets", name),
],
}),
msg,
);
}); });
} }
@ -77,7 +79,10 @@ describe("option-manager", () => {
presetTest("es2015_default_function"); presetTest("es2015_default_function");
presetTest("es2015_default_object"); presetTest("es2015_default_object");
presetThrowsTest("es2015_named", /Must export a default export when using ES6 modules/); presetThrowsTest(
"es2015_named",
/Must export a default export when using ES6 modules/,
);
presetThrowsTest("es2015_invalid", /Unsupported format: string/); presetThrowsTest("es2015_invalid", /Unsupported format: string/);
presetThrowsTest("es5_invalid", /Unsupported format: string/); presetThrowsTest("es5_invalid", /Unsupported format: string/);
}); });

View File

@ -2,152 +2,172 @@ import { transform } from "../lib/index";
import Plugin from "../lib/config/plugin"; import Plugin from "../lib/config/plugin";
import chai from "chai"; import chai from "chai";
describe("traversal path", function () { describe("traversal path", function() {
it("replaceWithSourceString", function () { it("replaceWithSourceString", function() {
const expectCode = "function foo() {}"; const expectCode = "function foo() {}";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
FunctionDeclaration: function (path) { FunctionDeclaration: function(path) {
path.replaceWithSourceString("console.whatever()"); path.replaceWithSourceString("console.whatever()");
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("console.whatever();"); chai.expect(actualCode).to.be.equal("console.whatever();");
}); });
it("replaceWith (arrow expression body to block statement body)", function () { it("replaceWith (arrow expression body to block statement body)", function() {
const expectCode = "var fn = () => true;"; const expectCode = "var fn = () => true;";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
ArrowFunctionExpression: function (path) { ArrowFunctionExpression: function(path) {
path.get("body").replaceWith({ path.get("body").replaceWith({
type: "BlockStatement", type: "BlockStatement",
body: [{ body: [
{
type: "ReturnStatement", type: "ReturnStatement",
argument: { argument: {
type: "BooleanLiteral", type: "BooleanLiteral",
value: true, value: true,
}, },
}], },
],
}); });
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("var fn = () => {\n return true;\n};"); chai.expect(actualCode).to.be.equal("var fn = () => {\n return true;\n};");
}); });
it("replaceWith (arrow block statement body to expression body)", function () { it("replaceWith (arrow block statement body to expression body)", function() {
const expectCode = "var fn = () => { return true; }"; const expectCode = "var fn = () => { return true; }";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
ArrowFunctionExpression: function (path) { ArrowFunctionExpression: function(path) {
path.get("body").replaceWith({ path.get("body").replaceWith({
type: "BooleanLiteral", type: "BooleanLiteral",
value: true, value: true,
}); });
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("var fn = () => true;"); chai.expect(actualCode).to.be.equal("var fn = () => true;");
}); });
it("replaceWith (for-in left expression to variable declaration)", function () { it("replaceWith (for-in left expression to variable declaration)", function() {
const expectCode = "for (KEY in right);"; const expectCode = "for (KEY in right);";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
ForInStatement: function (path) { ForInStatement: function(path) {
path.get("left").replaceWith({ path.get("left").replaceWith({
type: "VariableDeclaration", type: "VariableDeclaration",
kind: "var", kind: "var",
declarations: [{ declarations: [
{
type: "VariableDeclarator", type: "VariableDeclarator",
id: { id: {
type: "Identifier", type: "Identifier",
name: "KEY", name: "KEY",
}, },
}], },
],
}); });
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("for (var KEY in right);"); chai.expect(actualCode).to.be.equal("for (var KEY in right);");
}); });
it("replaceWith (for-in left variable declaration to expression)", function () { it("replaceWith (for-in left variable declaration to expression)", function() {
const expectCode = "for (var KEY in right);"; const expectCode = "for (var KEY in right);";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
ForInStatement: function (path) { ForInStatement: function(path) {
path.get("left").replaceWith({ path.get("left").replaceWith({
type: "Identifier", type: "Identifier",
name: "KEY", name: "KEY",
}); });
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("for (KEY in right);"); chai.expect(actualCode).to.be.equal("for (KEY in right);");
}); });
it("replaceWith (for-loop left expression to variable declaration)", function () { it("replaceWith (for-loop left expression to variable declaration)", function() {
const expectCode = "for (KEY;;);"; const expectCode = "for (KEY;;);";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
ForStatement: function (path) { ForStatement: function(path) {
path.get("init").replaceWith({ path.get("init").replaceWith({
type: "VariableDeclaration", type: "VariableDeclaration",
kind: "var", kind: "var",
declarations: [{ declarations: [
{
type: "VariableDeclarator", type: "VariableDeclarator",
id: { id: {
type: "Identifier", type: "Identifier",
name: "KEY", name: "KEY",
}, },
}], },
],
}); });
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("for (var KEY;;);"); chai.expect(actualCode).to.be.equal("for (var KEY;;);");
}); });
it("replaceWith (for-loop left variable declaration to expression)", function () { it("replaceWith (for-loop left variable declaration to expression)", function() {
const expectCode = "for (var KEY;;);"; const expectCode = "for (var KEY;;);";
const actualCode = transform(expectCode, { const actualCode = transform(expectCode, {
plugins: [new Plugin({ plugins: [
new Plugin({
visitor: { visitor: {
ForStatement: function (path) { ForStatement: function(path) {
path.get("init").replaceWith({ path.get("init").replaceWith({
type: "Identifier", type: "Identifier",
name: "KEY", name: "KEY",
}); });
}, },
}, },
})], }),
],
}).code; }).code;
chai.expect(actualCode).to.be.equal("for (KEY;;);"); chai.expect(actualCode).to.be.equal("for (KEY;;);");

View File

@ -2,7 +2,7 @@ import assert from "assert";
import * as babel from "../lib/index"; import * as babel from "../lib/index";
import path from "path"; import path from "path";
describe("addon resolution", function () { describe("addon resolution", function() {
const base = path.join(__dirname, "fixtures", "resolution"); const base = path.join(__dirname, "fixtures", "resolution");
beforeEach(function() { beforeEach(function() {
@ -20,9 +20,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["module:preset"],
"module:preset",
],
}); });
}); });
@ -32,9 +30,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["module:plugin"],
"module:plugin",
],
}); });
}); });
@ -44,9 +40,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["mod"],
"mod",
],
}); });
}); });
@ -56,9 +50,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["mod"],
"mod",
],
}); });
}); });
@ -68,9 +60,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["babel-preset-mod"],
"babel-preset-mod",
],
}); });
}); });
@ -80,9 +70,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["babel-plugin-mod"],
"babel-plugin-mod",
],
}); });
}); });
@ -92,9 +80,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["@babel/foo"],
"@babel/foo",
],
}); });
}); });
@ -104,9 +90,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["@babel/foo"],
"@babel/foo",
],
}); });
}); });
@ -116,9 +100,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["@babel/preset-foo"],
"@babel/preset-foo",
],
}); });
}); });
@ -128,9 +110,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["@babel/plugin-foo"],
"@babel/plugin-foo",
],
}); });
}); });
@ -140,9 +120,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["@foo/mod"],
"@foo/mod",
],
}); });
}); });
@ -152,9 +130,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["@foo/mod"],
"@foo/mod",
],
}); });
}); });
@ -164,9 +140,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["@foo/babel-preset-mod"],
"@foo/babel-preset-mod",
],
}); });
}); });
@ -176,9 +150,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["@foo/babel-plugin-mod"],
"@foo/babel-plugin-mod",
],
}); });
}); });
@ -188,9 +160,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["./dir/preset.js"],
"./dir/preset.js",
],
}); });
}); });
@ -200,9 +170,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["./dir/plugin.js"],
"./dir/plugin.js",
],
}); });
}); });
@ -212,9 +180,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["mod/preset"],
"mod/preset",
],
}); });
}); });
@ -224,9 +190,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["mod/plugin"],
"mod/plugin",
],
}); });
}); });
@ -236,9 +200,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["@foo/mod/preset"],
"@foo/mod/preset",
],
}); });
}); });
@ -248,9 +210,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["@foo/mod/plugin"],
"@foo/mod/plugin",
],
}); });
}); });
@ -260,9 +220,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["@babel/mod/preset"],
"@babel/mod/preset",
],
}); });
}); });
@ -272,9 +230,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["@babel/mod/plugin"],
"@babel/mod/plugin",
],
}); });
}); });
@ -285,9 +241,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["foo"],
"foo",
],
}); });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
}, /Cannot find module 'babel-preset-foo'.*\n- If you want to resolve "foo", use "module:foo"/); }, /Cannot find module 'babel-preset-foo'.*\n- If you want to resolve "foo", use "module:foo"/);
@ -300,9 +254,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["foo"],
"foo",
],
}); });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
}, /Cannot find module 'babel-plugin-foo'.*\n- If you want to resolve "foo", use "module:foo"/); }, /Cannot find module 'babel-plugin-foo'.*\n- If you want to resolve "foo", use "module:foo"/);
@ -315,9 +267,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["foo"],
"foo",
],
}); });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
}, /Cannot find module 'babel-preset-foo'.*\n- Did you mean "@babel\/foo"\?/); }, /Cannot find module 'babel-preset-foo'.*\n- Did you mean "@babel\/foo"\?/);
@ -330,9 +280,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["foo"],
"foo",
],
}); });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
}, /Cannot find module 'babel-plugin-foo'.*\n- Did you mean "@babel\/foo"\?/); }, /Cannot find module 'babel-plugin-foo'.*\n- Did you mean "@babel\/foo"\?/);
@ -345,9 +293,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["testplugin"],
"testplugin",
],
}); });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
}, /Cannot find module 'babel-preset-testplugin'.*\n- Did you accidentally pass a preset as a plugin\?/); }, /Cannot find module 'babel-preset-testplugin'.*\n- Did you accidentally pass a preset as a plugin\?/);
@ -360,9 +306,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["testpreset"],
"testpreset",
],
}); });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
}, /Cannot find module 'babel-plugin-testpreset'.*\n- Did you accidentally pass a plugin as a preset\?/); }, /Cannot find module 'babel-plugin-testpreset'.*\n- Did you accidentally pass a plugin as a preset\?/);
@ -375,9 +319,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
presets: [ presets: ["foo"],
"foo",
],
}); });
}, /Cannot find module 'babel-preset-foo'/); }, /Cannot find module 'babel-preset-foo'/);
}); });
@ -389,9 +331,7 @@ describe("addon resolution", function () {
babel.transform("", { babel.transform("", {
filename: "filename.js", filename: "filename.js",
babelrc: false, babelrc: false,
plugins: [ plugins: ["foo"],
"foo",
],
}); });
}, /Cannot find module 'babel-plugin-foo'/); }, /Cannot find module 'babel-plugin-foo'/);
}); });

View File

@ -54,7 +54,7 @@ export default class Buffer {
configurable: true, configurable: true,
enumerable: true, enumerable: true,
get() { get() {
return this.map = map.get(); return (this.map = map.get());
}, },
set(value) { set(value) {
Object.defineProperty(this, "map", { value, writable: true }); Object.defineProperty(this, "map", { value, writable: true });
@ -81,7 +81,11 @@ export default class Buffer {
queue(str: string): void { queue(str: string): void {
// Drop trailing spaces when a newline is inserted. // Drop trailing spaces when a newline is inserted.
if (str === "\n") while (this._queue.length > 0 && SPACES_RE.test(this._queue[0][0])) this._queue.shift(); if (str === "\n") {
while (this._queue.length > 0 && SPACES_RE.test(this._queue[0][0])) {
this._queue.shift();
}
}
const { line, column, filename, identifierName } = this._sourcePosition; const { line, column, filename, identifierName } = this._sourcePosition;
this._queue.unshift([str, line, column, identifierName, filename]); this._queue.unshift([str, line, column, identifierName, filename]);
@ -89,13 +93,26 @@ export default class Buffer {
_flush(): void { _flush(): void {
let item; let item;
while (item = this._queue.pop()) this._append(...item); while ((item = this._queue.pop())) this._append(...item);
} }
_append(str: string, line: number, column: number, identifierName: ?string, filename: ?string): void { _append(
str: string,
line: number,
column: number,
identifierName: ?string,
filename: ?string,
): void {
// If there the line is ending, adding a new mapping marker is redundant // If there the line is ending, adding a new mapping marker is redundant
if (this._map && str[0] !== "\n") { if (this._map && str[0] !== "\n") {
this._map.mark(this._position.line, this._position.column, line, column, identifierName, filename); this._map.mark(
this._position.line,
this._position.column,
line,
column,
identifierName,
filename,
);
} }
this._buf.push(str); this._buf.push(str);
@ -112,11 +129,15 @@ export default class Buffer {
} }
removeTrailingNewline(): void { removeTrailingNewline(): void {
if (this._queue.length > 0 && this._queue[0][0] === "\n") this._queue.shift(); if (this._queue.length > 0 && this._queue[0][0] === "\n") {
this._queue.shift();
}
} }
removeLastSemicolon(): void { removeLastSemicolon(): void {
if (this._queue.length > 0 && this._queue[0][0] === ";") this._queue.shift(); if (this._queue.length > 0 && this._queue[0][0] === ";") {
this._queue.shift();
}
} }
endsWith(suffix: string): boolean { endsWith(suffix: string): boolean {
@ -133,7 +154,8 @@ export default class Buffer {
return last === suffix; return last === suffix;
} }
const end = this._last + this._queue.reduce((acc, item) => item[0] + acc, ""); const end =
this._last + this._queue.reduce((acc, item) => item[0] + acc, "");
if (suffix.length <= end.length) { if (suffix.length <= end.length) {
return end.slice(-suffix.length) === suffix; return end.slice(-suffix.length) === suffix;
} }
@ -157,10 +179,10 @@ export default class Buffer {
const pos = loc ? loc[prop] : null; const pos = loc ? loc[prop] : null;
this._sourcePosition.identifierName = loc && loc.identifierName || null; this._sourcePosition.identifierName = (loc && loc.identifierName) || null;
this._sourcePosition.line = pos ? pos.line : null; this._sourcePosition.line = pos ? pos.line : null;
this._sourcePosition.column = pos ? pos.column : null; this._sourcePosition.column = pos ? pos.column : null;
this._sourcePosition.filename = loc && loc.filename || null; this._sourcePosition.filename = (loc && loc.filename) || null;
} }
/** /**
@ -190,7 +212,9 @@ export default class Buffer {
const extra = this._queue.reduce((acc, item) => item[0] + acc, ""); const extra = this._queue.reduce((acc, item) => item[0] + acc, "");
const lastIndex = extra.lastIndexOf("\n"); const lastIndex = extra.lastIndexOf("\n");
return lastIndex === -1 ? this._position.column + extra.length : (extra.length - 1 - lastIndex); return lastIndex === -1
? this._position.column + extra.length
: extra.length - 1 - lastIndex;
} }
getCurrentLine(): number { getCurrentLine(): number {

View File

@ -1,9 +1,12 @@
import * as t from "babel-types"; import * as t from "babel-types";
import * as n from "../node"; import * as n from "../node";
export function UnaryExpression(node: Object) { export function UnaryExpression(node: Object) {
if (node.operator === "void" || node.operator === "delete" || node.operator === "typeof") { if (
node.operator === "void" ||
node.operator === "delete" ||
node.operator === "typeof"
) {
this.word(node.operator); this.word(node.operator);
this.space(); this.space();
} else { } else {
@ -51,12 +54,16 @@ export function NewExpression(node: Object, parent: Object) {
this.word("new"); this.word("new");
this.space(); this.space();
this.print(node.callee, node); this.print(node.callee, node);
if (this.format.minified && if (
this.format.minified &&
node.arguments.length === 0 && node.arguments.length === 0 &&
!node.optional && !node.optional &&
!t.isCallExpression(parent, { callee: node }) && !t.isCallExpression(parent, { callee: node }) &&
!t.isMemberExpression(parent) && !t.isMemberExpression(parent) &&
!t.isNewExpression(parent)) return; !t.isNewExpression(parent)
) {
return;
}
if (node.optional) { if (node.optional) {
this.token("?."); this.token("?.");
@ -123,7 +130,7 @@ export function Import() {
} }
function buildYieldAwait(keyword: string) { function buildYieldAwait(keyword: string) {
return function (node: Object) { return function(node: Object) {
this.word(keyword); this.word(keyword);
if (node.delegate) { if (node.delegate) {
@ -164,7 +171,9 @@ export function AssignmentPattern(node: Object) {
export function AssignmentExpression(node: Object, parent: Object) { export function AssignmentExpression(node: Object, parent: Object) {
// Somewhere inside a for statement `init` node but doesn't usually // Somewhere inside a for statement `init` node but doesn't usually
// needs a paren except for `in` expressions: `for (a in b ? a : b;;)` // needs a paren except for `in` expressions: `for (a in b ? a : b;;)`
const parens = this.inForStatementInitCounter && node.operator === "in" && const parens =
this.inForStatementInitCounter &&
node.operator === "in" &&
!n.needsParens(node, parent); !n.needsParens(node, parent);
if (parens) { if (parens) {

View File

@ -159,7 +159,10 @@ export function FunctionTypeAnnotation(node: Object, parent: Object) {
this.token(")"); this.token(")");
// this node type is overloaded, not sure why but it makes it EXTREMELY annoying // this node type is overloaded, not sure why but it makes it EXTREMELY annoying
if (parent.type === "ObjectTypeCallProperty" || parent.type === "DeclareFunction") { if (
parent.type === "ObjectTypeCallProperty" ||
parent.type === "DeclareFunction"
) {
this.token(":"); this.token(":");
} else { } else {
this.space(); this.space();
@ -183,7 +186,10 @@ export function InterfaceExtends(node: Object) {
this.print(node.typeParameters, node); this.print(node.typeParameters, node);
} }
export { InterfaceExtends as ClassImplements, InterfaceExtends as GenericTypeAnnotation }; export {
InterfaceExtends as ClassImplements,
InterfaceExtends as GenericTypeAnnotation,
};
export function _interfaceish(node: Object) { export function _interfaceish(node: Object) {
this.print(node.id, node); this.print(node.id, node);

View File

@ -4,7 +4,7 @@ export function _params(node: Object) {
this.print(node.typeParameters, node); this.print(node.typeParameters, node);
this.token("("); this.token("(");
this.printList(node.params, node, { this.printList(node.params, node, {
iterator: (node) => { iterator: node => {
if (node.optional) this.token("?"); if (node.optional) this.token("?");
this.print(node.typeAnnotation, node); this.print(node.typeAnnotation, node);
}, },
@ -79,7 +79,11 @@ export function ArrowFunctionExpression(node: Object) {
const firstParam = node.params[0]; const firstParam = node.params[0];
if (node.params.length === 1 && t.isIdentifier(firstParam) && !hasTypes(node, firstParam)) { if (
node.params.length === 1 &&
t.isIdentifier(firstParam) &&
!hasTypes(node, firstParam)
) {
this.print(firstParam, node); this.print(firstParam, node);
} else { } else {
this._params(node); this._params(node);
@ -93,6 +97,11 @@ export function ArrowFunctionExpression(node: Object) {
} }
function hasTypes(node, param) { function hasTypes(node, param) {
return node.typeParameters || node.returnType || param.typeAnnotation || param.optional || return (
param.trailingComments; node.typeParameters ||
node.returnType ||
param.typeAnnotation ||
param.optional ||
param.trailingComments
);
} }

View File

@ -91,7 +91,10 @@ function ExportDeclaration(node: Object) {
let hasSpecial = false; let hasSpecial = false;
while (true) { while (true) {
const first = specifiers[0]; const first = specifiers[0];
if (t.isExportDefaultSpecifier(first) || t.isExportNamespaceSpecifier(first)) { if (
t.isExportDefaultSpecifier(first) ||
t.isExportNamespaceSpecifier(first)
) {
hasSpecial = true; hasSpecial = true;
this.print(specifiers.shift(), node); this.print(specifiers.shift(), node);
if (specifiers.length) { if (specifiers.length) {
@ -138,7 +141,10 @@ export function ImportDeclaration(node: Object) {
// print "special" specifiers first // print "special" specifiers first
while (true) { while (true) {
const first = specifiers[0]; const first = specifiers[0];
if (t.isImportDefaultSpecifier(first) || t.isImportNamespaceSpecifier(first)) { if (
t.isImportDefaultSpecifier(first) ||
t.isImportNamespaceSpecifier(first)
) {
this.print(specifiers.shift(), node); this.print(specifiers.shift(), node);
if (specifiers.length) { if (specifiers.length) {
this.token(","); this.token(",");

View File

@ -17,7 +17,8 @@ export function IfStatement(node: Object) {
this.token(")"); this.token(")");
this.space(); this.space();
const needsBlock = node.alternate && t.isIfStatement(getLastStatement(node.consequent)); const needsBlock =
node.alternate && t.isIfStatement(getLastStatement(node.consequent));
if (needsBlock) { if (needsBlock) {
this.token("{"); this.token("{");
this.newline(); this.newline();
@ -80,8 +81,8 @@ export function WhileStatement(node: Object) {
this.printBlock(node); this.printBlock(node);
} }
const buildForXStatement = function (op) { const buildForXStatement = function(op) {
return function (node: Object) { return function(node: Object) {
this.word("for"); this.word("for");
this.space(); this.space();
if (op === "of" && node.await) { if (op === "of" && node.await) {
@ -116,7 +117,7 @@ export function DoWhileStatement(node: Object) {
} }
function buildLabelStatement(prefix, key = "label") { function buildLabelStatement(prefix, key = "label") {
return function (node: Object) { return function(node: Object) {
this.word(prefix); this.word(prefix);
const label = node[key]; const label = node[key];
@ -261,7 +262,10 @@ export function VariableDeclaration(node: Object, parent: Object) {
let separator; let separator;
if (hasInits) { if (hasInits) {
separator = node.kind === "const" ? constDeclarationIndent : variableDeclarationIndent; separator =
node.kind === "const"
? constDeclarationIndent
: variableDeclarationIndent;
} }
// //

View File

@ -10,9 +10,7 @@ export function RestElement(node: Object) {
this.print(node.argument, node); this.print(node.argument, node);
} }
export { export { RestElement as SpreadElement };
RestElement as SpreadElement,
};
export function ObjectExpression(node: Object) { export function ObjectExpression(node: Object) {
const props = node.properties; const props = node.properties;
@ -45,8 +43,11 @@ export function ObjectProperty(node: Object) {
this.token("]"); this.token("]");
} else { } else {
// print `({ foo: foo = 5 } = {})` as `({ foo = 5 } = {});` // print `({ foo: foo = 5 } = {})` as `({ foo = 5 } = {});`
if (t.isAssignmentPattern(node.value) && t.isIdentifier(node.key) && if (
node.key.name === node.value.left.name) { t.isAssignmentPattern(node.value) &&
t.isIdentifier(node.key) &&
node.key.name === node.value.left.name
) {
this.print(node.value, node); this.print(node.value, node);
return; return;
} }
@ -54,10 +55,12 @@ export function ObjectProperty(node: Object) {
this.print(node.key, node); this.print(node.key, node);
// shorthand! // shorthand!
if (node.shorthand && if (
node.shorthand &&
(t.isIdentifier(node.key) && (t.isIdentifier(node.key) &&
t.isIdentifier(node.value) && t.isIdentifier(node.value) &&
node.key.name === node.value.name)) { node.key.name === node.value.name)
) {
return; return;
} }
} }

View File

@ -61,9 +61,13 @@ function normalizeOptions(code, opts): Format {
if (format.minified) { if (format.minified) {
format.compact = true; format.compact = true;
format.shouldPrintComment = format.shouldPrintComment || (() => format.comments); format.shouldPrintComment =
format.shouldPrintComment || (() => format.comments);
} else { } else {
format.shouldPrintComment = format.shouldPrintComment || ((value) => format.comments || format.shouldPrintComment =
format.shouldPrintComment ||
(value =>
format.comments ||
(value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0)); (value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0));
} }
@ -71,7 +75,9 @@ function normalizeOptions(code, opts): Format {
format.compact = code.length > 500_000; // 500KB format.compact = code.length > 500_000; // 500KB
if (format.compact) { if (format.compact) {
console.error("[BABEL] " + messages.get("codeGeneratorDeopt", opts.filename, "500KB")); console.error(
"[BABEL] " + messages.get("codeGeneratorDeopt", opts.filename, "500KB"),
);
} }
} }
@ -97,7 +103,7 @@ export class CodeGenerator {
} }
} }
export default function (ast: Object, opts: Object, code: string): Object { export default function(ast: Object, opts: Object, code: string): Object {
const gen = new Generator(ast, opts, code); const gen = new Generator(ast, opts, code);
return gen.generate(); return gen.generate();
} }

View File

@ -7,15 +7,16 @@ function expandAliases(obj) {
function add(type, func) { function add(type, func) {
const fn = newObj[type]; const fn = newObj[type];
newObj[type] = fn ? function(node, parent, stack) { newObj[type] = fn
? function(node, parent, stack) {
const result = fn(node, parent, stack); const result = fn(node, parent, stack);
return result == null ? func(node, parent, stack) : result; return result == null ? func(node, parent, stack) : result;
} : func; }
: func;
} }
for (const type of Object.keys(obj)) { for (const type of Object.keys(obj)) {
const aliases = t.FLIPPED_ALIAS_KEYS[type]; const aliases = t.FLIPPED_ALIAS_KEYS[type];
if (aliases) { if (aliases) {
for (const alias of aliases) { for (const alias of aliases) {
@ -46,8 +47,10 @@ function isOrHasCallExpression(node) {
} }
if (t.isMemberExpression(node)) { if (t.isMemberExpression(node)) {
return isOrHasCallExpression(node.object) || return (
(!node.computed && isOrHasCallExpression(node.property)); isOrHasCallExpression(node.object) ||
(!node.computed && isOrHasCallExpression(node.property))
);
} else { } else {
return false; return false;
} }

View File

@ -38,11 +38,19 @@ export function UpdateExpression(node: Object, parent: Object): boolean {
return t.isMemberExpression(parent) && parent.object === node; return t.isMemberExpression(parent) && parent.object === node;
} }
export function ObjectExpression(node: Object, parent: Object, printStack: Array<Object>): boolean { export function ObjectExpression(
node: Object,
parent: Object,
printStack: Array<Object>,
): boolean {
return isFirstInStatement(printStack, { considerArrow: true }); return isFirstInStatement(printStack, { considerArrow: true });
} }
export function DoExpression(node: Object, parent: Object, printStack: Array<Object>): boolean { export function DoExpression(
node: Object,
parent: Object,
printStack: Array<Object>,
): boolean {
return isFirstInStatement(printStack); return isFirstInStatement(printStack);
} }
@ -55,7 +63,8 @@ export function Binary(node: Object, parent: Object): boolean {
} }
if ( if (
((t.isCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node) || ((t.isCallExpression(parent) || t.isNewExpression(parent)) &&
parent.callee === node) ||
t.isUnaryLike(parent) || t.isUnaryLike(parent) ||
(t.isMemberExpression(parent) && parent.object === node) || (t.isMemberExpression(parent) && parent.object === node) ||
t.isAwaitExpression(parent) t.isAwaitExpression(parent)
@ -72,7 +81,9 @@ export function Binary(node: Object, parent: Object): boolean {
if ( if (
// Logical expressions with the same precedence don't need parens. // Logical expressions with the same precedence don't need parens.
(parentPos === nodePos && parent.right === node && !t.isLogicalExpression(parent)) || (parentPos === nodePos &&
parent.right === node &&
!t.isLogicalExpression(parent)) ||
parentPos > nodePos parentPos > nodePos
) { ) {
return true; return true;
@ -85,11 +96,13 @@ export function Binary(node: Object, parent: Object): boolean {
export function BinaryExpression(node: Object, parent: Object): boolean { export function BinaryExpression(node: Object, parent: Object): boolean {
// let i = (1 in []); // let i = (1 in []);
// for ((1 in []);;); // for ((1 in []);;);
return node.operator === "in" && (t.isVariableDeclarator(parent) || t.isFor(parent)); return (
node.operator === "in" &&
(t.isVariableDeclarator(parent) || t.isFor(parent))
);
} }
export function SequenceExpression(node: Object, parent: Object): boolean { export function SequenceExpression(node: Object, parent: Object): boolean {
if ( if (
// Although parentheses wouldn"t hurt around sequence // Although parentheses wouldn"t hurt around sequence
// expressions in the head of for loops, traditional style // expressions in the head of for loops, traditional style
@ -113,29 +126,40 @@ export function SequenceExpression(node: Object, parent: Object): boolean {
} }
export function YieldExpression(node: Object, parent: Object): boolean { export function YieldExpression(node: Object, parent: Object): boolean {
return t.isBinary(parent) || return (
t.isBinary(parent) ||
t.isUnaryLike(parent) || t.isUnaryLike(parent) ||
t.isCallExpression(parent) || t.isCallExpression(parent) ||
t.isMemberExpression(parent) || t.isMemberExpression(parent) ||
t.isNewExpression(parent) || t.isNewExpression(parent) ||
(t.isConditionalExpression(parent) && node === parent.test); (t.isConditionalExpression(parent) && node === parent.test)
);
} }
export { YieldExpression as AwaitExpression }; export { YieldExpression as AwaitExpression };
export function ClassExpression(node: Object, parent: Object, printStack: Array<Object>): boolean { export function ClassExpression(
node: Object,
parent: Object,
printStack: Array<Object>,
): boolean {
return isFirstInStatement(printStack, { considerDefaultExports: true }); return isFirstInStatement(printStack, { considerDefaultExports: true });
} }
export function UnaryLike(node: Object, parent: Object): boolean { export function UnaryLike(node: Object, parent: Object): boolean {
return t.isMemberExpression(parent, { object: node }) || return (
t.isMemberExpression(parent, { object: node }) ||
t.isCallExpression(parent, { callee: node }) || t.isCallExpression(parent, { callee: node }) ||
t.isNewExpression(parent, { callee: node }) || t.isNewExpression(parent, { callee: node }) ||
t.isBinaryExpression(parent, { operator: "**", left: node }); t.isBinaryExpression(parent, { operator: "**", left: node })
);
} }
export function FunctionExpression(node: Object, parent: Object, printStack: Array<Object>): boolean { export function FunctionExpression(
node: Object,
parent: Object,
printStack: Array<Object>,
): boolean {
return isFirstInStatement(printStack, { considerDefaultExports: true }); return isFirstInStatement(printStack, { considerDefaultExports: true });
} }
@ -167,10 +191,10 @@ export function AssignmentExpression(node: Object): boolean {
// Walk up the print stack to deterimine if our node can come first // Walk up the print stack to deterimine if our node can come first
// in statement. // in statement.
function isFirstInStatement(printStack: Array<Object>, { function isFirstInStatement(
considerArrow = false, printStack: Array<Object>,
considerDefaultExports = false, { considerArrow = false, considerDefaultExports = false } = {},
} = {}): boolean { ): boolean {
let i = printStack.length - 1; let i = printStack.length - 1;
let node = printStack[i]; let node = printStack[i];
i--; i--;
@ -179,8 +203,9 @@ function isFirstInStatement(printStack: Array<Object>, {
if ( if (
t.isExpressionStatement(parent, { expression: node }) || t.isExpressionStatement(parent, { expression: node }) ||
t.isTaggedTemplateExpression(parent) || t.isTaggedTemplateExpression(parent) ||
considerDefaultExports && t.isExportDefaultDeclaration(parent, { declaration: node }) || (considerDefaultExports &&
considerArrow && t.isArrowFunctionExpression(parent, { body: node }) t.isExportDefaultDeclaration(parent, { declaration: node })) ||
(considerArrow && t.isArrowFunctionExpression(parent, { body: node }))
) { ) {
return true; return true;
} }

View File

@ -3,7 +3,7 @@ import * as t from "babel-types";
type WhitespaceObject = { type WhitespaceObject = {
before?: boolean, before?: boolean,
after?: boolean after?: boolean,
}; };
/** /**
@ -45,15 +45,22 @@ function isHelper(node) {
} else if (t.isCallExpression(node)) { } else if (t.isCallExpression(node)) {
return isHelper(node.callee); return isHelper(node.callee);
} else if (t.isBinary(node) || t.isAssignmentExpression(node)) { } else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
return (t.isIdentifier(node.left) && isHelper(node.left)) || isHelper(node.right); return (
(t.isIdentifier(node.left) && isHelper(node.left)) || isHelper(node.right)
);
} else { } else {
return false; return false;
} }
} }
function isType(node) { function isType(node) {
return t.isLiteral(node) || t.isObjectExpression(node) || t.isArrayExpression(node) || return (
t.isIdentifier(node) || t.isMemberExpression(node); t.isLiteral(node) ||
t.isObjectExpression(node) ||
t.isArrayExpression(node) ||
t.isIdentifier(node) ||
t.isMemberExpression(node)
);
} }
/** /**
@ -61,7 +68,6 @@ function isType(node) {
*/ */
export const nodes = { export const nodes = {
/** /**
* Test if AssignmentExpression needs whitespace. * Test if AssignmentExpression needs whitespace.
*/ */
@ -164,9 +170,10 @@ export const nodes = {
* Test if Property needs whitespace. * Test if Property needs whitespace.
*/ */
nodes.ObjectProperty = nodes.ObjectProperty = nodes.ObjectTypeProperty = nodes.ObjectMethod = function(
nodes.ObjectTypeProperty = node: Object,
nodes.ObjectMethod = function (node: Object, parent): ?WhitespaceObject { parent,
): ?WhitespaceObject {
if (parent.properties[0] === node) { if (parent.properties[0] === node) {
return { return {
before: true, before: true,
@ -179,7 +186,6 @@ nodes.ObjectMethod = function (node: Object, parent): ?WhitespaceObject {
*/ */
export const list = { export const list = {
/** /**
* Return VariableDeclaration declarations init properties. * Return VariableDeclaration declarations init properties.
*/ */
@ -216,12 +222,12 @@ export const list = {
["LabeledStatement", true], ["LabeledStatement", true],
["SwitchStatement", true], ["SwitchStatement", true],
["TryStatement", true], ["TryStatement", true],
].forEach(function ([type, amounts]) { ].forEach(function([type, amounts]) {
if (typeof amounts === "boolean") { if (typeof amounts === "boolean") {
amounts = { after: amounts, before: amounts }; amounts = { after: amounts, before: amounts };
} }
[type].concat(t.FLIPPED_ALIAS_KEYS[type] || []).forEach(function (type) { [type].concat(t.FLIPPED_ALIAS_KEYS[type] || []).forEach(function(type) {
nodes[type] = function () { nodes[type] = function() {
return amounts; return amounts;
}; };
}); });

View File

@ -14,21 +14,21 @@ const ZERO_DECIMAL_INTEGER = /\.0+$/;
const NON_DECIMAL_LITERAL = /^0[box]/; const NON_DECIMAL_LITERAL = /^0[box]/;
export type Format = { export type Format = {
shouldPrintComment: (comment: string) => boolean; shouldPrintComment: (comment: string) => boolean,
retainLines: boolean; retainLines: boolean,
retainFunctionParens: boolean; retainFunctionParens: boolean,
comments: boolean; comments: boolean,
auxiliaryCommentBefore: string; auxiliaryCommentBefore: string,
auxiliaryCommentAfter: string; auxiliaryCommentAfter: string,
compact: boolean | "auto"; compact: boolean | "auto",
minified: boolean; minified: boolean,
quotes: "single" | "double"; quotes: "single" | "double",
concise: boolean; concise: boolean,
indent: { indent: {
adjustMultilineComment: boolean; adjustMultilineComment: boolean,
style: string; style: string,
base: number; base: number,
} },
}; };
export default class Printer { export default class Printer {
@ -107,7 +107,10 @@ export default class Printer {
space(force: boolean = false): void { space(force: boolean = false): void {
if (this.format.compact) return; if (this.format.compact) return;
if ((this._buf.hasContent() && !this.endsWith(" ") && !this.endsWith("\n")) || force) { if (
(this._buf.hasContent() && !this.endsWith(" ") && !this.endsWith("\n")) ||
force
) {
this._space(); this._space();
} }
} }
@ -149,14 +152,14 @@ export default class Printer {
token(str: string): void { token(str: string): void {
// space is mandatory to avoid outputting <!-- // space is mandatory to avoid outputting <!--
// http://javascript.spec.whatwg.org/#comment-syntax // http://javascript.spec.whatwg.org/#comment-syntax
if ((str === "--" && this.endsWith("!")) || if (
(str === "--" && this.endsWith("!")) ||
// Need spaces for operators of the same kind to avoid: `a+++b` // Need spaces for operators of the same kind to avoid: `a+++b`
(str[0] === "+" && this.endsWith("+")) || (str[0] === "+" && this.endsWith("+")) ||
(str[0] === "-" && this.endsWith("-")) || (str[0] === "-" && this.endsWith("-")) ||
// Needs spaces to avoid changing '34' to '34.', which would still be a valid number. // Needs spaces to avoid changing '34' to '34.', which would still be a valid number.
(str[0] === "." && this._endsWithInteger)) { (str[0] === "." && this._endsWithInteger)
) {
this._space(); this._space();
} }
@ -294,9 +297,9 @@ export default class Printer {
*/ */
startTerminatorless(): Object { startTerminatorless(): Object {
return this._parenPushNewlineState = { return (this._parenPushNewlineState = {
printed: false, printed: false,
}; });
} }
/** /**
@ -322,7 +325,11 @@ export default class Printer {
const printMethod = this[node.type]; const printMethod = this[node.type];
if (!printMethod) { if (!printMethod) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
throw new ReferenceError(`unknown node of type ${JSON.stringify(node.type)} with constructor ${JSON.stringify(node && node.constructor.name)}`); throw new ReferenceError(
`unknown node of type ${JSON.stringify(
node.type,
)} with constructor ${JSON.stringify(node && node.constructor.name)}`,
);
} }
this._printStack.push(node); this._printStack.push(node);
@ -335,7 +342,8 @@ export default class Printer {
if ( if (
this.format.retainFunctionParens && this.format.retainFunctionParens &&
node.type === "FunctionExpression" && node.type === "FunctionExpression" &&
node.extra && node.extra.parenthesized node.extra &&
node.extra.parenthesized
) { ) {
needsParens = true; needsParens = true;
} }
@ -343,7 +351,7 @@ export default class Printer {
this._printLeadingComments(node, parent); this._printLeadingComments(node, parent);
const loc = (t.isProgram(node) || t.isFile(node)) ? null : node.loc; const loc = t.isProgram(node) || t.isFile(node) ? null : node.loc;
this.withSource("start", loc, () => { this.withSource("start", loc, () => {
this[node.type](node, parent); this[node.type](node, parent);
}); });
@ -392,7 +400,12 @@ export default class Printer {
getPossibleRaw(node) { getPossibleRaw(node) {
const extra = node.extra; const extra = node.extra;
if (extra && extra.raw != null && extra.rawValue != null && node.value === extra.rawValue) { if (
extra &&
extra.raw != null &&
extra.rawValue != null &&
node.value === extra.rawValue
) {
return extra.raw; return extra.raw;
} }
} }
@ -490,14 +503,24 @@ export default class Printer {
// user node // user node
if (leading) { if (leading) {
const comments = node.leadingComments; const comments = node.leadingComments;
const comment = comments && find(comments, (comment) => const comment =
!!comment.loc && this.format.shouldPrintComment(comment.value)); comments &&
find(
comments,
comment =>
!!comment.loc && this.format.shouldPrintComment(comment.value),
);
lines = this._whitespace.getNewlinesBefore(comment || node); lines = this._whitespace.getNewlinesBefore(comment || node);
} else { } else {
const comments = node.trailingComments; const comments = node.trailingComments;
const comment = comments && findLast(comments, (comment) => const comment =
!!comment.loc && this.format.shouldPrintComment(comment.value)); comments &&
findLast(
comments,
comment =>
!!comment.loc && this.format.shouldPrintComment(comment.value),
);
lines = this._whitespace.getNewlinesAfter(comment || node); lines = this._whitespace.getNewlinesAfter(comment || node);
} }
@ -520,7 +543,9 @@ export default class Printer {
_getComments(leading, node) { _getComments(leading, node) {
// Note, we use a boolean flag here instead of passing in the attribute name as it is faster // Note, we use a boolean flag here instead of passing in the attribute name as it is faster
// because this is called extremely frequently. // because this is called extremely frequently.
return (node && (leading ? node.leadingComments : node.trailingComments)) || []; return (
(node && (leading ? node.leadingComments : node.trailingComments)) || []
);
} }
_printComment(comment) { _printComment(comment) {
@ -539,21 +564,32 @@ export default class Printer {
} }
// whitespace before // whitespace before
this.newline(this._whitespace ? this._whitespace.getNewlinesBefore(comment) : 0); this.newline(
this._whitespace ? this._whitespace.getNewlinesBefore(comment) : 0,
);
if (!this.endsWith("[") && !this.endsWith("{")) this.space(); if (!this.endsWith("[") && !this.endsWith("{")) this.space();
let val = comment.type === "CommentLine" ? `//${comment.value}\n` : `/*${comment.value}*/`; let val =
comment.type === "CommentLine"
? `//${comment.value}\n`
: `/*${comment.value}*/`;
// //
if (comment.type === "CommentBlock" && this.format.indent.adjustMultilineComment) { if (
comment.type === "CommentBlock" &&
this.format.indent.adjustMultilineComment
) {
const offset = comment.loc && comment.loc.start.column; const offset = comment.loc && comment.loc.start.column;
if (offset) { if (offset) {
const newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g"); const newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
val = val.replace(newlineRegex, "\n"); val = val.replace(newlineRegex, "\n");
} }
const indentSize = Math.max(this._getIndent().length, this._buf.getCurrentColumn()); const indentSize = Math.max(
this._getIndent().length,
this._buf.getCurrentColumn(),
);
val = val.replace(/\n(?!$)/g, `\n${repeat(" ", indentSize)}`); val = val.replace(/\n(?!$)/g, `\n${repeat(" ", indentSize)}`);
} }
@ -565,9 +601,11 @@ export default class Printer {
}); });
// whitespace after // whitespace after
this.newline((this._whitespace ? this._whitespace.getNewlinesAfter(comment) : 0) + this.newline(
(this._whitespace ? this._whitespace.getNewlinesAfter(comment) : 0) +
// Subtract one to account for the line force-added above. // Subtract one to account for the line force-added above.
(comment.type === "CommentLine" ? -1 : 0)); (comment.type === "CommentLine" ? -1 : 0),
);
} }
_printComments(comments?: Array<Object>) { _printComments(comments?: Array<Object>) {

View File

@ -18,16 +18,16 @@ export default class SourceMap {
get() { get() {
if (!this._cachedMap) { if (!this._cachedMap) {
const map = this._cachedMap = new sourceMap.SourceMapGenerator({ const map = (this._cachedMap = new sourceMap.SourceMapGenerator({
file: this._opts.sourceMapTarget, file: this._opts.sourceMapTarget,
sourceRoot: this._opts.sourceRoot, sourceRoot: this._opts.sourceRoot,
}); }));
const code = this._code; const code = this._code;
if (typeof code === "string") { if (typeof code === "string") {
map.setSourceContent(this._opts.sourceFileName, code); map.setSourceContent(this._opts.sourceFileName, code);
} else if (typeof code === "object") { } else if (typeof code === "object") {
Object.keys(code).forEach((sourceFileName) => { Object.keys(code).forEach(sourceFileName => {
map.setSourceContent(sourceFileName, code[sourceFileName]); map.setSourceContent(sourceFileName, code[sourceFileName]);
}); });
} }
@ -60,8 +60,11 @@ export default class SourceMap {
// If this mapping points to the same source location as the last one, we can ignore it since // If this mapping points to the same source location as the last one, we can ignore it since
// the previous one covers it. // the previous one covers it.
if (this._lastGenLine === generatedLine && this._lastSourceLine === line && if (
this._lastSourceColumn === column) { this._lastGenLine === generatedLine &&
this._lastSourceLine === line &&
this._lastSourceColumn === column
) {
return; return;
} }
@ -80,7 +83,10 @@ export default class SourceMap {
column: generatedColumn, column: generatedColumn,
}, },
source: line == null ? undefined : filename || this._opts.sourceFileName, source: line == null ? undefined : filename || this._opts.sourceFileName,
original: line == null ? undefined : { original:
line == null
? undefined
: {
line: line, line: line,
column: column, column: column,
}, },

View File

@ -17,7 +17,11 @@ export default class Whitespace {
let endToken; let endToken;
const tokens = this.tokens; const tokens = this.tokens;
let index = this._findToken((token) => token.start - node.start, 0, tokens.length); let index = this._findToken(
token => token.start - node.start,
0,
tokens.length,
);
if (index >= 0) { if (index >= 0) {
while (index && node.start === tokens[index - 1].start) --index; while (index && node.start === tokens[index - 1].start) --index;
startToken = tokens[index - 1]; startToken = tokens[index - 1];
@ -36,7 +40,11 @@ export default class Whitespace {
let endToken; let endToken;
const tokens = this.tokens; const tokens = this.tokens;
let index = this._findToken((token) => token.end - node.end, 0, tokens.length); let index = this._findToken(
token => token.end - node.end,
0,
tokens.length,
);
if (index >= 0) { if (index >= 0) {
while (index && node.end === tokens[index - 1].end) --index; while (index && node.end === tokens[index - 1].end) --index;
startToken = tokens[index]; startToken = tokens[index];

View File

@ -9,125 +9,164 @@ import fs from "fs";
import path from "path"; import path from "path";
import fixtures from "babel-helper-fixtures"; import fixtures from "babel-helper-fixtures";
describe("generation", function () { describe("generation", function() {
it("completeness", function () { it("completeness", function() {
Object.keys(t.VISITOR_KEYS).forEach(function (type) { Object.keys(t.VISITOR_KEYS).forEach(function(type) {
assert.ok(!!Printer.prototype[type], type + " should exist"); assert.ok(!!Printer.prototype[type], type + " should exist");
}); });
Object.keys(Printer.prototype).forEach(function (type) { Object.keys(Printer.prototype).forEach(function(type) {
if (!/[A-Z]/.test(type[0])) return; if (!/[A-Z]/.test(type[0])) return;
assert.ok(t.VISITOR_KEYS[type], type + " should not exist"); assert.ok(t.VISITOR_KEYS[type], type + " should not exist");
}); });
}); });
it("multiple sources", function () { it("multiple sources", function() {
const sources = { const sources = {
"a.js": "function hi (msg) { console.log(msg); }\n", "a.js": "function hi (msg) { console.log(msg); }\n",
"b.js": "hi('hello');\n", "b.js": "hi('hello');\n",
}; };
const parsed = Object.keys(sources).reduce(function (_parsed, filename) { const parsed = Object.keys(sources).reduce(function(_parsed, filename) {
_parsed[filename] = parse(sources[filename], { sourceFilename: filename }); _parsed[filename] = parse(sources[filename], {
sourceFilename: filename,
});
return _parsed; return _parsed;
}, {}); }, {});
const combinedAst = { const combinedAst = {
"type": "File", type: "File",
"program": { program: {
"type": "Program", type: "Program",
"sourceType": "module", sourceType: "module",
"body": [].concat(parsed["a.js"].program.body, parsed["b.js"].program.body), body: [].concat(
parsed["a.js"].program.body,
parsed["b.js"].program.body,
),
}, },
}; };
const generated = generate(combinedAst, { sourceMaps: true }, sources); const generated = generate(combinedAst, { sourceMaps: true }, sources);
chai.expect(generated.map).to.deep.equal({ chai.expect(generated.map).to.deep.equal(
{
version: 3, version: 3,
sources: [ "a.js", "b.js" ], sources: ["a.js", "b.js"],
mappings: "AAAA,SAASA,EAAT,CAAaC,GAAb,EAAkB;AAAEC,UAAQC,GAAR,CAAYF,GAAZ;AAAmB;;ACAvCD,GAAG,OAAH", mappings:
names: [ "AAAA,SAASA,EAAT,CAAaC,GAAb,EAAkB;AAAEC,UAAQC,GAAR,CAAYF,GAAZ;AAAmB;;ACAvCD,GAAG,OAAH",
"hi", names: ["hi", "msg", "console", "log"],
"msg",
"console",
"log",
],
sourcesContent: [ sourcesContent: [
"function hi (msg) { console.log(msg); }\n", "function hi (msg) { console.log(msg); }\n",
"hi('hello');\n", "hi('hello');\n",
], ],
}, "sourcemap was incorrectly generated"); },
"sourcemap was incorrectly generated",
);
chai.expect(generated.rawMappings).to.deep.equal([ chai.expect(generated.rawMappings).to.deep.equal(
{ name: undefined, [
{
name: undefined,
generated: { line: 1, column: 0 }, generated: { line: 1, column: 0 },
source: "a.js", source: "a.js",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
{ name: "hi", },
{
name: "hi",
generated: { line: 1, column: 9 }, generated: { line: 1, column: 9 },
source: "a.js", source: "a.js",
original: { line: 1, column: 9 } }, original: { line: 1, column: 9 },
{ name: undefined, },
{
name: undefined,
generated: { line: 1, column: 11 }, generated: { line: 1, column: 11 },
source: "a.js", source: "a.js",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
{ name: "msg", },
{
name: "msg",
generated: { line: 1, column: 12 }, generated: { line: 1, column: 12 },
source: "a.js", source: "a.js",
original: { line: 1, column: 13 } }, original: { line: 1, column: 13 },
{ name: undefined, },
{
name: undefined,
generated: { line: 1, column: 15 }, generated: { line: 1, column: 15 },
source: "a.js", source: "a.js",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
{ name: undefined, },
{
name: undefined,
generated: { line: 1, column: 17 }, generated: { line: 1, column: 17 },
source: "a.js", source: "a.js",
original: { line: 1, column: 18 } }, original: { line: 1, column: 18 },
{ name: "console", },
{
name: "console",
generated: { line: 2, column: 0 }, generated: { line: 2, column: 0 },
source: "a.js", source: "a.js",
original: { line: 1, column: 20 } }, original: { line: 1, column: 20 },
{ name: "log", },
{
name: "log",
generated: { line: 2, column: 10 }, generated: { line: 2, column: 10 },
source: "a.js", source: "a.js",
original: { line: 1, column: 28 } }, original: { line: 1, column: 28 },
{ name: undefined, },
{
name: undefined,
generated: { line: 2, column: 13 }, generated: { line: 2, column: 13 },
source: "a.js", source: "a.js",
original: { line: 1, column: 20 } }, original: { line: 1, column: 20 },
{ name: "msg", },
{
name: "msg",
generated: { line: 2, column: 14 }, generated: { line: 2, column: 14 },
source: "a.js", source: "a.js",
original: { line: 1, column: 32 } }, original: { line: 1, column: 32 },
{ name: undefined, },
{
name: undefined,
generated: { line: 2, column: 17 }, generated: { line: 2, column: 17 },
source: "a.js", source: "a.js",
original: { line: 1, column: 20 } }, original: { line: 1, column: 20 },
{ name: undefined, },
{
name: undefined,
generated: { line: 3, column: 0 }, generated: { line: 3, column: 0 },
source: "a.js", source: "a.js",
original: { line: 1, column: 39 } }, original: { line: 1, column: 39 },
{ name: "hi", },
{
name: "hi",
generated: { line: 5, column: 0 }, generated: { line: 5, column: 0 },
source: "b.js", source: "b.js",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
{ name: undefined, },
{
name: undefined,
generated: { line: 5, column: 3 }, generated: { line: 5, column: 3 },
source: "b.js", source: "b.js",
original: { line: 1, column: 3 } }, original: { line: 1, column: 3 },
{ name: undefined, },
{
name: undefined,
generated: { line: 5, column: 10 }, generated: { line: 5, column: 10 },
source: "b.js", source: "b.js",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
], "raw mappings were incorrectly generated"); },
],
"raw mappings were incorrectly generated",
);
chai.expect(generated.code).to.equal( chai
.expect(generated.code)
.to.equal(
"function hi(msg) {\n console.log(msg);\n}\n\nhi('hello');", "function hi(msg) {\n console.log(msg);\n}\n\nhi('hello');",
"code was incorrectly generated" "code was incorrectly generated",
); );
}); });
it("identifierName", function () { it("identifierName", function() {
const code = "function foo() { bar; }\n"; const code = "function foo() { bar; }\n";
const ast = parse(code, { filename: "inline" }).program; const ast = parse(code, { filename: "inline" }).program;
@ -141,50 +180,74 @@ describe("generation", function () {
id2.name += "2"; id2.name += "2";
id2.loc.identiferName = "bar"; id2.loc.identiferName = "bar";
const generated = generate(ast, { const generated = generate(
ast,
{
filename: "inline", filename: "inline",
sourceFileName: "inline", sourceFileName: "inline",
sourceMaps: true, sourceMaps: true,
}, code); },
code,
);
chai.expect(generated.map).to.deep.equal({ chai.expect(generated.map).to.deep.equal(
{
version: 3, version: 3,
sources: ["inline"], sources: ["inline"],
names: ["foo", "bar" ], names: ["foo", "bar"],
mappings: "AAAA,SAASA,IAAT,GAAe;AAAEC;AAAM", mappings: "AAAA,SAASA,IAAT,GAAe;AAAEC;AAAM",
sourcesContent: [ "function foo() { bar; }\n" ], sourcesContent: ["function foo() { bar; }\n"],
}, "sourcemap was incorrectly generated"); },
"sourcemap was incorrectly generated",
);
chai.expect(generated.rawMappings).to.deep.equal([ chai.expect(generated.rawMappings).to.deep.equal(
{ name: undefined, [
{
name: undefined,
generated: { line: 1, column: 0 }, generated: { line: 1, column: 0 },
source: "inline", source: "inline",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
{ name: "foo", },
{
name: "foo",
generated: { line: 1, column: 9 }, generated: { line: 1, column: 9 },
source: "inline", source: "inline",
original: { line: 1, column: 9 } }, original: { line: 1, column: 9 },
{ name: undefined, },
{
name: undefined,
generated: { line: 1, column: 13 }, generated: { line: 1, column: 13 },
source: "inline", source: "inline",
original: { line: 1, column: 0 } }, original: { line: 1, column: 0 },
{ name: undefined, },
{
name: undefined,
generated: { line: 1, column: 16 }, generated: { line: 1, column: 16 },
source: "inline", source: "inline",
original: { line: 1, column: 15 } }, original: { line: 1, column: 15 },
{ name: "bar", },
{
name: "bar",
generated: { line: 2, column: 0 }, generated: { line: 2, column: 0 },
source: "inline", source: "inline",
original: { line: 1, column: 17 } }, original: { line: 1, column: 17 },
{ name: undefined, },
{
name: undefined,
generated: { line: 3, column: 0 }, generated: { line: 3, column: 0 },
source: "inline", source: "inline",
original: { line: 1, column: 23 } }, original: { line: 1, column: 23 },
], "raw mappings were incorrectly generated"); },
],
"raw mappings were incorrectly generated",
);
chai.expect(generated.code).to.equal( chai
.expect(generated.code)
.to.equal(
"function foo2() {\n bar2;\n}", "function foo2() {\n bar2;\n}",
"code was incorrectly generated" "code was incorrectly generated",
); );
}); });
@ -199,17 +262,22 @@ describe("generation", function () {
chai.expect(generated.rawMappings).to.be.an("array"); chai.expect(generated.rawMappings).to.be.an("array");
chai.expect(generated).ownPropertyDescriptor("map").not.to.have.property("value"); chai
.expect(generated)
.ownPropertyDescriptor("map")
.not.to.have.property("value");
chai.expect(generated.map).to.be.an("object"); chai.expect(generated.map).to.be.an("object");
}); });
}); });
describe("programmatic generation", function() { describe("programmatic generation", function() {
it("numeric member expression", function() { it("numeric member expression", function() {
// Should not generate `0.foo` // Should not generate `0.foo`
const mem = t.memberExpression(t.numericLiteral(60702), t.identifier("foo")); const mem = t.memberExpression(
t.numericLiteral(60702),
t.identifier("foo"),
);
new Function(generate(mem).code); new Function(generate(mem).code);
}); });
@ -220,10 +288,10 @@ describe("programmatic generation", function() {
t.stringLiteral("while cond"), t.stringLiteral("while cond"),
t.ifStatement( t.ifStatement(
t.stringLiteral("nested"), t.stringLiteral("nested"),
t.expressionStatement(t.numericLiteral(1)) t.expressionStatement(t.numericLiteral(1)),
)
), ),
t.expressionStatement(t.stringLiteral("alt")) ),
t.expressionStatement(t.stringLiteral("alt")),
); );
const ast = parse(generate(ifStatement).code); const ast = parse(generate(ifStatement).code);
@ -233,35 +301,22 @@ describe("programmatic generation", function() {
it("prints directives in block with empty body", function() { it("prints directives in block with empty body", function() {
const blockStatement = t.blockStatement( const blockStatement = t.blockStatement(
[], [],
[t.directive(t.directiveLiteral("use strict"))] [t.directive(t.directiveLiteral("use strict"))],
); );
const output = generate(blockStatement).code; const output = generate(blockStatement).code;
assert.equal(output, [ assert.equal(output, ["{", ' "use strict";', "}"].join("\n"));
"{",
" \"use strict\";",
"}",
].join("\n"));
}); });
it("flow object indentation", function() { it("flow object indentation", function() {
const objectStatement = t.objectTypeAnnotation( const objectStatement = t.objectTypeAnnotation(
[ [t.objectTypeProperty(t.identifier("bar"), t.stringTypeAnnotation())],
t.objectTypeProperty( null,
t.identifier("bar"),
t.stringTypeAnnotation()
),
],
null, null,
null
); );
const output = generate(objectStatement).code; const output = generate(objectStatement).code;
assert.equal(output, [ assert.equal(output, ["{", " bar: string,", "}"].join("\n"));
"{",
" bar: string,",
"}",
].join("\n"));
}); });
it("flow object indentation with empty leading ObjectTypeProperty", function() { it("flow object indentation with empty leading ObjectTypeProperty", function() {
@ -273,21 +328,17 @@ describe("programmatic generation", function() {
t.anyTypeAnnotation(), t.anyTypeAnnotation(),
t.identifier("Test"), t.identifier("Test"),
), ),
] ],
); );
const output = generate(objectStatement).code; const output = generate(objectStatement).code;
assert.equal(output, [ assert.equal(output, ["{", " [key: any]: Test,", "}"].join("\n"));
"{",
" [key: any]: Test,",
"}",
].join("\n"));
}); });
}); });
describe("whitespace", function () { describe("whitespace", function() {
it("empty token list", function () { it("empty token list", function() {
const w = new Whitespace([]); const w = new Whitespace([]);
assert.equal(w.getNewlinesBefore(t.stringLiteral("1")), 0); assert.equal(w.getNewlinesBefore(t.stringLiteral("1")), 0);
}); });
@ -295,10 +346,13 @@ describe("whitespace", function () {
const suites = fixtures(`${__dirname}/fixtures`); const suites = fixtures(`${__dirname}/fixtures`);
suites.forEach(function (testSuite) { suites.forEach(function(testSuite) {
describe("generation/" + testSuite.title, function () { describe("generation/" + testSuite.title, function() {
testSuite.tests.forEach(function (task) { testSuite.tests.forEach(function(task) {
it(task.title, !task.disabled && function () { it(
task.title,
!task.disabled &&
function() {
const expect = task.expect; const expect = task.expect;
const actual = task.actual; const actual = task.actual;
const actualCode = actual.code; const actualCode = actual.code;
@ -326,16 +380,21 @@ suites.forEach(function (testSuite) {
const result = generate(actualAst, task.options, actualCode); const result = generate(actualAst, task.options, actualCode);
if ( if (
!expect.code && result.code && fs.statSync(path.dirname(expect.loc)).isDirectory() && !expect.code &&
result.code &&
fs.statSync(path.dirname(expect.loc)).isDirectory() &&
!process.env.CI !process.env.CI
) { ) {
console.log(`New test file created: ${expect.loc}`); console.log(`New test file created: ${expect.loc}`);
fs.writeFileSync(expect.loc, result.code); fs.writeFileSync(expect.loc, result.code);
} else { } else {
chai.expect(result.code).to.be.equal(expect.code, actual.loc + " !== " + expect.loc); chai
.expect(result.code)
.to.be.equal(expect.code, actual.loc + " !== " + expect.loc);
} }
} }
}); },
);
}); });
}); });
}); });

View File

@ -1,7 +1,9 @@
import type { NodePath } from "babel-traverse"; import type { NodePath } from "babel-traverse";
import * as t from "babel-types"; import * as t from "babel-types";
export default function bindifyDecorators(decorators: Array<NodePath>): Array<NodePath> { export default function bindifyDecorators(
decorators: Array<NodePath>,
): Array<NodePath> {
for (const decoratorPath of decorators) { for (const decoratorPath of decorators) {
const decorator = decoratorPath.node; const decorator = decoratorPath.node;
const expression = decorator.expression; const expression = decorator.expression;
@ -19,13 +21,15 @@ export default function bindifyDecorators(decorators: Array<NodePath>): Array<No
ref = expression.object; ref = expression.object;
} }
nodes.push(t.callExpression( nodes.push(
t.callExpression(
t.memberExpression( t.memberExpression(
t.memberExpression(ref, expression.property, expression.computed), t.memberExpression(ref, expression.property, expression.computed),
t.identifier("bind") t.identifier("bind"),
), ),
[ref] [ref],
)); ),
);
if (nodes.length === 1) { if (nodes.length === 1) {
decorator.expression = nodes[0]; decorator.expression = nodes[0];

View File

@ -1,10 +1,7 @@
import explode from "babel-helper-explode-assignable-expression"; import explode from "babel-helper-explode-assignable-expression";
import * as t from "babel-types"; import * as t from "babel-types";
export default function (opts: { export default function(opts: { build: Function, operator: string }): Object {
build: Function;
operator: string;
}): Object {
const visitor = {}; const visitor = {};
function isAssignment(node) { function isAssignment(node) {
@ -15,7 +12,7 @@ export default function (opts: {
return t.assignmentExpression("=", left, right); return t.assignmentExpression("=", left, right);
} }
visitor.ExpressionStatement = function (path, file) { visitor.ExpressionStatement = function(path, file) {
// hit the `AssignmentExpression` one below // hit the `AssignmentExpression` one below
if (path.isCompletionRecord()) return; if (path.isCompletionRecord()) return;
@ -25,24 +22,28 @@ export default function (opts: {
const nodes = []; const nodes = [];
const exploded = explode(expr.left, nodes, file, path.scope, true); const exploded = explode(expr.left, nodes, file, path.scope, true);
nodes.push(t.expressionStatement( nodes.push(
buildAssignment(exploded.ref, opts.build(exploded.uid, expr.right)) t.expressionStatement(
)); buildAssignment(exploded.ref, opts.build(exploded.uid, expr.right)),
),
);
path.replaceWithMultiple(nodes); path.replaceWithMultiple(nodes);
}; };
visitor.AssignmentExpression = function (path, file) { visitor.AssignmentExpression = function(path, file) {
const { node, scope } = path; const { node, scope } = path;
if (!isAssignment(node)) return; if (!isAssignment(node)) return;
const nodes = []; const nodes = [];
const exploded = explode(node.left, nodes, file, scope); const exploded = explode(node.left, nodes, file, scope);
nodes.push(buildAssignment(exploded.ref, opts.build(exploded.uid, node.right))); nodes.push(
buildAssignment(exploded.ref, opts.build(exploded.uid, node.right)),
);
path.replaceWithMultiple(nodes); path.replaceWithMultiple(nodes);
}; };
visitor.BinaryExpression = function (path) { visitor.BinaryExpression = function(path) {
const { node } = path; const { node } = path;
if (node.operator === opts.operator) { if (node.operator === opts.operator) {
path.replaceWith(opts.build(node.left, node.right)); path.replaceWith(opts.build(node.left, node.right));

View File

@ -2,19 +2,21 @@ import esutils from "esutils";
import * as t from "babel-types"; import * as t from "babel-types";
type ElementState = { type ElementState = {
tagExpr: Object; // tag node tagExpr: Object, // tag node
tagName: string; // raw string tag name tagName: string, // raw string tag name
args: Array<Object>; // array of call arguments args: Array<Object>, // array of call arguments
call?: Object; // optional call property that can be set to override the call expression returned call?: Object, // optional call property that can be set to override the call expression returned
pre?: Function; // function called with (state: ElementState) before building attribs pre?: Function, // function called with (state: ElementState) before building attribs
post?: Function; // function called with (state: ElementState) after building attribs post?: Function, // function called with (state: ElementState) after building attribs
}; };
export default function (opts) { export default function(opts) {
const visitor = {}; const visitor = {};
visitor.JSXNamespacedName = function (path) { visitor.JSXNamespacedName = function(path) {
throw path.buildCodeFrameError("Namespace tags are not supported. ReactJSX is not XML."); throw path.buildCodeFrameError(
"Namespace tags are not supported. ReactJSX is not XML.",
);
}; };
visitor.JSXElement = { visitor.JSXElement = {
@ -45,7 +47,7 @@ export default function (opts) {
} else if (t.isJSXMemberExpression(node)) { } else if (t.isJSXMemberExpression(node)) {
return t.memberExpression( return t.memberExpression(
convertJSXIdentifier(node.object, node), convertJSXIdentifier(node.object, node),
convertJSXIdentifier(node.property, node) convertJSXIdentifier(node.property, node),
); );
} }
@ -127,7 +129,6 @@ export default function (opts) {
return []; return [];
} }
/** /**
* The logic for this is quite terse. It's because we need to * The logic for this is quite terse. It's because we need to
* support spread elements. We loop over all attributes, * support spread elements. We loop over all attributes,
@ -141,8 +142,10 @@ export default function (opts) {
const useBuiltIns = file.opts.useBuiltIns || false; const useBuiltIns = file.opts.useBuiltIns || false;
if (typeof useBuiltIns !== "boolean") { if (typeof useBuiltIns !== "boolean") {
throw new Error("transform-react-jsx currently only accepts a boolean option for " + throw new Error(
"useBuiltIns (defaults to false)"); "transform-react-jsx currently only accepts a boolean option for " +
"useBuiltIns (defaults to false)",
);
} }
while (attribs.length) { while (attribs.length) {
@ -166,9 +169,9 @@ export default function (opts) {
objs.unshift(t.objectExpression([])); objs.unshift(t.objectExpression([]));
} }
const helper = useBuiltIns ? const helper = useBuiltIns
t.memberExpression(t.identifier("Object"), t.identifier("assign")) : ? t.memberExpression(t.identifier("Object"), t.identifier("assign"))
file.addHelper("extends"); : file.addHelper("extends");
// spread it // spread it
attribs = t.callExpression(helper, objs); attribs = t.callExpression(helper, objs);

View File

@ -18,15 +18,21 @@ const visitor = {
}, },
}; };
export default function (path: NodePath, scope = path.scope) { export default function(path: NodePath, scope = path.scope) {
const { node } = path; const { node } = path;
const container = t.functionExpression(null, [], node.body, node.generator, node.async); const container = t.functionExpression(
null,
[],
node.body,
node.generator,
node.async,
);
let callee = container; let callee = container;
let args = []; let args = [];
// todo: only hoist if necessary // todo: only hoist if necessary
hoistVariables(path, (id) => scope.push({ id })); hoistVariables(path, id => scope.push({ id }));
const state = { const state = {
foundThis: false, foundThis: false,

View File

@ -12,7 +12,13 @@ function toKind(node: Object) {
return "value"; return "value";
} }
export function push(mutatorMap: Object, node: Object, kind: string, file, scope?): Object { export function push(
mutatorMap: Object,
node: Object,
kind: string,
file,
scope?,
): Object {
const alias = t.toKeyAlias(node); const alias = t.toKeyAlias(node);
// //
@ -33,9 +39,11 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope
} }
if (node.decorators) { if (node.decorators) {
const decorators = map.decorators = map.decorators || t.arrayExpression([]); const decorators = (map.decorators =
map.decorators || t.arrayExpression([]));
decorators.elements = decorators.elements.concat( decorators.elements = decorators.elements.concat(
node.decorators.map((dec) => dec.expression).reverse()); node.decorators.map(dec => dec.expression).reverse(),
);
} }
if (map.value || map.initializer) { if (map.value || map.initializer) {
@ -45,14 +53,24 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope
let key, value; let key, value;
// save the key so we can possibly do function name inferences // save the key so we can possibly do function name inferences
if (t.isObjectProperty(node) || t.isObjectMethod(node) || t.isClassMethod(node)) { if (
t.isObjectProperty(node) ||
t.isObjectMethod(node) ||
t.isClassMethod(node)
) {
key = t.toComputedKey(node, node.key); key = t.toComputedKey(node, node.key);
} }
if (t.isObjectProperty(node) || t.isClassProperty(node)) { if (t.isObjectProperty(node) || t.isClassProperty(node)) {
value = node.value; value = node.value;
} else if (t.isObjectMethod(node) || t.isClassMethod(node)) { } else if (t.isObjectMethod(node) || t.isClassMethod(node)) {
value = t.functionExpression(null, node.params, node.body, node.generator, node.async); value = t.functionExpression(
null,
node.params,
node.body,
node.generator,
node.async,
);
value.returnType = node.returnType; value.returnType = node.returnType;
} }
@ -62,8 +80,12 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope
} }
// infer function name // infer function name
if (scope && t.isStringLiteral(key) && (kind === "value" || kind === "initializer") && if (
t.isFunctionExpression(value)) { scope &&
t.isStringLiteral(key) &&
(kind === "value" || kind === "initializer") &&
t.isFunctionExpression(value)
) {
value = nameFunction({ id: key, node: value, scope }); value = nameFunction({ id: key, node: value, scope });
} }
@ -90,7 +112,9 @@ export function toComputedObjectFromClass(obj: Object): Object {
for (let i = 0; i < obj.properties.length; i++) { for (let i = 0; i < obj.properties.length; i++) {
const prop = obj.properties[i]; const prop = obj.properties[i];
const val = prop.value; const val = prop.value;
val.properties.unshift(t.objectProperty(t.identifier("key"), t.toComputedKey(prop))); val.properties.unshift(
t.objectProperty(t.identifier("key"), t.toComputedKey(prop)),
);
objExpr.elements.push(val); objExpr.elements.push(val);
} }
@ -100,13 +124,13 @@ export function toComputedObjectFromClass(obj: Object): Object {
export function toClassObject(mutatorMap: Object): Object { export function toClassObject(mutatorMap: Object): Object {
const objExpr = t.objectExpression([]); const objExpr = t.objectExpression([]);
Object.keys(mutatorMap).forEach(function (mutatorMapKey) { Object.keys(mutatorMap).forEach(function(mutatorMapKey) {
const map = mutatorMap[mutatorMapKey]; const map = mutatorMap[mutatorMapKey];
const mapNode = t.objectExpression([]); const mapNode = t.objectExpression([]);
const propNode = t.objectProperty(map._key, mapNode, map._computed); const propNode = t.objectProperty(map._key, mapNode, map._computed);
Object.keys(map).forEach(function (key) { Object.keys(map).forEach(function(key) {
let node = map[key]; let node = map[key];
if (key[0] === "_") return; if (key[0] === "_") return;
@ -127,7 +151,7 @@ export function toClassObject(mutatorMap: Object): Object {
} }
export function toDefineObject(mutatorMap: Object): Object { export function toDefineObject(mutatorMap: Object): Object {
Object.keys(mutatorMap).forEach(function (key) { Object.keys(mutatorMap).forEach(function(key) {
const map = mutatorMap[key]; const map = mutatorMap[key];
if (map.value) map.writable = t.booleanLiteral(true); if (map.value) map.writable = t.booleanLiteral(true);
map.configurable = t.booleanLiteral(true); map.configurable = t.booleanLiteral(true);

View File

@ -20,7 +20,7 @@ function getObjRef(node, nodes, file, scope) {
} else if (t.isMemberExpression(node)) { } else if (t.isMemberExpression(node)) {
ref = node.object; ref = node.object;
if (t.isSuper(ref) || t.isIdentifier(ref) && scope.hasBinding(ref.name)) { if (t.isSuper(ref) || (t.isIdentifier(ref) && scope.hasBinding(ref.name))) {
// the object reference that we need to save is locally declared // the object reference that we need to save is locally declared
// so as per the previous comment we can be 100% sure evaluating // so as per the previous comment we can be 100% sure evaluating
// it multiple times will be safe // it multiple times will be safe
@ -32,9 +32,7 @@ function getObjRef(node, nodes, file, scope) {
} }
const temp = scope.generateUidIdentifierBasedOnNode(ref); const temp = scope.generateUidIdentifierBasedOnNode(ref);
nodes.push(t.variableDeclaration("var", [ nodes.push(t.variableDeclaration("var", [t.variableDeclarator(temp, ref)]));
t.variableDeclarator(temp, ref),
]));
return temp; return temp;
} }
@ -44,21 +42,19 @@ function getPropRef(node, nodes, file, scope) {
if (t.isLiteral(key) && t.isPureish(key)) return key; if (t.isLiteral(key) && t.isPureish(key)) return key;
const temp = scope.generateUidIdentifierBasedOnNode(prop); const temp = scope.generateUidIdentifierBasedOnNode(prop);
nodes.push(t.variableDeclaration("var", [ nodes.push(t.variableDeclaration("var", [t.variableDeclarator(temp, prop)]));
t.variableDeclarator(temp, prop),
]));
return temp; return temp;
} }
export default function ( export default function(
node: Object, node: Object,
nodes: Array<Object>, nodes: Array<Object>,
file, file,
scope: Scope, scope: Scope,
allowedSingleIdent?: boolean, allowedSingleIdent?: boolean,
): { ): {
uid: Object; uid: Object,
ref: Object; ref: Object,
} { } {
let obj; let obj;
if (t.isIdentifier(node) && allowedSingleIdent) { if (t.isIdentifier(node) && allowedSingleIdent) {

View File

@ -2,7 +2,7 @@ import bindifyDecorators from "babel-helper-bindify-decorators";
import type { NodePath } from "babel-traverse"; import type { NodePath } from "babel-traverse";
import * as t from "babel-types"; import * as t from "babel-types";
export default function (classPath) { export default function(classPath) {
classPath.assertClass(); classPath.assertClass();
const memoisedExpressions = []; const memoisedExpressions = [];
@ -44,6 +44,8 @@ export default function (classPath) {
} }
if (memoisedExpressions) { if (memoisedExpressions) {
classPath.insertBefore(memoisedExpressions.map((expr) => t.expressionStatement(expr))); classPath.insertBefore(
memoisedExpressions.map(expr => t.expressionStatement(expr)),
);
} }
} }

View File

@ -15,25 +15,25 @@ function humanize(val, noext) {
} }
type TestFile = { type TestFile = {
loc: string; loc: string,
code: string; code: string,
filename: string; filename: string,
}; };
type Test = { type Test = {
title: string; title: string,
disabled: boolean; disabled: boolean,
options: Object; options: Object,
exec: TestFile; exec: TestFile,
actual: TestFile; actual: TestFile,
expected: TestFile; expected: TestFile,
}; };
type Suite = { type Suite = {
options: Object; options: Object,
tests: Array<Test>; tests: Array<Test>,
title: string; title: string,
filename: string; filename: string,
}; };
function assertDirectory(loc) { function assertDirectory(loc) {
@ -50,7 +50,9 @@ function shouldIgnore(name, blacklist?: Array<string>) {
const ext = path.extname(name); const ext = path.extname(name);
const base = path.basename(name, ext); const base = path.basename(name, ext);
return name[0] === "." || ext === ".md" || base === "LICENSE" || base === "options"; return (
name[0] === "." || ext === ".md" || base === "LICENSE" || base === "options"
);
} }
export default function get(entryLoc): Array<Suite> { export default function get(entryLoc): Array<Suite> {
@ -133,7 +135,9 @@ export default function get(entryLoc): Array<Suite> {
const minimumVersion = semver.clean(taskOpts.minNodeVersion); const minimumVersion = semver.clean(taskOpts.minNodeVersion);
if (minimumVersion == null) { if (minimumVersion == null) {
throw new Error(`'minNodeVersion' has invalid semver format: ${taskOpts.minNodeVersion}`); throw new Error(
`'minNodeVersion' has invalid semver format: ${taskOpts.minNodeVersion}`,
);
} }
if (semver.lt(nodeVersion, minimumVersion)) { if (semver.lt(nodeVersion, minimumVersion)) {

View File

@ -56,7 +56,9 @@ function wrap(state, method, id, scope) {
// need to add a wrapper since we can't change the references // need to add a wrapper since we can't change the references
let build = buildPropertyMethodAssignmentWrapper; let build = buildPropertyMethodAssignmentWrapper;
if (method.generator) build = buildGeneratorPropertyMethodAssignmentWrapper; if (method.generator) {
build = buildGeneratorPropertyMethodAssignmentWrapper;
}
const template = build({ const template = build({
FUNCTION: method, FUNCTION: method,
FUNCTION_ID: id, FUNCTION_ID: id,
@ -125,12 +127,15 @@ function visit(node, name, scope) {
return state; return state;
} }
export default function ({ node, parent, scope, id }) { export default function({ node, parent, scope, id }) {
// has an `id` so we don't need to infer one // has an `id` so we don't need to infer one
if (node.id) return; if (node.id) return;
if ((t.isObjectProperty(parent) || t.isObjectMethod(parent, { kind: "method" })) && if (
(!parent.computed || t.isLiteral(parent.key))) { (t.isObjectProperty(parent) ||
t.isObjectMethod(parent, { kind: "method" })) &&
(!parent.computed || t.isLiteral(parent.key))
) {
// { foo() {} }; // { foo() {} };
id = parent.key; id = parent.key;
} else if (t.isVariableDeclarator(parent)) { } else if (t.isVariableDeclarator(parent)) {
@ -139,7 +144,11 @@ export default function ({ node, parent, scope, id }) {
if (t.isIdentifier(id)) { if (t.isIdentifier(id)) {
const binding = scope.parent.getBinding(id.name); const binding = scope.parent.getBinding(id.name);
if (binding && binding.constant && scope.getBinding(id.name) === binding) { if (
binding &&
binding.constant &&
scope.getBinding(id.name) === binding
) {
// always going to reference this method // always going to reference this method
node.id = id; node.id = id;
node.id[t.NOT_LOCAL_BINDING] = true; node.id[t.NOT_LOCAL_BINDING] = true;

View File

@ -1,6 +1,6 @@
import * as t from "babel-types"; import * as t from "babel-types";
export default function (node): number { export default function(node): number {
const params: Array<Object> = node.params; const params: Array<Object> = node.params;
for (let i = 0; i < params.length; i++) { for (let i = 0; i < params.length; i++) {
const param = params[i]; const param = params[i];

View File

@ -21,9 +21,11 @@ const visitor = {
firstId = declar.node.id; firstId = declar.node.id;
if (declar.node.init) { if (declar.node.init) {
nodes.push(t.expressionStatement( nodes.push(
t.assignmentExpression("=", declar.node.id, declar.node.init) t.expressionStatement(
)); t.assignmentExpression("=", declar.node.id, declar.node.init),
),
);
} }
for (const name in declar.getBindingIdentifiers()) { for (const name in declar.getBindingIdentifiers()) {
@ -40,6 +42,6 @@ const visitor = {
}, },
}; };
export default function (path, emit: Function, kind: "var" | "let" = "var") { export default function(path, emit: Function, kind: "var" | "let" = "var") {
path.traverse(visitor, { kind, emit }); path.traverse(visitor, { kind, emit });
} }

View File

@ -1,17 +1,20 @@
import * as t from "babel-types"; import * as t from "babel-types";
export default function (callee, thisNode, args) { export default function(callee, thisNode, args) {
if (args.length === 1 && t.isSpreadElement(args[0]) && if (
t.isIdentifier(args[0].argument, { name: "arguments" })) { args.length === 1 &&
t.isSpreadElement(args[0]) &&
t.isIdentifier(args[0].argument, { name: "arguments" })
) {
// eg. super(...arguments); // eg. super(...arguments);
return t.callExpression( return t.callExpression(t.memberExpression(callee, t.identifier("apply")), [
t.memberExpression(callee, t.identifier("apply")), thisNode,
[thisNode, args[0].argument] args[0].argument,
); ]);
} else { } else {
return t.callExpression( return t.callExpression(t.memberExpression(callee, t.identifier("call")), [
t.memberExpression(callee, t.identifier("call")), thisNode,
[thisNode, ...args] ...args,
); ]);
} }
} }

View File

@ -1,7 +1,7 @@
import testRunner from "babel-helper-transform-fixture-test-runner"; import testRunner from "babel-helper-transform-fixture-test-runner";
import path from "path"; import path from "path";
export default function (loc) { export default function(loc) {
const name = path.basename(path.dirname(loc)); const name = path.basename(path.dirname(loc));
testRunner(loc + "/fixtures", name); testRunner(loc + "/fixtures", name);
} }

View File

@ -48,13 +48,17 @@ const forAwaitVisitor = {
const callee = path.node.callee; const callee = path.node.callee;
// if no await wrapping is being applied, unwrap the call expression // if no await wrapping is being applied, unwrap the call expression
if (t.isIdentifier(callee) && callee.name === "AWAIT" && !replacements.AWAIT) { if (
t.isIdentifier(callee) &&
callee.name === "AWAIT" &&
!replacements.AWAIT
) {
path.replaceWith(path.node.arguments[0]); path.replaceWith(path.node.arguments[0]);
} }
}, },
}; };
export default function (path, helpers) { export default function(path, helpers) {
const { node, scope, parent } = path; const { node, scope, parent } = path;
const stepKey = scope.generateUidIdentifier("step"); const stepKey = scope.generateUidIdentifier("step");
@ -64,7 +68,9 @@ export default function (path, helpers) {
if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) { if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) {
// for await (i of test), for await ({ i } of test) // for await (i of test), for await ({ i } of test)
declar = t.expressionStatement(t.assignmentExpression("=", left, stepValue)); declar = t.expressionStatement(
t.assignmentExpression("=", left, stepValue),
);
} else if (t.isVariableDeclaration(left)) { } else if (t.isVariableDeclaration(left)) {
// for await (let i of test) // for await (let i of test)
declar = t.variableDeclaration(left.kind, [ declar = t.variableDeclaration(left.kind, [
@ -76,7 +82,9 @@ export default function (path, helpers) {
traverse(template, forAwaitVisitor, null, { traverse(template, forAwaitVisitor, null, {
ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"), ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"),
ITERATOR_COMPLETION: scope.generateUidIdentifier("iteratorNormalCompletion"), ITERATOR_COMPLETION: scope.generateUidIdentifier(
"iteratorNormalCompletion",
),
ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"), ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"),
ITERATOR_KEY: scope.generateUidIdentifier("iterator"), ITERATOR_KEY: scope.generateUidIdentifier("iterator"),
GET_ITERATOR: helpers.getAsyncIterator, GET_ITERATOR: helpers.getAsyncIterator,

View File

@ -70,7 +70,6 @@ const awaitVisitor = {
path.replaceWithMultiple(build.node); path.replaceWithMultiple(build.node);
} }
}, },
}; };
function classOrObjectMethod(path: NodePath, callId: Object) { function classOrObjectMethod(path: NodePath, callId: Object) {
@ -79,12 +78,16 @@ function classOrObjectMethod(path: NodePath, callId: Object) {
node.async = false; node.async = false;
const container = t.functionExpression(null, [], t.blockStatement(body.body), true); const container = t.functionExpression(
null,
[],
t.blockStatement(body.body),
true,
);
body.body = [ body.body = [
t.returnStatement(t.callExpression( t.returnStatement(
t.callExpression(callId, [container]), t.callExpression(t.callExpression(callId, [container]), []),
[] ),
)),
]; ];
// Regardless of whether or not the wrapped function is a an async method // Regardless of whether or not the wrapped function is a an async method
@ -92,7 +95,9 @@ function classOrObjectMethod(path: NodePath, callId: Object) {
node.generator = false; node.generator = false;
// Unwrap the wrapper IIFE's environment so super and this and such still work. // Unwrap the wrapper IIFE's environment so super and this and such still work.
path.get("body.body.0.argument.callee.arguments.0").unwrapFunctionEnvironment(); path
.get("body.body.0.argument.callee.arguments.0")
.unwrapFunctionEnvironment();
} }
function plainFunction(path: NodePath, callId: Object) { function plainFunction(path: NodePath, callId: Object) {
@ -121,25 +126,29 @@ function plainFunction(path: NodePath, callId: Object) {
NAME: asyncFnId || null, NAME: asyncFnId || null,
REF: path.scope.generateUidIdentifier("ref"), REF: path.scope.generateUidIdentifier("ref"),
FUNCTION: built, FUNCTION: built,
PARAMS: node.params.reduce((acc, param) => { PARAMS: node.params.reduce(
acc.done = acc.done || t.isAssignmentPattern(param) || t.isRestElement(param); (acc, param) => {
acc.done =
acc.done || t.isAssignmentPattern(param) || t.isRestElement(param);
if (!acc.done) { if (!acc.done) {
acc.params.push(path.scope.generateUidIdentifier("x")); acc.params.push(path.scope.generateUidIdentifier("x"));
} }
return acc; return acc;
}, { },
{
params: [], params: [],
done: false, done: false,
}).params, },
).params,
}).expression; }).expression;
if (isDeclaration) { if (isDeclaration) {
const declar = t.variableDeclaration("let", [ const declar = t.variableDeclaration("let", [
t.variableDeclarator( t.variableDeclarator(
t.identifier(asyncFnId.name), t.identifier(asyncFnId.name),
t.callExpression(container, []) t.callExpression(container, []),
), ),
]); ]);
declar._blockHoist = true; declar._blockHoist = true;
@ -149,14 +158,12 @@ function plainFunction(path: NodePath, callId: Object) {
// the identifier into an expressionStatement // the identifier into an expressionStatement
path.parentPath.insertBefore(declar); path.parentPath.insertBefore(declar);
path.parentPath.replaceWith( path.parentPath.replaceWith(
t.exportNamedDeclaration(null, t.exportNamedDeclaration(null, [
[
t.exportSpecifier( t.exportSpecifier(
t.identifier(asyncFnId.name), t.identifier(asyncFnId.name),
t.identifier("default") t.identifier("default"),
), ),
] ]),
)
); );
return; return;
} }
@ -182,7 +189,7 @@ function plainFunction(path: NodePath, callId: Object) {
} }
} }
export default function (path: NodePath, file: Object, helpers: Object) { export default function(path: NodePath, file: Object, helpers: Object) {
if (!helpers) { if (!helpers) {
// bc for 6.15 and earlier // bc for 6.15 and earlier
helpers = { wrapAsync: file }; helpers = { wrapAsync: file };

View File

@ -30,16 +30,19 @@ function isMemberExpressionSuper(node) {
* CLASS.prototype.__proto__ || Object.getPrototypeOf(CLASS.prototype) * CLASS.prototype.__proto__ || Object.getPrototypeOf(CLASS.prototype)
*/ */
function getPrototypeOfExpression(objectRef, isStatic) { function getPrototypeOfExpression(objectRef, isStatic) {
const targetRef = isStatic ? objectRef : t.memberExpression(objectRef, t.identifier("prototype")); const targetRef = isStatic
? objectRef
: t.memberExpression(objectRef, t.identifier("prototype"));
return t.logicalExpression( return t.logicalExpression(
"||", "||",
t.memberExpression(targetRef, t.identifier("__proto__")), t.memberExpression(targetRef, t.identifier("__proto__")),
t.callExpression( t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")), t.memberExpression(
[ t.identifier("Object"),
targetRef, t.identifier("getPrototypeOf"),
] ),
[targetRef],
), ),
); );
} }
@ -119,14 +122,14 @@ export default class ReplaceSupers {
scope: Scope; scope: Scope;
file; file;
opts: { opts: {
forceSuperMemoisation: boolean; forceSuperMemoisation: boolean,
getObjetRef: Function; getObjetRef: Function,
methodPath: NodePath; methodPath: NodePath,
methodNode: Object; methodNode: Object,
superRef: Object; superRef: Object,
isStatic: boolean; isStatic: boolean,
isLoose: boolean; isLoose: boolean,
file: any; file: any,
}; };
getObjectRef() { getObjectRef() {
@ -143,16 +146,17 @@ export default class ReplaceSupers {
* *
*/ */
setSuperProperty(property: Object, value: Object, isComputed: boolean): Object { setSuperProperty(
return t.callExpression( property: Object,
this.file.addHelper("set"), value: Object,
[ isComputed: boolean,
): Object {
return t.callExpression(this.file.addHelper("set"), [
getPrototypeOfExpression(this.getObjectRef(), this.isStatic), getPrototypeOfExpression(this.getObjectRef(), this.isStatic),
isComputed ? property : t.stringLiteral(property.name), isComputed ? property : t.stringLiteral(property.name),
value, value,
t.thisExpression(), t.thisExpression(),
] ]);
);
} }
/** /**
@ -165,14 +169,11 @@ export default class ReplaceSupers {
*/ */
getSuperProperty(property: Object, isComputed: boolean): Object { getSuperProperty(property: Object, isComputed: boolean): Object {
return t.callExpression( return t.callExpression(this.file.addHelper("get"), [
this.file.addHelper("get"),
[
getPrototypeOfExpression(this.getObjectRef(), this.isStatic), getPrototypeOfExpression(this.getObjectRef(), this.isStatic),
isComputed ? property : t.stringLiteral(property.name), isComputed ? property : t.stringLiteral(property.name),
t.thisExpression(), t.thisExpression(),
] ]);
);
} }
replace() { replace() {
@ -214,16 +215,23 @@ export default class ReplaceSupers {
specHandleAssignmentExpression(ref, path, node) { specHandleAssignmentExpression(ref, path, node) {
if (node.operator === "=") { if (node.operator === "=") {
// super.name = "val"; -> _set(Object.getPrototypeOf(objectRef.prototype), "name", this); // super.name = "val"; -> _set(Object.getPrototypeOf(objectRef.prototype), "name", this);
return this.setSuperProperty(node.left.property, node.right, node.left.computed); return this.setSuperProperty(
node.left.property,
node.right,
node.left.computed,
);
} else { } else {
// super.age += 2; -> let _ref = super.age; super.age = _ref + 2; // super.age += 2; -> let _ref = super.age; super.age = _ref + 2;
ref = ref || path.scope.generateUidIdentifier("ref"); ref = ref || path.scope.generateUidIdentifier("ref");
return [ return [
t.variableDeclaration("var", [ t.variableDeclaration("var", [t.variableDeclarator(ref, node.left)]),
t.variableDeclarator(ref, node.left), t.expressionStatement(
]), t.assignmentExpression(
t.expressionStatement(t.assignmentExpression("=", node.left, "=",
t.binaryExpression(node.operator.slice(0, -1), ref, node.right))), node.left,
t.binaryExpression(node.operator.slice(0, -1), ref, node.right),
),
),
]; ];
} }
} }
@ -258,8 +266,15 @@ export default class ReplaceSupers {
// _get(Object.getPrototypeOf(objectRef.prototype), "name", this); // _get(Object.getPrototypeOf(objectRef.prototype), "name", this);
property = node.property; property = node.property;
computed = node.computed; computed = node.computed;
} else if (t.isUpdateExpression(node) && isMemberExpressionSuper(node.argument)) { } else if (
const binary = t.assignmentExpression(node.operator[0] + "=", node.argument, t.numericLiteral(1)); t.isUpdateExpression(node) &&
isMemberExpressionSuper(node.argument)
) {
const binary = t.assignmentExpression(
node.operator[0] + "=",
node.argument,
t.numericLiteral(1),
);
if (node.prefix) { if (node.prefix) {
// ++super.foo; // ++super.foo;
// to // to
@ -270,9 +285,14 @@ export default class ReplaceSupers {
// to // to
// let _ref = super.foo; super.foo = _ref + 1; // let _ref = super.foo; super.foo = _ref + 1;
const ref = path.scope.generateUidIdentifier("ref"); const ref = path.scope.generateUidIdentifier("ref");
return this.specHandleAssignmentExpression(ref, path, binary).concat(t.expressionStatement(ref)); return this.specHandleAssignmentExpression(ref, path, binary).concat(
t.expressionStatement(ref),
);
} }
} else if (t.isAssignmentExpression(node) && isMemberExpressionSuper(node.left)) { } else if (
t.isAssignmentExpression(node) &&
isMemberExpressionSuper(node.left)
) {
return this.specHandleAssignmentExpression(null, path, node); return this.specHandleAssignmentExpression(null, path, node);
} }

View File

@ -4,13 +4,9 @@ export function assertNoOwnProperties(obj) {
assert.equal(Object.getOwnPropertyNames(obj).length, 0); assert.equal(Object.getOwnPropertyNames(obj).length, 0);
} }
export function assertHasOwnProperty() { export function assertHasOwnProperty() {}
} export function assertLacksOwnProperty() {}
export function assertLacksOwnProperty() {
}
export function multiline(arr) { export function multiline(arr) {
return arr.join("\n"); return arr.join("\n");

View File

@ -38,7 +38,9 @@ runCodeInTestContext(buildExternalHelpers());
* This allows us to run our unittests * This allows us to run our unittests
*/ */
function runModuleInTestContext(id: string, relativeFilename: string) { function runModuleInTestContext(id: string, relativeFilename: string) {
const filename = resolve.sync(id, { basedir: path.dirname(relativeFilename) }); const filename = resolve.sync(id, {
basedir: path.dirname(relativeFilename),
});
// Expose Node-internal modules if the tests want them. Note, this will not execute inside // Expose Node-internal modules if the tests want them. Note, this will not execute inside
// the context's global scope. // the context's global scope.
@ -46,20 +48,22 @@ function runModuleInTestContext(id: string, relativeFilename: string) {
if (moduleCache[filename]) return moduleCache[filename].exports; if (moduleCache[filename]) return moduleCache[filename].exports;
const module = moduleCache[filename] = { const module = (moduleCache[filename] = {
id: filename, id: filename,
exports: {}, exports: {},
}; });
const dirname = path.dirname(filename); const dirname = path.dirname(filename);
const req = (id) => runModuleInTestContext(id, filename); const req = id => runModuleInTestContext(id, filename);
const src = fs.readFileSync(filename, "utf8"); const src = fs.readFileSync(filename, "utf8");
const code = `(function (exports, require, module, __filename, __dirname) {${src}\n});`; const code = `(function (exports, require, module, __filename, __dirname) {${src}\n});`;
vm.runInContext(code, testContext, { vm
.runInContext(code, testContext, {
filename, filename,
displayErrors: true, displayErrors: true,
}).call(module.exports, module.exports, req, module, filename, dirname); })
.call(module.exports, module.exports, req, module, filename, dirname);
return module.exports; return module.exports;
} }
@ -69,10 +73,13 @@ function runModuleInTestContext(id: string, relativeFilename: string) {
* *
* Exposed for unit tests, not for use as an API. * Exposed for unit tests, not for use as an API.
*/ */
export function runCodeInTestContext(code: string, opts: {filename?: string} = {}) { export function runCodeInTestContext(
code: string,
opts: { filename?: string } = {},
) {
const filename = opts.filename || null; const filename = opts.filename || null;
const dirname = filename ? path.dirname(filename) : null; const dirname = filename ? path.dirname(filename) : null;
const req = filename ? ((id) => runModuleInTestContext(id, filename)) : null; const req = filename ? id => runModuleInTestContext(id, filename) : null;
const module = { const module = {
id: filename, id: filename,
@ -90,21 +97,21 @@ export function runCodeInTestContext(code: string, opts: {filename?: string} = {
} }
function wrapPackagesArray(type, names, optionsDir) { function wrapPackagesArray(type, names, optionsDir) {
return (names || []).map(function (val) { return (names || []).map(function(val) {
if (typeof val === "string") val = [val]; if (typeof val === "string") val = [val];
// relative path (outside of monorepo) // relative path (outside of monorepo)
if (val[0][0] === ".") { if (val[0][0] === ".") {
if (!optionsDir) { if (!optionsDir) {
throw new Error("Please provide an options.json in test dir when using a " + throw new Error(
"relative plugin path."); "Please provide an options.json in test dir when using a " +
"relative plugin path.",
);
} }
val[0] = path.resolve(optionsDir, val[0]); val[0] = path.resolve(optionsDir, val[0]);
} } else {
// check node_modules/babel-x-y // check node_modules/babel-x-y
else {
val[0] = __dirname + "/../../babel-" + type + "-" + val[0]; val[0] = __dirname + "/../../babel-" + type + "-" + val[0];
} }
@ -120,15 +127,25 @@ function run(task) {
const optionsDir = task.optionsDir; const optionsDir = task.optionsDir;
function getOpts(self) { function getOpts(self) {
const newOpts = merge({ const newOpts = merge(
{
filename: self.loc, filename: self.loc,
}, opts); },
opts,
);
newOpts.plugins = wrapPackagesArray("plugin", newOpts.plugins, optionsDir); newOpts.plugins = wrapPackagesArray("plugin", newOpts.plugins, optionsDir);
newOpts.presets = wrapPackagesArray("preset", newOpts.presets, optionsDir).map(function (val) { newOpts.presets = wrapPackagesArray(
"preset",
newOpts.presets,
optionsDir,
).map(function(val) {
if (val.length > 2) { if (val.length > 2) {
throw new Error("Unexpected extra options " + JSON.stringify(val.slice(2)) + throw new Error(
" passed to preset."); "Unexpected extra options " +
JSON.stringify(val.slice(2)) +
" passed to preset.",
);
} }
return val; return val;
@ -160,14 +177,19 @@ function run(task) {
if (!execCode || actualCode) { if (!execCode || actualCode) {
result = babel.transform(actualCode, getOpts(actual)); result = babel.transform(actualCode, getOpts(actual));
if ( if (
!expect.code && result.code && !opts.throws && fs.statSync(path.dirname(expect.loc)).isDirectory() && !expect.code &&
result.code &&
!opts.throws &&
fs.statSync(path.dirname(expect.loc)).isDirectory() &&
!process.env.CI !process.env.CI
) { ) {
console.log(`New test file created: ${expect.loc}`); console.log(`New test file created: ${expect.loc}`);
fs.writeFileSync(expect.loc, result.code); fs.writeFileSync(expect.loc, result.code);
} else { } else {
actualCode = result.code.trim(); actualCode = result.code.trim();
chai.expect(actualCode).to.be.equal(expectCode, actual.loc + " !== " + expect.loc); chai
.expect(actualCode)
.to.be.equal(expectCode, actual.loc + " !== " + expect.loc);
} }
} }
@ -178,11 +200,13 @@ function run(task) {
if (task.sourceMappings) { if (task.sourceMappings) {
const consumer = new sourceMap.SourceMapConsumer(result.map); const consumer = new sourceMap.SourceMapConsumer(result.map);
task.sourceMappings.forEach(function (mapping) { task.sourceMappings.forEach(function(mapping) {
const actual = mapping.original; const actual = mapping.original;
const expect = consumer.originalPositionFor(mapping.generated); const expect = consumer.originalPositionFor(mapping.generated);
chai.expect({ line: expect.line, column: expect.column }).to.deep.equal(actual); chai
.expect({ line: expect.line, column: expect.column })
.to.deep.equal(actual);
}); });
} }
@ -191,7 +215,7 @@ function run(task) {
} }
} }
export default function ( export default function(
fixturesLoc: string, fixturesLoc: string,
name: string, name: string,
suiteOpts = {}, suiteOpts = {},
@ -203,12 +227,19 @@ export default function (
for (const testSuite of suites) { for (const testSuite of suites) {
if (includes(suiteOpts.ignoreSuites, testSuite.title)) continue; if (includes(suiteOpts.ignoreSuites, testSuite.title)) continue;
describe(name + "/" + testSuite.title, function () { describe(name + "/" + testSuite.title, function() {
for (const task of testSuite.tests) { for (const task of testSuite.tests) {
if (includes(suiteOpts.ignoreTasks, task.title) || if (
includes(suiteOpts.ignoreTasks, testSuite.title + "/" + task.title)) continue; includes(suiteOpts.ignoreTasks, task.title) ||
includes(suiteOpts.ignoreTasks, testSuite.title + "/" + task.title)
) {
continue;
}
it(task.title, !task.disabled && function () { it(
task.title,
!task.disabled &&
function() {
function runTask() { function runTask() {
run(task); run(task);
} }
@ -232,8 +263,10 @@ export default function (
// the options object with useless options // the options object with useless options
delete task.options.throws; delete task.options.throws;
assert.throws(runTask, function (err) { assert.throws(runTask, function(err) {
return throwMsg === true || err.message.indexOf(throwMsg) >= 0; return (
throwMsg === true || err.message.indexOf(throwMsg) >= 0
);
}); });
} else { } else {
if (task.exec.code) { if (task.exec.code) {
@ -245,7 +278,8 @@ export default function (
runTask(); runTask();
} }
} }
}); },
);
} }
}); });
} }

View File

@ -359,7 +359,6 @@ helpers.get = template(`
}); });
`); `);
helpers.inherits = template(` helpers.inherits = template(`
(function (subClass, superClass) { (function (subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) { if (typeof superClass !== "function" && superClass !== null) {
@ -395,7 +394,6 @@ helpers.instanceof = template(`
}); });
`); `);
helpers.interopRequireDefault = template(` helpers.interopRequireDefault = template(`
(function (obj) { (function (obj) {
return obj && obj.__esModule ? obj : { default: obj }; return obj && obj.__esModule ? obj : { default: obj };

View File

@ -8,7 +8,7 @@ export function get(name) {
} }
export const list = Object.keys(helpers) export const list = Object.keys(helpers)
.map((name) => name.replace(/^_/, "")) .map(name => name.replace(/^_/, ""))
.filter((name) => name !== "__esModule"); .filter(name => name !== "__esModule");
export default get; export default get;

View File

@ -8,38 +8,55 @@ import * as util from "util";
*/ */
export const MESSAGES = { export const MESSAGES = {
tailCallReassignmentDeopt: "Function reference has been reassigned, so it will probably be dereferenced, therefore we can't optimise this with confidence", tailCallReassignmentDeopt:
"Function reference has been reassigned, so it will probably be dereferenced, therefore we can't optimise this with confidence",
classesIllegalBareSuper: "Illegal use of bare super", classesIllegalBareSuper: "Illegal use of bare super",
classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead", classesIllegalSuperCall:
"Direct super call is illegal in non-constructor, use super.$1() instead",
scopeDuplicateDeclaration: "Duplicate declaration $1", scopeDuplicateDeclaration: "Duplicate declaration $1",
settersNoRest: "Setters aren't allowed to have a rest", settersNoRest: "Setters aren't allowed to have a rest",
noAssignmentsInForHead: "No assignments allowed in for-in/of head", noAssignmentsInForHead: "No assignments allowed in for-in/of head",
expectedMemberExpressionOrIdentifier: "Expected type MemberExpression or Identifier", expectedMemberExpressionOrIdentifier:
invalidParentForThisNode: "We don't know how to handle this node within the current parent - please open an issue", "Expected type MemberExpression or Identifier",
invalidParentForThisNode:
"We don't know how to handle this node within the current parent - please open an issue",
readOnly: "$1 is read-only", readOnly: "$1 is read-only",
unknownForHead: "Unknown node type $1 in ForStatement", unknownForHead: "Unknown node type $1 in ForStatement",
didYouMean: "Did you mean $1?", didYouMean: "Did you mean $1?",
codeGeneratorDeopt: "Note: The code generator has deoptimised the styling of $1 as it exceeds the max of $2.", codeGeneratorDeopt:
missingTemplatesDirectory: "no templates directory - this is most likely the result of a broken `npm publish`. Please report to https://github.com/babel/babel/issues", "Note: The code generator has deoptimised the styling of $1 as it exceeds the max of $2.",
missingTemplatesDirectory:
"no templates directory - this is most likely the result of a broken `npm publish`. Please report to https://github.com/babel/babel/issues",
unsupportedOutputType: "Unsupported output type $1", unsupportedOutputType: "Unsupported output type $1",
illegalMethodName: "Illegal method name $1", illegalMethodName: "Illegal method name $1",
lostTrackNodePath: "We lost track of this node's position, likely because the AST was directly manipulated", lostTrackNodePath:
"We lost track of this node's position, likely because the AST was directly manipulated",
modulesIllegalExportName: "Illegal export $1", modulesIllegalExportName: "Illegal export $1",
modulesDuplicateDeclarations: "Duplicate module declarations with the same source but in different scopes", modulesDuplicateDeclarations:
"Duplicate module declarations with the same source but in different scopes",
undeclaredVariable: "Reference to undeclared variable $1", undeclaredVariable: "Reference to undeclared variable $1",
undeclaredVariableType: "Referencing a type alias outside of a type annotation", undeclaredVariableType:
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?", "Referencing a type alias outside of a type annotation",
undeclaredVariableSuggestion:
"Reference to undeclared variable $1 - did you mean $2?",
traverseNeedsParent: "You must pass a scope and parentPath unless traversing a Program/File. Instead of that you tried to traverse a $1 node without passing scope and parentPath.", traverseNeedsParent:
traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?", "You must pass a scope and parentPath unless traversing a Program/File. Instead of that you tried to traverse a $1 node without passing scope and parentPath.",
traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2", traverseVerifyRootFunction:
traverseVerifyNodeType: "You gave us a visitor for the node type $1 but it's not a valid type", "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?",
traverseVerifyVisitorProperty:
"You passed `traverse()` a visitor object with the property $1 that has the invalid property $2",
traverseVerifyNodeType:
"You gave us a visitor for the node type $1 but it's not a valid type",
pluginNotObject: "Plugin $2 specified in $1 was expected to return an object when invoked but returned $3", pluginNotObject:
pluginNotFunction: "Plugin $2 specified in $1 was expected to return a function but returned $3", "Plugin $2 specified in $1 was expected to return an object when invoked but returned $3",
pluginUnknown: "Unknown plugin $1 specified in $2 at $3, attempted to resolve relative to $4", pluginNotFunction:
"Plugin $2 specified in $1 was expected to return a function but returned $3",
pluginUnknown:
"Unknown plugin $1 specified in $2 at $3, attempted to resolve relative to $4",
pluginInvalidProperty: "Plugin $1 provided an invalid property of $2", pluginInvalidProperty: "Plugin $1 provided an invalid property of $2",
}; };
@ -55,7 +72,7 @@ export function get(key: string, ...args: Array<any>): string {
args = parseArgs(args); args = parseArgs(args);
// replace $0 placeholders with args // replace $0 placeholders with args
return msg.replace(/\$(\d+)/g, function (str, i) { return msg.replace(/\$(\d+)/g, function(str, i) {
return args[i - 1]; return args[i - 1];
}); });
} }
@ -65,7 +82,7 @@ export function get(key: string, ...args: Array<any>): string {
*/ */
export function parseArgs(args: Array<any>): Array<string> { export function parseArgs(args: Array<any>): Array<string> {
return args.map(function (val) { return args.map(function(val) {
if (val != null && val.inspect) { if (val != null && val.inspect) {
return val.inspect(); return val.inspect();
} else { } else {

View File

@ -1,4 +1,4 @@
export default function ({ messages }) { export default function({ messages }) {
return { return {
visitor: { visitor: {
Scope({ scope }) { Scope({ scope }) {

View File

@ -1,4 +1,4 @@
export default function ({ types: t }) { export default function({ types: t }) {
return { return {
pre(file) { pre(file) {
file.set("helpersNamespace", t.identifier("babelHelpers")); file.set("helpersNamespace", t.identifier("babelHelpers"));

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("asyncFunctions"); parserOpts.plugins.push("asyncFunctions");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("asyncGenerators"); parserOpts.plugins.push("asyncGenerators");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("classProperties"); parserOpts.plugins.push("classProperties");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("decorators"); parserOpts.plugins.push("decorators");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("doExpressions"); parserOpts.plugins.push("doExpressions");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("dynamicImport"); parserOpts.plugins.push("dynamicImport");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("exponentiationOperator"); parserOpts.plugins.push("exponentiationOperator");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("exportExtensions"); parserOpts.plugins.push("exportExtensions");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("flow"); parserOpts.plugins.push("flow");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("functionBind"); parserOpts.plugins.push("functionBind");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("functionSent"); parserOpts.plugins.push("functionSent");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("jsx"); parserOpts.plugins.push("jsx");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("numericSeparator"); parserOpts.plugins.push("numericSeparator");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("objectRestSpread"); parserOpts.plugins.push("objectRestSpread");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("optionalChaining"); parserOpts.plugins.push("optionalChaining");

View File

@ -1,4 +1,4 @@
export default function () { export default function() {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("trailingFunctionCommas"); parserOpts.plugins.push("trailingFunctionCommas");

View File

@ -1,6 +1,6 @@
import asyncSyntaxPlugin from "babel-plugin-syntax-async-functions"; import asyncSyntaxPlugin from "babel-plugin-syntax-async-functions";
export default function () { export default function() {
return { return {
inherits: asyncSyntaxPlugin, inherits: asyncSyntaxPlugin,
}; };

View File

@ -1,7 +1,7 @@
import remapAsyncToGenerator from "babel-helper-remap-async-to-generator"; import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";
import syntaxAsyncGenerators from "babel-plugin-syntax-async-generators"; import syntaxAsyncGenerators from "babel-plugin-syntax-async-generators";
export default function ({ types: t }) { export default function({ types: t }) {
const yieldStarVisitor = { const yieldStarVisitor = {
Function(path) { Function(path) {
path.skip(); path.skip();
@ -12,7 +12,10 @@ export default function ({ types: t }) {
const callee = state.addHelper("asyncGeneratorDelegate"); const callee = state.addHelper("asyncGeneratorDelegate");
node.argument = t.callExpression(callee, [ node.argument = t.callExpression(callee, [
t.callExpression(state.addHelper("asyncIterator"), [node.argument]), t.callExpression(state.addHelper("asyncIterator"), [node.argument]),
t.memberExpression(state.addHelper("asyncGenerator"), t.identifier("await")), t.memberExpression(
state.addHelper("asyncGenerator"),
t.identifier("await"),
),
]); ]);
}, },
}; };
@ -27,9 +30,13 @@ export default function ({ types: t }) {
remapAsyncToGenerator(path, state.file, { remapAsyncToGenerator(path, state.file, {
wrapAsync: t.memberExpression( wrapAsync: t.memberExpression(
state.addHelper("asyncGenerator"), t.identifier("wrap")), state.addHelper("asyncGenerator"),
t.identifier("wrap"),
),
wrapAwait: t.memberExpression( wrapAwait: t.memberExpression(
state.addHelper("asyncGenerator"), t.identifier("await")), state.addHelper("asyncGenerator"),
t.identifier("await"),
),
}); });
}, },
}, },

View File

@ -1,7 +1,7 @@
import remapAsyncToGenerator from "babel-helper-remap-async-to-generator"; import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";
import syntaxAsyncFunctions from "babel-plugin-syntax-async-functions"; import syntaxAsyncFunctions from "babel-plugin-syntax-async-functions";
export default function () { export default function() {
return { return {
inherits: syntaxAsyncFunctions, inherits: syntaxAsyncFunctions,

View File

@ -1,7 +1,7 @@
import remapAsyncToGenerator from "babel-helper-remap-async-to-generator"; import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";
import syntaxAsyncFunctions from "babel-plugin-syntax-async-functions"; import syntaxAsyncFunctions from "babel-plugin-syntax-async-functions";
export default function () { export default function() {
return { return {
inherits: syntaxAsyncFunctions, inherits: syntaxAsyncFunctions,

View File

@ -2,7 +2,7 @@ import nameFunction from "babel-helper-function-name";
import template from "babel-template"; import template from "babel-template";
import syntaxClassProperties from "babel-plugin-syntax-class-properties"; import syntaxClassProperties from "babel-plugin-syntax-class-properties";
export default function ({ types: t }) { export default function({ types: t }) {
const findBareSupers = { const findBareSupers = {
Super(path) { Super(path) {
if (path.parentPath.isCallExpression({ callee: path.node })) { if (path.parentPath.isCallExpression({ callee: path.node })) {
@ -29,14 +29,20 @@ export default function ({ types: t }) {
}); });
`); `);
const buildClassPropertySpec = (ref, { key, value, computed }) => buildObjectDefineProperty({ const buildClassPropertySpec = (ref, { key, value, computed }) =>
buildObjectDefineProperty({
REF: ref, REF: ref,
KEY: (t.isIdentifier(key) && !computed) ? t.stringLiteral(key.name) : key, KEY: t.isIdentifier(key) && !computed ? t.stringLiteral(key.name) : key,
VALUE: value ? value : t.identifier("undefined"), VALUE: value ? value : t.identifier("undefined"),
}); });
const buildClassPropertyNonSpec = (ref, { key, value, computed }) => t.expressionStatement( const buildClassPropertyNonSpec = (ref, { key, value, computed }) =>
t.assignmentExpression("=", t.memberExpression(ref, key, computed || t.isLiteral(key)), value) t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(ref, key, computed || t.isLiteral(key)),
value,
),
); );
return { return {
@ -44,8 +50,9 @@ export default function ({ types: t }) {
visitor: { visitor: {
Class(path, state) { Class(path, state) {
const buildClassProperty = state.opts.spec ? buildClassPropertySpec : const buildClassProperty = state.opts.spec
buildClassPropertyNonSpec; ? buildClassPropertySpec
: buildClassPropertyNonSpec;
const isDerived = !!path.node.superClass; const isDerived = !!path.node.superClass;
let constructor; let constructor;
const props = []; const props = [];
@ -67,7 +74,8 @@ export default function ({ types: t }) {
if (path.isClassExpression() || !path.node.id) { if (path.isClassExpression() || !path.node.id) {
nameFunction(path); nameFunction(path);
ref = path.scope.generateUidIdentifier("class"); ref = path.scope.generateUidIdentifier("class");
} else { // path.isClassDeclaration() && path.node.id } else {
// path.isClassDeclaration() && path.node.id
ref = path.node.id; ref = path.node.id;
} }
@ -93,17 +101,20 @@ export default function ({ types: t }) {
if (instanceBody.length) { if (instanceBody.length) {
if (!constructor) { if (!constructor) {
const newConstructor = t.classMethod("constructor", t.identifier("constructor"), [], const newConstructor = t.classMethod(
t.blockStatement([])); "constructor",
t.identifier("constructor"),
[],
t.blockStatement([]),
);
if (isDerived) { if (isDerived) {
newConstructor.params = [t.restElement(t.identifier("args"))]; newConstructor.params = [t.restElement(t.identifier("args"))];
newConstructor.body.body.push( newConstructor.body.body.push(
t.returnStatement( t.returnStatement(
t.callExpression( t.callExpression(t.super(), [
t.super(), t.spreadElement(t.identifier("args")),
[t.spreadElement(t.identifier("args"))] ]),
) ),
)
); );
} }
[constructor] = body.unshiftContainer("body", newConstructor); [constructor] = body.unshiftContainer("body", newConstructor);
@ -120,19 +131,29 @@ export default function ({ types: t }) {
} }
if (collisionState.collision) { if (collisionState.collision) {
const initialisePropsRef = path.scope.generateUidIdentifier("initialiseProps"); const initialisePropsRef = path.scope.generateUidIdentifier(
"initialiseProps",
);
nodes.push(t.variableDeclaration("var", [ nodes.push(
t.variableDeclaration("var", [
t.variableDeclarator( t.variableDeclarator(
initialisePropsRef, initialisePropsRef,
t.functionExpression(null, [], t.blockStatement(instanceBody)) t.functionExpression(
null,
[],
t.blockStatement(instanceBody),
), ),
])); ),
]),
);
instanceBody = [ instanceBody = [
t.expressionStatement( t.expressionStatement(
t.callExpression(t.memberExpression(initialisePropsRef, t.identifier("call")), [ t.callExpression(
t.thisExpression()]) t.memberExpression(initialisePropsRef, t.identifier("call")),
[t.thisExpression()],
),
), ),
]; ];
} }
@ -159,7 +180,8 @@ export default function ({ types: t }) {
if (path.isClassExpression()) { if (path.isClassExpression()) {
path.scope.push({ id: ref }); path.scope.push({ id: ref });
path.replaceWith(t.assignmentExpression("=", ref, path.node)); path.replaceWith(t.assignmentExpression("=", ref, path.node));
} else { // path.isClassDeclaration() } else {
// path.isClassDeclaration()
if (!path.node.id) { if (!path.node.id) {
path.node.id = ref; path.node.id = ref;
} }
@ -177,7 +199,7 @@ export default function ({ types: t }) {
const body = classExp.get("body"); const body = classExp.get("body");
const members = body.get("body"); const members = body.get("body");
if (members.some((member) => member.isClassProperty())) { if (members.some(member => member.isClassProperty())) {
path.ensureBlock(); path.ensureBlock();
} }
}, },

View File

@ -15,7 +15,6 @@ const buildGetDescriptor = template(`
Object.getOwnPropertyDescriptor(TARGET, PROPERTY); Object.getOwnPropertyDescriptor(TARGET, PROPERTY);
`); `);
const buildGetObjectInitializer = template(` const buildGetObjectInitializer = template(`
(TEMP = Object.getOwnPropertyDescriptor(TARGET, PROPERTY), (TEMP = TEMP ? TEMP.value : undefined), { (TEMP = Object.getOwnPropertyDescriptor(TARGET, PROPERTY), (TEMP = TEMP ? TEMP.value : undefined), {
enumerable: true, enumerable: true,
@ -88,7 +87,9 @@ export default function({ types: t }) {
*/ */
function ensureApplyDecoratedDescriptorHelper(path, state) { function ensureApplyDecoratedDescriptorHelper(path, state) {
if (!state.applyDecoratedDescriptor) { if (!state.applyDecoratedDescriptor) {
state.applyDecoratedDescriptor = path.scope.generateUidIdentifier("applyDecoratedDescriptor"); state.applyDecoratedDescriptor = path.scope.generateUidIdentifier(
"applyDecoratedDescriptor",
);
const helper = buildApplyDecoratedDescriptor({ const helper = buildApplyDecoratedDescriptor({
NAME: state.applyDecoratedDescriptor, NAME: state.applyDecoratedDescriptor,
}); });
@ -103,7 +104,9 @@ export default function({ types: t }) {
*/ */
function ensureInitializerDefineProp(path, state) { function ensureInitializerDefineProp(path, state) {
if (!state.initializerDefineProp) { if (!state.initializerDefineProp) {
state.initializerDefineProp = path.scope.generateUidIdentifier("initDefineProp"); state.initializerDefineProp = path.scope.generateUidIdentifier(
"initDefineProp",
);
const helper = buildInitializerDefineProperty({ const helper = buildInitializerDefineProperty({
NAME: state.initializerDefineProp, NAME: state.initializerDefineProp,
}); });
@ -119,7 +122,9 @@ export default function({ types: t }) {
*/ */
function ensureInitializerWarning(path, state) { function ensureInitializerWarning(path, state) {
if (!state.initializerWarningHelper) { if (!state.initializerWarningHelper) {
state.initializerWarningHelper = path.scope.generateUidIdentifier("initializerWarningHelper"); state.initializerWarningHelper = path.scope.generateUidIdentifier(
"initializerWarningHelper",
);
const helper = buildInitializerWarningHelper({ const helper = buildInitializerWarningHelper({
NAME: state.initializerWarningHelper, NAME: state.initializerWarningHelper,
}); });
@ -135,20 +140,29 @@ export default function({ types: t }) {
*/ */
function applyEnsureOrdering(path) { function applyEnsureOrdering(path) {
// TODO: This should probably also hoist computed properties. // TODO: This should probably also hoist computed properties.
const decorators = ( const decorators = (path.isClass()
path.isClass()
? [path].concat(path.get("body.body")) ? [path].concat(path.get("body.body"))
: path.get("properties") : path.get("properties")).reduce(
).reduce((acc, prop) => acc.concat(prop.node.decorators || []), []); (acc, prop) => acc.concat(prop.node.decorators || []),
[],
);
const identDecorators = decorators.filter((decorator) => !t.isIdentifier(decorator.expression)); const identDecorators = decorators.filter(
decorator => !t.isIdentifier(decorator.expression),
);
if (identDecorators.length === 0) return; if (identDecorators.length === 0) return;
return t.sequenceExpression(identDecorators.map((decorator) => { return t.sequenceExpression(
identDecorators
.map(decorator => {
const expression = decorator.expression; const expression = decorator.expression;
const id = decorator.expression = path.scope.generateDeclaredUidIdentifier("dec"); const id = (decorator.expression = path.scope.generateDeclaredUidIdentifier(
"dec",
));
return t.assignmentExpression("=", id, expression); return t.assignmentExpression("=", id, expression);
}).concat([path.node])); })
.concat([path.node]),
);
} }
/** /**
@ -164,7 +178,7 @@ export default function({ types: t }) {
const name = classPath.scope.generateDeclaredUidIdentifier("class"); const name = classPath.scope.generateDeclaredUidIdentifier("class");
return decorators return decorators
.map((dec) => dec.expression) .map(dec => dec.expression)
.reverse() .reverse()
.reduce(function(acc, decorator) { .reduce(function(acc, decorator) {
return buildClassDecorator({ return buildClassDecorator({
@ -207,7 +221,9 @@ export default function({ types: t }) {
* A helper to pull out property decorators into a sequence expression. * A helper to pull out property decorators into a sequence expression.
*/ */
function applyTargetDecorators(path, state, decoratedProps) { function applyTargetDecorators(path, state, decoratedProps) {
const name = path.scope.generateDeclaredUidIdentifier(path.isClass() ? "class" : "obj"); const name = path.scope.generateDeclaredUidIdentifier(
path.isClass() ? "class" : "obj",
);
const exprs = decoratedProps.reduce(function(acc, node) { const exprs = decoratedProps.reduce(function(acc, node) {
const decorators = node.decorators || []; const decorators = node.decorators || [];
@ -216,36 +232,58 @@ export default function({ types: t }) {
if (decorators.length === 0) return acc; if (decorators.length === 0) return acc;
if (node.computed) { if (node.computed) {
throw path.buildCodeFrameError("Computed method/property decorators are not yet supported."); throw path.buildCodeFrameError(
"Computed method/property decorators are not yet supported.",
);
} }
const property = t.isLiteral(node.key) ? node.key : t.stringLiteral(node.key.name); const property = t.isLiteral(node.key)
? node.key
: t.stringLiteral(node.key.name);
const target = (path.isClass() && !node.static) ? buildClassPrototype({ const target =
path.isClass() && !node.static
? buildClassPrototype({
CLASS_REF: name, CLASS_REF: name,
}).expression : name; }).expression
: name;
if (t.isClassProperty(node, { static: false })) { if (t.isClassProperty(node, { static: false })) {
const descriptor = path.scope.generateDeclaredUidIdentifier("descriptor"); const descriptor = path.scope.generateDeclaredUidIdentifier(
"descriptor",
const initializer = node.value ?
t.functionExpression(null, [], t.blockStatement([t.returnStatement(node.value)])) :
t.nullLiteral();
node.value = t.callExpression(
ensureInitializerWarning(path, state), [descriptor, t.thisExpression()]
); );
const initializer = node.value
? t.functionExpression(
null,
[],
t.blockStatement([t.returnStatement(node.value)]),
)
: t.nullLiteral();
node.value = t.callExpression(ensureInitializerWarning(path, state), [
descriptor,
t.thisExpression(),
]);
acc = acc.concat([ acc = acc.concat([
t.assignmentExpression( t.assignmentExpression(
"=", descriptor, t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [ "=",
descriptor,
t.callExpression(
ensureApplyDecoratedDescriptorHelper(path, state),
[
target, target,
property, property,
t.arrayExpression(decorators.map((dec) => dec.expression)), t.arrayExpression(decorators.map(dec => dec.expression)),
t.objectExpression([ t.objectExpression([
t.objectProperty(t.identifier("enumerable"), t.booleanLiteral(true)), t.objectProperty(
t.identifier("enumerable"),
t.booleanLiteral(true),
),
t.objectProperty(t.identifier("initializer"), initializer), t.objectProperty(t.identifier("initializer"), initializer),
]), ]),
]) ],
),
), ),
]); ]);
} else { } else {
@ -253,21 +291,20 @@ export default function({ types: t }) {
t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [ t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [
target, target,
property, property,
t.arrayExpression(decorators.map((dec) => dec.expression)), t.arrayExpression(decorators.map(dec => dec.expression)),
(
t.isObjectProperty(node) || t.isObjectProperty(node) ||
t.isClassProperty(node, { static: true })) ? t.isClassProperty(node, { static: true })
buildGetObjectInitializer({ ? buildGetObjectInitializer({
TEMP: path.scope.generateDeclaredUidIdentifier("init"), TEMP: path.scope.generateDeclaredUidIdentifier("init"),
TARGET: target, TARGET: target,
PROPERTY: property, PROPERTY: property,
}).expression : buildGetDescriptor({ }).expression
: buildGetDescriptor({
TARGET: target, TARGET: target,
PROPERTY: property, PROPERTY: property,
} }).expression,
).expression,
target, target,
]) ]),
); );
} }
@ -289,35 +326,42 @@ export default function({ types: t }) {
if (!path.get("declaration").isClassDeclaration()) return; if (!path.get("declaration").isClassDeclaration()) return;
const { node } = path; const { node } = path;
const ref = node.declaration.id || path.scope.generateUidIdentifier("default"); const ref =
node.declaration.id || path.scope.generateUidIdentifier("default");
node.declaration.id = ref; node.declaration.id = ref;
// Split the class declaration and the export into two separate statements. // Split the class declaration and the export into two separate statements.
path.replaceWith(node.declaration); path.replaceWith(node.declaration);
path.insertAfter(t.exportNamedDeclaration(null, [t.exportSpecifier(ref, t.identifier("default"))])); path.insertAfter(
t.exportNamedDeclaration(null, [
t.exportSpecifier(ref, t.identifier("default")),
]),
);
}, },
ClassDeclaration(path) { ClassDeclaration(path) {
const { node } = path; const { node } = path;
const ref = node.id || path.scope.generateUidIdentifier("class"); const ref = node.id || path.scope.generateUidIdentifier("class");
path.replaceWith(t.variableDeclaration("let", [ path.replaceWith(
t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)), t.variableDeclarator(ref, t.toExpression(node)),
])); ]),
);
}, },
ClassExpression(path, state) { ClassExpression(path, state) {
// Create a replacement for the class node if there is one. We do one pass to replace classes with // Create a replacement for the class node if there is one. We do one pass to replace classes with
// class decorators, and a second pass to process method decorators. // class decorators, and a second pass to process method decorators.
const decoratedClass = ( const decoratedClass =
applyEnsureOrdering(path) || applyEnsureOrdering(path) ||
applyClassDecorators(path, state) || applyClassDecorators(path, state) ||
applyMethodDecorators(path, state) applyMethodDecorators(path, state);
);
if (decoratedClass) path.replaceWith(decoratedClass); if (decoratedClass) path.replaceWith(decoratedClass);
}, },
ObjectExpression(path, state) { ObjectExpression(path, state) {
const decoratedObject = applyEnsureOrdering(path) || applyObjectDecorators(path, state); const decoratedObject =
applyEnsureOrdering(path) || applyObjectDecorators(path, state);
if (decoratedObject) path.replaceWith(decoratedObject); if (decoratedObject) path.replaceWith(decoratedObject);
}, },
@ -328,14 +372,22 @@ export default function({ types: t }) {
if (!path.get("left").isMemberExpression()) return; if (!path.get("left").isMemberExpression()) return;
if (!path.get("left.property").isIdentifier()) return; if (!path.get("left.property").isIdentifier()) return;
if (!path.get("right").isCallExpression()) return; if (!path.get("right").isCallExpression()) return;
if (!path.get("right.callee").isIdentifier({ name: state.initializerWarningHelper.name })) return; if (
!path
.get("right.callee")
.isIdentifier({ name: state.initializerWarningHelper.name })
) {
return;
}
path.replaceWith(t.callExpression(ensureInitializerDefineProp(path, state), [ path.replaceWith(
t.callExpression(ensureInitializerDefineProp(path, state), [
path.get("left.object").node, path.get("left.object").node,
t.stringLiteral(path.get("left.property").node.name), t.stringLiteral(path.get("left.property").node.name),
path.get("right.arguments")[0].node, path.get("right.arguments")[0].node,
path.get("right.arguments")[1].node, path.get("right.arguments")[1].node,
])); ]),
);
}, },
}, },
}; };

View File

@ -1,6 +1,6 @@
import syntaxDoExpressions from "babel-plugin-syntax-do-expressions"; import syntaxDoExpressions from "babel-plugin-syntax-do-expressions";
export default function () { export default function() {
return { return {
inherits: syntaxDoExpressions, inherits: syntaxDoExpressions,

View File

@ -2,10 +2,13 @@
import type NodePath from "babel-traverse"; import type NodePath from "babel-traverse";
export default function () { export default function() {
return { return {
visitor: { visitor: {
ArrowFunctionExpression(path: NodePath<BabelNodeArrowFunctionExpression>, state: Object) { ArrowFunctionExpression(
path: NodePath<BabelNodeArrowFunctionExpression>,
state: Object,
) {
// In some conversion cases, it may have already been converted to a function while this callback // In some conversion cases, it may have already been converted to a function while this callback
// was queued up. // was queued up.
if (!path.isArrowFunctionExpression()) return; if (!path.isArrowFunctionExpression()) return;

View File

@ -1,4 +1,4 @@
export default function ({ types: t }) { export default function({ types: t }) {
function statementList(key, path) { function statementList(key, path) {
const paths: Array = path.get(key); const paths: Array = path.get(key);
@ -24,7 +24,10 @@ export default function ({ types: t }) {
visitor: { visitor: {
BlockStatement(path) { BlockStatement(path) {
const { node, parent } = path; const { node, parent } = path;
if (t.isFunction(parent, { body: node }) || t.isExportDeclaration(parent)) { if (
t.isFunction(parent, { body: node }) ||
t.isExportDeclaration(parent)
) {
return; return;
} }

View File

@ -8,7 +8,7 @@ import values from "lodash/values";
import extend from "lodash/extend"; import extend from "lodash/extend";
import template from "babel-template"; import template from "babel-template";
export default function () { export default function() {
return { return {
visitor: { visitor: {
VariableDeclaration(path, file) { VariableDeclaration(path, file) {
@ -44,20 +44,38 @@ export default function () {
Loop(path, file) { Loop(path, file) {
const { node, parent, scope } = path; const { node, parent, scope } = path;
t.ensureBlock(node); t.ensureBlock(node);
const blockScoping = new BlockScoping(path, path.get("body"), parent, scope, file); const blockScoping = new BlockScoping(
path,
path.get("body"),
parent,
scope,
file,
);
const replace = blockScoping.run(); const replace = blockScoping.run();
if (replace) path.replaceWith(replace); if (replace) path.replaceWith(replace);
}, },
CatchClause(path, file) { CatchClause(path, file) {
const { parent, scope } = path; const { parent, scope } = path;
const blockScoping = new BlockScoping(null, path.get("body"), parent, scope, file); const blockScoping = new BlockScoping(
null,
path.get("body"),
parent,
scope,
file,
);
blockScoping.run(); blockScoping.run();
}, },
"BlockStatement|SwitchStatement|Program"(path, file) { "BlockStatement|SwitchStatement|Program"(path, file) {
if (!ignoreBlock(path)) { if (!ignoreBlock(path)) {
const blockScoping = new BlockScoping(null, path, path.parent, path.scope, file); const blockScoping = new BlockScoping(
null,
path,
path.parent,
path.scope,
file,
);
blockScoping.run(); blockScoping.run();
} }
}, },
@ -80,7 +98,13 @@ function isBlockScoped(node) {
return true; return true;
} }
function convertBlockScopedToVar(path, node, parent, scope, moveBindingsToParent = false) { function convertBlockScopedToVar(
path,
node,
parent,
scope,
moveBindingsToParent = false,
) {
if (!node) { if (!node) {
node = path.node; node = path.node;
} }
@ -111,7 +135,8 @@ function isVar(node) {
return t.isVariableDeclaration(node, { kind: "var" }) && !isBlockScoped(node); return t.isVariableDeclaration(node, { kind: "var" }) && !isBlockScoped(node);
} }
const letReferenceBlockVisitor = traverse.visitors.merge([{ const letReferenceBlockVisitor = traverse.visitors.merge([
{
Loop: { Loop: {
enter(path, state) { enter(path, state) {
state.loopDepth++; state.loopDepth++;
@ -129,9 +154,12 @@ const letReferenceBlockVisitor = traverse.visitors.merge([{
} }
return path.skip(); return path.skip();
}, },
}, tdzVisitor]); },
tdzVisitor,
]);
const letReferenceFunctionVisitor = traverse.visitors.merge([{ const letReferenceFunctionVisitor = traverse.visitors.merge([
{
ReferencedIdentifier(path, state) { ReferencedIdentifier(path, state) {
const ref = state.letReferences[path.node.name]; const ref = state.letReferences[path.node.name];
@ -145,7 +173,9 @@ const letReferenceFunctionVisitor = traverse.visitors.merge([{
state.closurify = true; state.closurify = true;
}, },
}, tdzVisitor]); },
tdzVisitor,
]);
const hoistVarDeclarationsVisitor = { const hoistVarDeclarationsVisitor = {
enter(path, self) { enter(path, self) {
@ -166,7 +196,9 @@ const hoistVarDeclarationsVisitor = {
node.left = node.left.declarations[0].id; node.left = node.left.declarations[0].id;
} }
} else if (isVar(node, parent)) { } else if (isVar(node, parent)) {
path.replaceWithMultiple(self.pushDeclar(node).map((expr) => t.expressionStatement(expr))); path.replaceWithMultiple(
self.pushDeclar(node).map(expr => t.expressionStatement(expr)),
);
} else if (path.isFunction()) { } else if (path.isFunction()) {
return path.skip(); return path.skip();
} }
@ -184,7 +216,12 @@ const continuationVisitor = {
if (path.isAssignmentExpression() || path.isUpdateExpression()) { if (path.isAssignmentExpression() || path.isUpdateExpression()) {
const bindings = path.getBindingIdentifiers(); const bindings = path.getBindingIdentifiers();
for (const name in bindings) { for (const name in bindings) {
if (state.outsideReferences[name] !== path.scope.getBindingIdentifier(name)) continue; if (
state.outsideReferences[name] !==
path.scope.getBindingIdentifier(name)
) {
continue;
}
state.reassignments[name] = true; state.reassignments[name] = true;
} }
} }
@ -252,7 +289,10 @@ const loopVisitor = {
if (path.isReturnStatement()) { if (path.isReturnStatement()) {
state.hasReturn = true; state.hasReturn = true;
replace = t.objectExpression([ replace = t.objectExpression([
t.objectProperty(t.identifier("v"), node.argument || scope.buildUndefinedNode()), t.objectProperty(
t.identifier("v"),
node.argument || scope.buildUndefinedNode(),
),
]); ]);
} }
@ -266,7 +306,13 @@ const loopVisitor = {
}; };
class BlockScoping { class BlockScoping {
constructor(loopPath?: NodePath, blockPath: NodePath, parent: Object, scope: Scope, file: File) { constructor(
loopPath?: NodePath,
blockPath: NodePath,
parent: Object,
scope: Scope,
file: File,
) {
this.parent = parent; this.parent = parent;
this.scope = scope; this.scope = scope;
this.file = file; this.file = file;
@ -281,7 +327,8 @@ class BlockScoping {
if (loopPath) { if (loopPath) {
this.loopParent = loopPath.parent; this.loopParent = loopPath.parent;
this.loopLabel = t.isLabeledStatement(this.loopParent) && this.loopParent.label; this.loopLabel =
t.isLabeledStatement(this.loopParent) && this.loopParent.label;
this.loopPath = loopPath; this.loopPath = loopPath;
this.loop = loopPath.node; this.loop = loopPath.node;
} }
@ -360,11 +407,13 @@ class BlockScoping {
// The same identifier might have been bound separately in the block scope and // The same identifier might have been bound separately in the block scope and
// the enclosing scope (e.g. loop or catch statement), so we should handle both // the enclosing scope (e.g. loop or catch statement), so we should handle both
// individually // individually
if (scope.hasOwnBinding(key)) if (scope.hasOwnBinding(key)) {
{scope.rename(ref.name);} scope.rename(ref.name);
}
if (this.blockPath.scope.hasOwnBinding(key)) if (this.blockPath.scope.hasOwnBinding(key)) {
{this.blockPath.scope.rename(ref.name);} this.blockPath.scope.rename(ref.name);
}
} }
} }
} }
@ -373,7 +422,7 @@ class BlockScoping {
if (this.file.opts.throwIfClosureRequired) { if (this.file.opts.throwIfClosureRequired) {
throw this.blockPath.buildCodeFrameError( throw this.blockPath.buildCodeFrameError(
"Compiling let/const in this block would add a closure " + "Compiling let/const in this block would add a closure " +
"(throwIfClosureRequired)." "(throwIfClosureRequired).",
); );
} }
const block = this.block; const block = this.block;
@ -385,7 +434,10 @@ class BlockScoping {
for (const name in outsideRefs) { for (const name in outsideRefs) {
const id = outsideRefs[name]; const id = outsideRefs[name];
if (this.scope.hasGlobal(id.name) || this.scope.parentHasBinding(id.name)) { if (
this.scope.hasGlobal(id.name) ||
this.scope.parentHasBinding(id.name)
) {
delete outsideRefs[id.name]; delete outsideRefs[id.name];
delete this.letReferences[id.name]; delete this.letReferences[id.name];
@ -411,8 +463,11 @@ class BlockScoping {
const isSwitch = this.blockPath.isSwitchStatement(); const isSwitch = this.blockPath.isSwitchStatement();
// build the closure that we're going to wrap the block with, possible wrapping switch(){} // build the closure that we're going to wrap the block with, possible wrapping switch(){}
const fn = t.functionExpression(null, params, const fn = t.functionExpression(
t.blockStatement(isSwitch ? [block] : block.body)); null,
params,
t.blockStatement(isSwitch ? [block] : block.body),
);
// continuation // continuation
this.addContinuations(fn); this.addContinuations(fn);
@ -421,7 +476,12 @@ class BlockScoping {
let basePath = ".callee"; let basePath = ".callee";
// handle generators // handle generators
const hasYield = traverse.hasType(fn.body, this.scope, "YieldExpression", t.FUNCTION_TYPES); const hasYield = traverse.hasType(
fn.body,
this.scope,
"YieldExpression",
t.FUNCTION_TYPES,
);
if (hasYield) { if (hasYield) {
fn.generator = true; fn.generator = true;
call = t.yieldExpression(call, true); call = t.yieldExpression(call, true);
@ -429,7 +489,12 @@ class BlockScoping {
} }
// handlers async functions // handlers async functions
const hasAsync = traverse.hasType(fn.body, this.scope, "AwaitExpression", t.FUNCTION_TYPES); const hasAsync = traverse.hasType(
fn.body,
this.scope,
"AwaitExpression",
t.FUNCTION_TYPES,
);
if (hasAsync) { if (hasAsync) {
fn.async = true; fn.async = true;
call = t.awaitExpression(call); call = t.awaitExpression(call);
@ -441,9 +506,9 @@ class BlockScoping {
if (this.has.hasReturn || this.has.hasBreakContinue) { if (this.has.hasReturn || this.has.hasBreakContinue) {
const ret = this.scope.generateUidIdentifier("ret"); const ret = this.scope.generateUidIdentifier("ret");
this.body.push(t.variableDeclaration("var", [ this.body.push(
t.variableDeclarator(ret, call), t.variableDeclaration("var", [t.variableDeclarator(ret, call)]),
])); );
placeholderPath = "declarations.0.init" + basePath; placeholderPath = "declarations.0.init" + basePath;
index = this.body.length - 1; index = this.body.length - 1;
@ -471,9 +536,9 @@ class BlockScoping {
let fnPath; let fnPath;
if (this.loop) { if (this.loop) {
const ref = this.scope.generateUidIdentifier("loop"); const ref = this.scope.generateUidIdentifier("loop");
const p = this.loopPath.insertBefore(t.variableDeclaration("var", [ const p = this.loopPath.insertBefore(
t.variableDeclarator(ref, fn), t.variableDeclaration("var", [t.variableDeclarator(ref, fn)]),
])); );
placeholder.replaceWith(ref); placeholder.replaceWith(ref);
fnPath = p[0].get("declarations.0.init"); fnPath = p[0].get("declarations.0.init");
@ -512,7 +577,9 @@ class BlockScoping {
this.scope.rename(param.name, newParam.name, fn); this.scope.rename(param.name, newParam.name, fn);
// assign outer reference as it's been modified internally and needs to be retained // assign outer reference as it's been modified internally and needs to be retained
fn.body.body.push(t.expressionStatement(t.assignmentExpression("=", param, newParam))); fn.body.body.push(
t.expressionStatement(t.assignmentExpression("=", param, newParam)),
);
} }
} }
@ -531,7 +598,11 @@ class BlockScoping {
const addDeclarationsFromChild = (path, node) => { const addDeclarationsFromChild = (path, node) => {
node = node || path.node; node = node || path.node;
if (t.isClassDeclaration(node) || t.isFunctionDeclaration(node) || isBlockScoped(node)) { if (
t.isClassDeclaration(node) ||
t.isFunctionDeclaration(node) ||
isBlockScoped(node)
) {
if (isBlockScoped(node)) { if (isBlockScoped(node)) {
convertBlockScopedToVar(path, node, block, this.scope); convertBlockScopedToVar(path, node, block, this.scope);
} }
@ -585,7 +656,7 @@ class BlockScoping {
}; };
const loopOrFunctionParent = this.blockPath.find( const loopOrFunctionParent = this.blockPath.find(
(path) => path.isLoop() || path.isFunction() path => path.isLoop() || path.isFunction(),
); );
if (loopOrFunctionParent && loopOrFunctionParent.isLoop()) { if (loopOrFunctionParent && loopOrFunctionParent.isLoop()) {
// There is a loop ancestor closer than the closest function, so we // There is a loop ancestor closer than the closest function, so we
@ -686,18 +757,20 @@ class BlockScoping {
if (cases.length === 1) { if (cases.length === 1) {
const single = cases[0]; const single = cases[0];
body.push(t.ifStatement( body.push(
t.ifStatement(
t.binaryExpression("===", ret, single.test), t.binaryExpression("===", ret, single.test),
single.consequent[0] single.consequent[0],
)); ),
);
} else { } else {
if (this.loop) { if (this.loop) {
// https://github.com/babel/babel/issues/998 // https://github.com/babel/babel/issues/998
for (let i = 0; i < cases.length; i++) { for (let i = 0; i < cases.length; i++) {
const caseConsequent = cases[i].consequent[0]; const caseConsequent = cases[i].consequent[0];
if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) { if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) {
caseConsequent.label = this.loopLabel = this.loopLabel || caseConsequent.label = this.loopLabel =
this.scope.generateUidIdentifier("loop"); this.loopLabel || this.scope.generateUidIdentifier("loop");
} }
} }
} }

View File

@ -13,10 +13,11 @@ function getTDZStatus(refPath, bindingPath) {
} }
function buildTDZAssert(node, file) { function buildTDZAssert(node, file) {
return t.callExpression( return t.callExpression(file.addHelper("temporalRef"), [
file.addHelper("temporalRef"), node,
[node, t.stringLiteral(node.name), file.addHelper("temporalUndefined")] t.stringLiteral(node.name),
); file.addHelper("temporalUndefined"),
]);
} }
function isReference(node, scope, state) { function isReference(node, scope, state) {
@ -56,12 +57,18 @@ export const visitor = {
path.replaceWith(assert); path.replaceWith(assert);
} }
} else if (status === "outside") { } else if (status === "outside") {
path.replaceWith(t.throwStatement(t.inherits( path.replaceWith(
t.throwStatement(
t.inherits(
t.newExpression(t.identifier("ReferenceError"), [ t.newExpression(t.identifier("ReferenceError"), [
t.stringLiteral(`${node.name} is not defined - temporal dead zone`), t.stringLiteral(
`${node.name} is not defined - temporal dead zone`,
),
]), ]),
node node,
))); ),
),
);
} }
}, },

View File

@ -2,7 +2,7 @@ import LooseTransformer from "./loose";
import VanillaTransformer from "./vanilla"; import VanillaTransformer from "./vanilla";
import nameFunction from "babel-helper-function-name"; import nameFunction from "babel-helper-function-name";
export default function ({ types: t }) { export default function({ types: t }) {
// todo: investigate traversal requeueing // todo: investigate traversal requeueing
const VISITED = Symbol(); const VISITED = Symbol();
@ -12,15 +12,17 @@ export default function ({ types: t }) {
if (!path.get("declaration").isClassDeclaration()) return; if (!path.get("declaration").isClassDeclaration()) return;
const { node } = path; const { node } = path;
const ref = node.declaration.id || path.scope.generateUidIdentifier("class"); const ref =
node.declaration.id || path.scope.generateUidIdentifier("class");
node.declaration.id = ref; node.declaration.id = ref;
// Split the class declaration and the export into two separate statements. // Split the class declaration and the export into two separate statements.
path.replaceWith(node.declaration); path.replaceWith(node.declaration);
path.insertAfter(t.exportNamedDeclaration( path.insertAfter(
null, t.exportNamedDeclaration(null, [
[t.exportSpecifier(ref, t.identifier("default"))] t.exportSpecifier(ref, t.identifier("default")),
)); ]),
);
}, },
ClassDeclaration(path) { ClassDeclaration(path) {
@ -28,9 +30,11 @@ export default function ({ types: t }) {
const ref = node.id || path.scope.generateUidIdentifier("class"); const ref = node.id || path.scope.generateUidIdentifier("class");
path.replaceWith(t.variableDeclaration("let", [ path.replaceWith(
t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)), t.variableDeclarator(ref, t.toExpression(node)),
])); ]),
);
}, },
ClassExpression(path, state) { ClassExpression(path, state) {
@ -47,7 +51,10 @@ export default function ({ types: t }) {
path.replaceWith(new Constructor(path, state.file).run()); path.replaceWith(new Constructor(path, state.file).run());
if (path.isCallExpression() && path.get("callee").isArrowFunctionExpression()) { if (
path.isCallExpression() &&
path.get("callee").isArrowFunctionExpression()
) {
path.get("callee").arrowFunctionToExpression(); path.get("callee").arrowFunctionToExpression();
} }
}, },

Some files were not shown because too many files have changed in this diff Show More