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(
gutil.log(err.stack); plumber({
}, errorHandler: function(err) {
})) gutil.log(err.stack);
.pipe(newer({ },
dest: base, })
map: swapSrcWithLib, )
})) .pipe(
.pipe(through.obj(function (file, enc, callback) { newer({
gutil.log("Compiling", "'" + chalk.cyan(file.relative) + "'..."); dest: base,
callback(null, file); map: swapSrcWithLib,
})) })
)
.pipe(
through.obj(function(file, enc, callback) {
gutil.log("Compiling", "'" + chalk.cyan(file.relative) + "'...");
callback(null, file);
})
)
.pipe(babel()) .pipe(babel())
.pipe(through.obj(function (file, enc, callback) { .pipe(
// Passing 'file.relative' because newer() above uses a relative path and this keeps it consistent. through.obj(function(file, enc, callback) {
file.path = path.resolve(file.base, swapSrcWithLib(file.relative)); // Passing 'file.relative' because newer() above uses a relative path and this keeps it consistent.
callback(null, file); file.path = path.resolve(file.base, swapSrcWithLib(file.relative));
})) 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(
sourceFileName: slash(path.relative(dest + "/..", src)), src,
sourceMapTarget: path.basename(relative), defaults(
}, opts)); {
sourceFileName: slash(path.relative(dest + "/..", src)),
sourceMapTarget: path.basename(relative),
},
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:
line: mapping.originalLine, mapping.source == null
column: mapping.originalColumn, ? null
}, : {
line: mapping.originalLine,
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(
sourceFileName: "stdin", util.transform(
}, opts))); commander.filename,
code,
defaults(
{
sourceFileName: "stdin",
},
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(
sourceFileName: sourceFilename, filename,
}, opts)); defaults(
{
sourceFileName: sourceFilename,
},
opts,
),
);
if (!data) return; if (!data) return;
@ -142,33 +166,36 @@ 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
persistent: true, .watch(filenames, {
ignoreInitial: true, persistent: true,
awaitWriteFinish: { ignoreInitial: true,
stabilityThreshold: 50, awaitWriteFinish: {
pollInterval: 10, stabilityThreshold: 50,
}, pollInterval: 10,
}).on("all", function (type, filename) { },
if (!util.isCompilableExtension(filename, commander.extensions)) return; })
.on("all", function(type, filename) {
if (type === "add" || type === "change") { if (!util.isCompilableExtension(filename, commander.extensions)) {
util.log(type + " " + filename); return;
try {
walk();
} catch (err) {
console.error(err.stack);
} }
}
}); if (type === "add" || type === "change") {
util.log(type + " " + filename);
try {
walk();
} catch (err) {
console.error(err.stack);
}
}
});
} }
}; };

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,34 +193,39 @@ 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
const number = start + 1 + index; .slice(start, end)
const paddedNumber = ` ${number}`.slice(-numberMaxWidth); .map((line, index) => {
const gutter = ` ${paddedNumber} | `; const number = start + 1 + index;
const hasMarker = markerLines[number]; const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
if (hasMarker) { const gutter = ` ${paddedNumber} | `;
let markerLine = ""; const hasMarker = markerLines[number];
if (Array.isArray(hasMarker)) { if (hasMarker) {
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " "); let markerLine = "";
const numberOfMarkers = hasMarker[1] || 1; if (Array.isArray(hasMarker)) {
const markerSpacing = line
.slice(0, Math.max(hasMarker[0] - 1, 0))
.replace(/[^\t]/g, " ");
const numberOfMarkers = hasMarker[1] || 1;
markerLine = [ markerLine = [
"\n ", "\n ",
maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")), maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")),
markerSpacing, markerSpacing,
maybeHighlight(defs.marker, "^").repeat(numberOfMarkers), maybeHighlight(defs.marker, "^").repeat(numberOfMarkers),
].join("");
}
return [
maybeHighlight(defs.marker, ">"),
maybeHighlight(defs.gutter, gutter),
line,
markerLine,
].join(""); ].join("");
} else {
return ` ${maybeHighlight(defs.gutter, gutter)}${line}`;
} }
return [ })
maybeHighlight(defs.marker, ">"), .join("\n");
maybeHighlight(defs.gutter, gutter),
line,
markerLine,
].join("");
} else {
return ` ${maybeHighlight(defs.gutter, gutter)}${line}`;
}
}).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"); " 1 | class Foo {",
assert.equal(codeFrame(rawLines, 2, 16), [ "> 2 | constructor()",
" 1 | class Foo {", " | ^",
"> 2 | constructor()", " 3 | };",
" | ^", ].join("\n"),
" 3 | };", );
].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,18 +38,21 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 7, 2), [ assert.equal(
" 5 | * @param b Number", codeFrame(rawLines, 7, 2),
" 6 | * @returns Number", [
"> 7 | */", " 5 | * @param b Number",
" | ^", " 6 | * @returns Number",
" 8 | ", "> 7 | */",
" 9 | function sum(a, b) {", " | ^",
" 10 | return a + b", " 8 | ",
].join("\n")); " 9 | function sum(a, b) {",
" 10 | return a + b",
].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,43 +66,49 @@ describe("babel-code-frame", function () {
" return a + b", " return a + b",
"}", "}",
].join("\n"); ].join("\n");
assert.equal(codeFrame(rawLines, 6, 2), [ assert.equal(
" 4 | * @param a Number", codeFrame(rawLines, 6, 2),
" 5 | * @param b Number", [
"> 6 | * @returns Number", " 4 | * @param a Number",
" | ^", " 5 | * @param b Number",
" 7 | */", "> 6 | * @returns Number",
" 8 | ", " | ^",
" 9 | function sum(a, b) {", " 7 | */",
].join("\n")); " 8 | ",
" 9 | function sum(a, b) {",
].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(
" 1 | \tclass Foo {", codeFrame(rawLines, 2, 25),
"> 2 | \t \t\t constructor\t(\t)", [
" | \t \t\t \t \t ^", " 1 | \tclass Foo {",
" 3 | \t};", "> 2 | \t \t\t constructor\t(\t)",
].join("\n")); " | \t \t\t \t \t ^",
" 3 | \t};",
].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(
" 6 | * @returns Number", codeFrame(rawLines, 7, 2, { linesAbove: 1 }),
"> 7 | */", [
" | ^", " 6 | * @returns Number",
" 8 | ", "> 7 | */",
" 9 | function sum(a, b) {", " | ^",
" 10 | return a + b", " 8 | ",
].join("\n")); " 9 | function sum(a, b) {",
" 10 | return a + b",
].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(
" 5 | * @param b Number", codeFrame(rawLines, 7, 2, { linesBelow: 1 }),
" 6 | * @returns Number", [
"> 7 | */", " 5 | * @param b Number",
" | ^", " 6 | * @returns Number",
" 8 | ", "> 7 | */",
].join("\n")); " | ^",
" 8 | ",
].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 | "), [
marker(">") + gutter(" 3 | "), " " + gutter(" 2 | "),
" " + gutter(" 4 | "), marker(">") + gutter(" 3 | "),
].join("\n")) " " + gutter(" 4 | "),
].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"); " 1 | class Foo {",
assert.equal(codeFrameColumns(rawLines, { start: { line: 2, column: 16 } }), [ "> 2 | constructor()",
" 1 | class Foo {", " | ^",
"> 2 | constructor()", " 3 | };",
" | ^", ].join("\n"),
" 3 | };", );
].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,55 +66,53 @@ 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", [
"for various types of caching, using the first param of their handler functions:", "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:",
"module.exports = function(api) {", "",
" // The API exposes the following:", "module.exports = function(api) {",
"", " // The API exposes the following:",
" // Cache the returned value forever and don't call this function again.", "",
" api.cache(true);", " // Cache the returned value forever and don't call this function again.",
"", " api.cache(true);",
" // Don't cache at all. Not recommended because it will be very slow.", "",
" api.cache(false);", " // Don't cache at all. Not recommended because it will be very slow.",
"", " api.cache(false);",
" // Cached based on the value of some function. If this function returns a value different from", "",
" // a previously-encountered value, the plugins will re-evaluate.", " // Cached based on the value of some function. If this function returns a value different from",
" var env = api.cache(() => process.env.NODE_ENV);", " // a previously-encountered value, the plugins will re-evaluate.",
"", " var env = api.cache(() => process.env.NODE_ENV);",
" // 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.", " // If testing for a specific env, we recommend specifics to avoid instantiating a plugin for",
" var isProd = api.cache(() => process.env.NODE_ENV === \"production\");", " // any possible NODE_ENV value that might come up during plugin execution.",
"", ' var isProd = api.cache(() => process.env.NODE_ENV === "production");',
" // .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", " // .cache(fn) will perform a linear search though instances to find the matching plugin based",
" // previous instance whenever something changes, you may use:", " // based on previous instantiated plugins. If you want to recreate the plugin and discard the",
" var isProd = api.cache.invalidate(() => process.env.NODE_ENV === \"production\");", " // previous instance whenever something changes, you may use:",
"", ' var isProd = api.cache.invalidate(() => process.env.NODE_ENV === "production");',
" // Note, we also expose the following more-verbose versions of the above examples:", "",
" api.cache.forever(); // api.cache(true)", " // Note, we also expose the following more-verbose versions of the above examples:",
" api.cache.never(); // api.cache(false)", " api.cache.forever(); // api.cache(true)",
" api.cache.using(fn); // api.cache(fn)", " api.cache.never(); // api.cache(false)",
"", " api.cache.using(fn); // api.cache(fn)",
" // Return the value that will be cached.", "",
" return { };", " // Return the value that will be cached.",
"};", " 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,51 +141,80 @@ function makeCacheConfig(): { cache: CacheConfigurator, result: *, deactivate: (
active = false; active = false;
}; };
const cache: CacheConfigurator = Object.assign((function cacheFn(val) { const cache: CacheConfigurator = Object.assign(
if (typeof val === "boolean") { (function cacheFn(val) {
if (val) cache.forever(); if (typeof val === "boolean") {
else cache.never(); if (val) cache.forever();
return; else cache.never();
} return;
return cache.using(val);
}: any), ({
forever() {
if (!active) 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.configured = true;
},
never() {
if (!active) 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.configured = true;
},
using<T>(handler: () => T): T {
if (!active) throw new Error("Cannot change caching after evaluation has completed.");
if (result.never || result.forever) {
throw new Error("Caching has already been configured with .never or .forever()");
} }
result.configured = true;
const key = handler(); return cache.using(val);
pairs.push([ key, handler ]); }: any),
return key; ({
}, forever() {
invalidate<T>(handler: () => T): T { if (!active) {
if (!active) throw new Error("Cannot change caching after evaluation has completed."); throw new Error(
if (result.never || result.forever) { "Cannot change caching after evaluation has completed.",
throw new Error("Caching has already been configured with .never or .forever()"); );
} }
result.invalidate = true; if (result.never) {
result.configured = true; throw new Error("Caching has already been configured with .never()");
}
result.forever = true;
result.configured = true;
},
never() {
if (!active) {
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.configured = true;
},
using<T>(handler: () => T): T {
if (!active) {
throw new Error(
"Cannot change caching after evaluation has completed.",
);
}
if (result.never || result.forever) {
throw new Error(
"Caching has already been configured with .never or .forever()",
);
}
result.configured = true;
const key = handler(); const key = handler();
pairs.push([ key, handler ]); pairs.push([key, handler]);
return key; return key;
}, },
}: CacheConfiguratorObj)); invalidate<T>(handler: () => T): T {
if (!active) {
throw new Error(
"Cannot change caching after evaluation has completed.",
);
}
if (result.never || result.forever) {
throw new Error(
"Caching has already been configured with .never or .forever()",
);
}
result.invalidate = true;
result.configured = true;
const key = handler();
pairs.push([key, handler]);
return key;
},
}: 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 (
// foo -> babel-preset-foo name
.replace(isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE, `babel-${type}-`) // foo -> babel-preset-foo
// @babel/es2015 -> @babel/preset-es2015 .replace(
.replace(isPreset ? BABEL_PRESET_ORG_RE : BABEL_PLUGIN_ORG_RE, `$1${type}-`) isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE,
// @foo/mypreset -> @foo/babel-preset-mypreset `babel-${type}-`,
.replace(isPreset ? OTHER_PRESET_ORG_RE : OTHER_PLUGIN_ORG_RE, `$1babel-${type}-`) )
// module:mypreset -> mypreset // @babel/es2015 -> @babel/preset-es2015
.replace(EXACT_RE, ""); .replace(
isPreset ? BABEL_PRESET_ORG_RE : BABEL_PLUGIN_ORG_RE,
`$1${type}-`,
)
// @foo/mypreset -> @foo/babel-preset-mypreset
.replace(
isPreset ? OTHER_PRESET_ORG_RE : OTHER_PLUGIN_ORG_RE,
`$1babel-${type}-`,
)
// module:mypreset -> mypreset
.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", [
t.variableDeclarator(
namespace,
t.assignmentExpression("=", t.memberExpression(t.identifier("global"), namespace),
t.objectExpression([]))
), ),
])); ]);
body.push(
t.variableDeclaration("var", [
t.variableDeclarator(
namespace,
t.assignmentExpression(
"=",
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.variableDeclarator(namespace, t.identifier("global")), t.variableDeclaration("var", [
])); 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.variableDeclarator(namespace, t.objectExpression([])), t.variableDeclaration("var", [
])); 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,10 +335,13 @@ export default class File extends Store {
mergedGenerator.addMapping({ mergedGenerator.addMapping({
source: mapping.source, source: mapping.source,
original: mapping.source == null ? null : { original:
line: mapping.originalLine, mapping.source == null
column: mapping.originalColumn, ? null
}, : {
line: mapping.originalLine,
column: mapping.originalColumn,
},
generated: generatedPosition, generated: generatedPosition,
}); });
@ -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(
parserOpts: { newTransform(experimental).ast,
plugins: ["flow"], babel.transform(experimental, {
}, parserOpts: {
}).ast); plugins: ["flow"],
},
}).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(
parserOpts: { newTransformWithPlugins(experimental).ast,
plugins: ["flow"], babel.transform(experimental, {
}, parserOpts: {
}).ast); plugins: ["flow"],
},
}).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(
parserOpts: { newTransform(experimental).ast,
allowImportExportEverywhere: true, babel.transform(experimental, {
}, parserOpts: {
}).ast); allowImportExportEverywhere: true,
},
}).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;", {
visitor: { plugins: [
Program: function (path) { new Plugin({
visitor: {
Program: function(path) {
path.mark("category", "foobar");
},
},
}),
],
}).marked[0].message,
"foobar",
);
assert.equal(
babel.analyse(
"foobar;",
{},
{
Program: function(path) {
path.mark("category", "foobar"); path.mark("category", "foobar");
}, },
}, },
})], ).marked[0].message,
}).marked[0].message, "foobar"); "foobar",
assert.equal(babel.analyse("foobar;", {}, {
Program: function (path) {
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/
); );
}); });
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: [
name: "foobar", new Plugin({
visitor: { name: "foobar",
"Program|Identifier": function () { visitor: {
calledRaw++; "Program|Identifier": function() {
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) {", "",
" return y;", "var x = function x(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) {", "",
" return y;", "var x = function x(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,288 +336,345 @@ 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(
"argtwo;", result.code,
"argone;", [
"eleven;", "argtwo;",
"twelve;", "argone;",
"one;", "eleven;",
"two;", "twelve;",
"five;", "one;",
"six;", "two;",
"three;", "five;",
"four;", "six;",
"seventeen;", "three;",
"eighteen;", "four;",
"nineteen;", "seventeen;",
"twenty;", "eighteen;",
"thirteen;", "nineteen;",
"fourteen;", "twenty;",
"fifteen;", "thirteen;",
"sixteen;", "fourteen;",
"argfive;", "fifteen;",
"argsix;", "sixteen;",
"argthree;", "argfive;",
"argfour;", "argsix;",
"seven;", "argthree;",
"eight;", "argfour;",
"nine;", "seven;",
"ten;", "eight;",
].join("\n")); "nine;",
"ten;",
].join("\n"),
);
}); });
it("source map merging", function () { it("source map merging", function() {
const result = babel.transform([ const result = babel.transform(
/* eslint-disable max-len */ [
"function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }", /* eslint-disable max-len */
"", 'function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }',
"let Foo = function Foo() {", "",
" _classCallCheck(this, Foo);", "let Foo = function Foo() {",
"};", " _classCallCheck(this, Foo);",
"", "};",
"//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZG91dCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztJQUFNLEdBQUcsWUFBSCxHQUFHO3dCQUFILEdBQUciLCJmaWxlIjoidW5kZWZpbmVkIiwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRm9vIHt9XG4iXX0=", "",
/* eslint-enable max-len */ "//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZG91dCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztJQUFNLEdBQUcsWUFBSCxHQUFHO3dCQUFILEdBQUciLCJmaWxlIjoidW5kZWZpbmVkIiwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRm9vIHt9XG4iXX0=",
].join("\n"), { /* eslint-enable max-len */
sourceMap: true, ].join("\n"),
}); {
sourceMap: true,
},
);
assert.deepEqual([ assert.deepEqual(
"function _classCallCheck(instance, Constructor) {", [
" if (!(instance instanceof Constructor)) {", "function _classCallCheck(instance, Constructor) {",
" throw new TypeError(\"Cannot call a class as a function\");", " if (!(instance instanceof Constructor)) {",
" }", ' throw new TypeError("Cannot call a class as a function");',
"}", " }",
"", "}",
"let Foo = function Foo() {", "",
" _classCallCheck(this, Foo);", "let Foo = function 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(
line: 7, consumer.originalPositionFor({
column: 4, line: 7,
}), { column: 4,
name: null, }),
source: "stdout", {
line: 1, name: null,
column: 6, source: "stdout",
}); line: 1,
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: [
const t = babel.types; function(babel) {
return { const t = babel.types;
visitor: { return {
Program: function (path) { visitor: {
path.unshiftContainer("body", t.expressionStatement(t.identifier("start"))); Program: function(path) {
path.pushContainer("body", t.expressionStatement(t.identifier("end"))); path.unshiftContainer(
"body",
t.expressionStatement(t.identifier("start")),
);
path.pushContainer(
"body",
t.expressionStatement(t.identifier("end")),
);
},
}, },
}, };
}; },
}], ],
}).then(function (result) { }).then(function(result) {
assert.equal(result.code, assert.equal(
"/*before*/start;\n/*after*/class Foo {}\n/*before*/end;\n/*after*/"); 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", {
imported: "externalName", kind: "named",
local: "localName", imported: "externalName",
}], 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", {
local: "localName2", kind: "namespace",
}], 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", {
imported: "default", kind: "named",
local: "localName3", imported: "default",
}], 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", {
exported: "externalName1", kind: "external-namespace",
source: "external", exported: "externalName1",
}], 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", {
local: "externalName2", kind: "external",
exported: "externalName2", local: "externalName2",
source: "external", exported: "externalName2",
}], 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", {
local: "namedFunction", kind: "local",
exported: "namedFunction", local: "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", {
local: "foo", kind: "local",
exported: "foo", local: "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", {
local: "localName", kind: "local",
exported: "externalName3", local: "localName",
}], 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", {
local: "externalName4", kind: "external",
exported: "externalName4", local: "externalName4",
source: "external", exported: "externalName4",
}], 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", {
source: "external", kind: "external-all",
}], 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", {
local: "defaultFunction", kind: "local",
exported: "default", local: "defaultFunction",
}], 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,50 +521,49 @@ 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" +
const chain = buildConfigChain({ " package.json doesn't contain a `babel` field",
filename: fixture("json-pkg-config-no-babel", "src.js"), function() {
}); const chain = buildConfigChain({
filename: fixture("json-pkg-config-no-babel", "src.js"),
});
const expected = [ const expected = [
{ {
type: "options", type: "options",
options: { options: {
ignore: [ ignore: ["root-ignore"],
"root-ignore", },
], alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
dirname: fixture(),
}, },
alias: fixture(".babelignore"), {
loc: fixture(".babelignore"), type: "options",
dirname: fixture(), options: {
}, plugins: ["json"],
{ },
type: "options", alias: fixture("json-pkg-config-no-babel", ".babelrc"),
options: { loc: fixture("json-pkg-config-no-babel", ".babelrc"),
plugins: [ dirname: fixture("json-pkg-config-no-babel"),
"json",
],
}, },
alias: fixture("json-pkg-config-no-babel", ".babelrc"), {
loc: fixture("json-pkg-config-no-babel", ".babelrc"), type: "arguments",
dirname: fixture("json-pkg-config-no-babel"), options: {
}, filename: fixture("json-pkg-config-no-babel", "src.js"),
{ },
type: "arguments", alias: "base",
options: { loc: "base",
filename: fixture("json-pkg-config-no-babel", "src.js"), dirname: base(),
}, },
alias: "base", ];
loc: "base",
dirname: base(),
},
];
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() {
assert.throws(function() {
buildConfigChain({
filename: fixture("js-config-error", "src.js"),
});
}, /Error while loading config/);
}); });
it("js-config-error", 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-error", "src.js"), });
}); }, /Configuration should be an exported JavaScript object/);
},
/Error while loading config/
);
}); });
it("js-config-error2", 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-error2", "src.js"), });
}); }, /Configuration should be an exported JavaScript object/);
},
/Configuration should be an exported JavaScript object/
);
}); });
it("js-config-error3", function () { it("json-config-error", function() {
assert.throws( assert.throws(function() {
function () { buildConfigChain({
buildConfigChain({ filename: fixture("json-config-error", "src.js"),
filename: fixture("js-config-error3", "src.js"), });
}); }, /Error while parsing config/);
},
/Configuration should be an exported JavaScript object/
);
});
it("json-config-error", function () {
assert.throws(
function () {
buildConfigChain({
filename: fixture("json-config-error", "src.js"),
});
},
/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(
plugins: ["*"], parse(code, {
}), visitor); plugins: ["*"],
}),
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: [
"presets": [path.join(__dirname, "fixtures/option-manager/not-a-preset")], 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: [
visitor: { new Plugin({
FunctionDeclaration: function (path) { visitor: {
path.replaceWithSourceString("console.whatever()"); FunctionDeclaration: function(path) {
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: [
visitor: { new Plugin({
ArrowFunctionExpression: function (path) { visitor: {
path.get("body").replaceWith({ ArrowFunctionExpression: function(path) {
type: "BlockStatement", path.get("body").replaceWith({
body: [{ type: "BlockStatement",
type: "ReturnStatement", body: [
argument: { {
type: "BooleanLiteral", type: "ReturnStatement",
value: true, argument: {
}, type: "BooleanLiteral",
}], 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: [
visitor: { new Plugin({
ArrowFunctionExpression: function (path) { visitor: {
path.get("body").replaceWith({ ArrowFunctionExpression: function(path) {
type: "BooleanLiteral", path.get("body").replaceWith({
value: true, type: "BooleanLiteral",
}); 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: [
visitor: { new Plugin({
ForInStatement: function (path) { visitor: {
path.get("left").replaceWith({ ForInStatement: function(path) {
type: "VariableDeclaration", path.get("left").replaceWith({
kind: "var", type: "VariableDeclaration",
declarations: [{ kind: "var",
type: "VariableDeclarator", declarations: [
id: { {
type: "Identifier", type: "VariableDeclarator",
name: "KEY", id: {
}, type: "Identifier",
}], 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: [
visitor: { new Plugin({
ForInStatement: function (path) { visitor: {
path.get("left").replaceWith({ ForInStatement: function(path) {
type: "Identifier", path.get("left").replaceWith({
name: "KEY", type: "Identifier",
}); 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: [
visitor: { new Plugin({
ForStatement: function (path) { visitor: {
path.get("init").replaceWith({ ForStatement: function(path) {
type: "VariableDeclaration", path.get("init").replaceWith({
kind: "var", type: "VariableDeclaration",
declarations: [{ kind: "var",
type: "VariableDeclarator", declarations: [
id: { {
type: "Identifier", type: "VariableDeclarator",
name: "KEY", id: {
}, type: "Identifier",
}], 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: [
visitor: { new Plugin({
ForStatement: function (path) { visitor: {
path.get("init").replaceWith({ ForStatement: function(path) {
type: "Identifier", path.get("init").replaceWith({
name: "KEY", type: "Identifier",
}); 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 (
node.arguments.length === 0 && this.format.minified &&
!node.optional && node.arguments.length === 0 &&
!t.isCallExpression(parent, { callee: node }) && !node.optional &&
!t.isMemberExpression(parent) && !t.isCallExpression(parent, { callee: node }) &&
!t.isNewExpression(parent)) return; !t.isMemberExpression(parent) &&
!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,8 +171,10 @@ 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 =
!n.needsParens(node, parent); this.inForStatementInitCounter &&
node.operator === "in" &&
!n.needsParens(node, parent);
if (parens) { if (parens) {
this.token("("); this.token("(");

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;
} }
} }
@ -111,7 +114,7 @@ export function NumericLiteral(node: Object) {
const raw = this.getPossibleRaw(node); const raw = this.getPossibleRaw(node);
const value = node.value + ""; const value = node.value + "";
if (raw == null) { if (raw == null) {
this.number(value); // normalize this.number(value); // normalize
} else if (this.format.minified) { } else if (this.format.minified) {
this.number(raw.length < value.length ? raw : value); this.number(raw.length < value.length ? raw : value);
} else { } else {

View File

@ -61,17 +61,23 @@ 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 =
(value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0)); format.shouldPrintComment ||
(value =>
format.comments ||
(value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0));
} }
if (format.compact === "auto") { if (format.compact === "auto") {
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
const result = fn(node, parent, stack); ? function(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.isUnaryLike(parent) || t.isBinary(parent) ||
t.isCallExpression(parent) || t.isUnaryLike(parent) ||
t.isMemberExpression(parent) || t.isCallExpression(parent) ||
t.isNewExpression(parent) || t.isMemberExpression(parent) ||
(t.isConditionalExpression(parent) && node === parent.test); t.isNewExpression(parent) ||
(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.isCallExpression(parent, { callee: node }) || t.isMemberExpression(parent, { object: node }) ||
t.isNewExpression(parent, { callee: node }) || t.isCallExpression(parent, { callee: node }) ||
t.isBinaryExpression(parent, { operator: "**", left: node }); t.isNewExpression(parent, { callee: 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(
// Subtract one to account for the line force-added above. (this._whitespace ? this._whitespace.getNewlinesAfter(comment) : 0) +
(comment.type === "CommentLine" ? -1 : 0)); // Subtract one to account for the line force-added above.
(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,10 +83,13 @@ 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: line, line == null
column: column, ? undefined
}, : {
line: line,
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, {
sources: [ "a.js", "b.js" ], version: 3,
mappings: "AAAA,SAASA,EAAT,CAAaC,GAAb,EAAkB;AAAEC,UAAQC,GAAR,CAAYF,GAAZ;AAAmB;;ACAvCD,GAAG,OAAH", sources: ["a.js", "b.js"],
names: [ mappings:
"hi", "AAAA,SAASA,EAAT,CAAaC,GAAb,EAAkB;AAAEC,UAAQC,GAAR,CAAYF,GAAZ;AAAmB;;ACAvCD,GAAG,OAAH",
"msg", names: ["hi", "msg", "console", "log"],
"console", sourcesContent: [
"log", "function hi (msg) { console.log(msg); }\n",
], "hi('hello');\n",
sourcesContent: [ ],
"function hi (msg) { console.log(msg); }\n", },
"hi('hello');\n", "sourcemap was incorrectly generated",
],
}, "sourcemap was incorrectly generated");
chai.expect(generated.rawMappings).to.deep.equal([
{ name: undefined,
generated: { line: 1, column: 0 },
source: "a.js",
original: { line: 1, column: 0 } },
{ name: "hi",
generated: { line: 1, column: 9 },
source: "a.js",
original: { line: 1, column: 9 } },
{ name: undefined,
generated: { line: 1, column: 11 },
source: "a.js",
original: { line: 1, column: 0 } },
{ name: "msg",
generated: { line: 1, column: 12 },
source: "a.js",
original: { line: 1, column: 13 } },
{ name: undefined,
generated: { line: 1, column: 15 },
source: "a.js",
original: { line: 1, column: 0 } },
{ name: undefined,
generated: { line: 1, column: 17 },
source: "a.js",
original: { line: 1, column: 18 } },
{ name: "console",
generated: { line: 2, column: 0 },
source: "a.js",
original: { line: 1, column: 20 } },
{ name: "log",
generated: { line: 2, column: 10 },
source: "a.js",
original: { line: 1, column: 28 } },
{ name: undefined,
generated: { line: 2, column: 13 },
source: "a.js",
original: { line: 1, column: 20 } },
{ name: "msg",
generated: { line: 2, column: 14 },
source: "a.js",
original: { line: 1, column: 32 } },
{ name: undefined,
generated: { line: 2, column: 17 },
source: "a.js",
original: { line: 1, column: 20 } },
{ name: undefined,
generated: { line: 3, column: 0 },
source: "a.js",
original: { line: 1, column: 39 } },
{ name: "hi",
generated: { line: 5, column: 0 },
source: "b.js",
original: { line: 1, column: 0 } },
{ name: undefined,
generated: { line: 5, column: 3 },
source: "b.js",
original: { line: 1, column: 3 } },
{ name: undefined,
generated: { line: 5, column: 10 },
source: "b.js",
original: { line: 1, column: 0 } },
], "raw mappings were incorrectly generated");
chai.expect(generated.code).to.equal(
"function hi(msg) {\n console.log(msg);\n}\n\nhi('hello');",
"code was incorrectly generated"
); );
chai.expect(generated.rawMappings).to.deep.equal(
[
{
name: undefined,
generated: { line: 1, column: 0 },
source: "a.js",
original: { line: 1, column: 0 },
},
{
name: "hi",
generated: { line: 1, column: 9 },
source: "a.js",
original: { line: 1, column: 9 },
},
{
name: undefined,
generated: { line: 1, column: 11 },
source: "a.js",
original: { line: 1, column: 0 },
},
{
name: "msg",
generated: { line: 1, column: 12 },
source: "a.js",
original: { line: 1, column: 13 },
},
{
name: undefined,
generated: { line: 1, column: 15 },
source: "a.js",
original: { line: 1, column: 0 },
},
{
name: undefined,
generated: { line: 1, column: 17 },
source: "a.js",
original: { line: 1, column: 18 },
},
{
name: "console",
generated: { line: 2, column: 0 },
source: "a.js",
original: { line: 1, column: 20 },
},
{
name: "log",
generated: { line: 2, column: 10 },
source: "a.js",
original: { line: 1, column: 28 },
},
{
name: undefined,
generated: { line: 2, column: 13 },
source: "a.js",
original: { line: 1, column: 20 },
},
{
name: "msg",
generated: { line: 2, column: 14 },
source: "a.js",
original: { line: 1, column: 32 },
},
{
name: undefined,
generated: { line: 2, column: 17 },
source: "a.js",
original: { line: 1, column: 20 },
},
{
name: undefined,
generated: { line: 3, column: 0 },
source: "a.js",
original: { line: 1, column: 39 },
},
{
name: "hi",
generated: { line: 5, column: 0 },
source: "b.js",
original: { line: 1, column: 0 },
},
{
name: undefined,
generated: { line: 5, column: 3 },
source: "b.js",
original: { line: 1, column: 3 },
},
{
name: undefined,
generated: { line: 5, column: 10 },
source: "b.js",
original: { line: 1, column: 0 },
},
],
"raw mappings were incorrectly generated",
);
chai
.expect(generated.code)
.to.equal(
"function hi(msg) {\n console.log(msg);\n}\n\nhi('hello');",
"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,51 +180,75 @@ describe("generation", function () {
id2.name += "2"; id2.name += "2";
id2.loc.identiferName = "bar"; id2.loc.identiferName = "bar";
const generated = generate(ast, { const generated = generate(
filename: "inline", ast,
sourceFileName: "inline", {
sourceMaps: true, filename: "inline",
}, code); sourceFileName: "inline",
sourceMaps: true,
chai.expect(generated.map).to.deep.equal({ },
version: 3, code,
sources: ["inline"],
names: ["foo", "bar" ],
mappings: "AAAA,SAASA,IAAT,GAAe;AAAEC;AAAM",
sourcesContent: [ "function foo() { bar; }\n" ],
}, "sourcemap was incorrectly generated");
chai.expect(generated.rawMappings).to.deep.equal([
{ name: undefined,
generated: { line: 1, column: 0 },
source: "inline",
original: { line: 1, column: 0 } },
{ name: "foo",
generated: { line: 1, column: 9 },
source: "inline",
original: { line: 1, column: 9 } },
{ name: undefined,
generated: { line: 1, column: 13 },
source: "inline",
original: { line: 1, column: 0 } },
{ name: undefined,
generated: { line: 1, column: 16 },
source: "inline",
original: { line: 1, column: 15 } },
{ name: "bar",
generated: { line: 2, column: 0 },
source: "inline",
original: { line: 1, column: 17 } },
{ name: undefined,
generated: { line: 3, column: 0 },
source: "inline",
original: { line: 1, column: 23 } },
], "raw mappings were incorrectly generated");
chai.expect(generated.code).to.equal(
"function foo2() {\n bar2;\n}",
"code was incorrectly generated"
); );
chai.expect(generated.map).to.deep.equal(
{
version: 3,
sources: ["inline"],
names: ["foo", "bar"],
mappings: "AAAA,SAASA,IAAT,GAAe;AAAEC;AAAM",
sourcesContent: ["function foo() { bar; }\n"],
},
"sourcemap was incorrectly generated",
);
chai.expect(generated.rawMappings).to.deep.equal(
[
{
name: undefined,
generated: { line: 1, column: 0 },
source: "inline",
original: { line: 1, column: 0 },
},
{
name: "foo",
generated: { line: 1, column: 9 },
source: "inline",
original: { line: 1, column: 9 },
},
{
name: undefined,
generated: { line: 1, column: 13 },
source: "inline",
original: { line: 1, column: 0 },
},
{
name: undefined,
generated: { line: 1, column: 16 },
source: "inline",
original: { line: 1, column: 15 },
},
{
name: "bar",
generated: { line: 2, column: 0 },
source: "inline",
original: { line: 1, column: 17 },
},
{
name: undefined,
generated: { line: 3, column: 0 },
source: "inline",
original: { line: 1, column: 23 },
},
],
"raw mappings were incorrectly generated",
);
chai
.expect(generated.code)
.to.equal(
"function foo2() {\n bar2;\n}",
"code was incorrectly generated",
);
}); });
it("lazy source map generation", function() { it("lazy source map generation", function() {
@ -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,47 +346,55 @@ 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(
const expect = task.expect; task.title,
const actual = task.actual; !task.disabled &&
const actualCode = actual.code; function() {
const expect = task.expect;
const actual = task.actual;
const actualCode = actual.code;
if (actualCode) { if (actualCode) {
const actualAst = parse(actualCode, { const actualAst = parse(actualCode, {
filename: actual.loc, filename: actual.loc,
plugins: [ plugins: [
"asyncGenerators", "asyncGenerators",
"classProperties", "classProperties",
"decorators", "decorators",
"doExpressions", "doExpressions",
"dynamicImport", "dynamicImport",
"exportExtensions", "exportExtensions",
"flow", "flow",
"functionBind", "functionBind",
"functionSent", "functionSent",
"jsx", "jsx",
"objectRestSpread", "objectRestSpread",
"optionalChaining", "optionalChaining",
], ],
strictMode: false, strictMode: false,
sourceType: "module", sourceType: "module",
}); });
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 &&
!process.env.CI result.code &&
) { fs.statSync(path.dirname(expect.loc)).isDirectory() &&
console.log(`New test file created: ${expect.loc}`); !process.env.CI
fs.writeFileSync(expect.loc, result.code); ) {
} else { console.log(`New test file created: ${expect.loc}`);
chai.expect(result.code).to.be.equal(expect.code, actual.loc + " !== " + expect.loc); fs.writeFileSync(expect.loc, result.code);
} } else {
} 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.memberExpression( t.callExpression(
t.memberExpression(ref, expression.property, expression.computed), t.memberExpression(
t.identifier("bind") t.memberExpression(ref, expression.property, expression.computed),
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: [], {
done: false, params: [],
}).params, done: false,
},
).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,
getPrototypeOfExpression(this.getObjectRef(), this.isStatic), ): Object {
isComputed ? property : t.stringLiteral(property.name), return t.callExpression(this.file.addHelper("set"), [
value, getPrototypeOfExpression(this.getObjectRef(), this.isStatic),
t.thisExpression(), isComputed ? property : t.stringLiteral(property.name),
] value,
); 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),
[ isComputed ? property : t.stringLiteral(property.name),
getPrototypeOfExpression(this.getObjectRef(), this.isStatic), t.thisExpression(),
isComputed ? property : t.stringLiteral(property.name), ]);
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
filename, .runInContext(code, testContext, {
displayErrors: true, filename,
}).call(module.exports, module.exports, req, module, filename, dirname); displayErrors: true,
})
.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, {
}, opts); filename: self.loc,
},
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,49 +227,59 @@ 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(
function runTask() { task.title,
run(task); !task.disabled &&
} function() {
function runTask() {
defaults(task.options, { run(task);
filenameRelative: task.expect.filename,
sourceFileName: task.actual.filename,
sourceMapTarget: task.expect.filename,
suppressDeprecationMessages: true,
babelrc: false,
sourceMap: !!(task.sourceMappings || task.sourceMap),
});
extend(task.options, taskOpts);
if (dynamicOpts) dynamicOpts(task.options, task);
const throwMsg = task.options.throws;
if (throwMsg) {
// internal api doesn't have this option but it's best not to pollute
// the options object with useless options
delete task.options.throws;
assert.throws(runTask, function (err) {
return throwMsg === true || err.message.indexOf(throwMsg) >= 0;
});
} else {
if (task.exec.code) {
const result = run(task);
if (result && typeof result.then === "function") {
return result;
} }
} else {
runTask(); defaults(task.options, {
} filenameRelative: task.expect.filename,
} sourceFileName: task.actual.filename,
}); sourceMapTarget: task.expect.filename,
suppressDeprecationMessages: true,
babelrc: false,
sourceMap: !!(task.sourceMappings || task.sourceMap),
});
extend(task.options, taskOpts);
if (dynamicOpts) dynamicOpts(task.options, task);
const throwMsg = task.options.throws;
if (throwMsg) {
// internal api doesn't have this option but it's best not to pollute
// the options object with useless options
delete task.options.throws;
assert.throws(runTask, function(err) {
return (
throwMsg === true || err.message.indexOf(throwMsg) >= 0
);
});
} else {
if (task.exec.code) {
const result = run(task);
if (result && typeof result.then === "function") {
return result;
}
} else {
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,23 +29,30 @@ export default function ({ types: t }) {
}); });
`); `);
const buildClassPropertySpec = (ref, { key, value, computed }) => buildObjectDefineProperty({ const buildClassPropertySpec = (ref, { key, value, computed }) =>
REF: ref, buildObjectDefineProperty({
KEY: (t.isIdentifier(key) && !computed) ? t.stringLiteral(key.name) : key, REF: ref,
VALUE: value ? value : t.identifier("undefined"), KEY: t.isIdentifier(key) && !computed ? t.stringLiteral(key.name) : key,
}); 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 {
inherits: syntaxClassProperties, inherits: syntaxClassProperties,
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.variableDeclarator( t.variableDeclaration("var", [
initialisePropsRef, t.variableDeclarator(
t.functionExpression(null, [], t.blockStatement(instanceBody)) initialisePropsRef,
), 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(
const expression = decorator.expression; identDecorators
const id = decorator.expression = path.scope.generateDeclaredUidIdentifier("dec"); .map(decorator => {
return t.assignmentExpression("=", id, expression); const expression = decorator.expression;
}).concat([path.node])); const id = (decorator.expression = path.scope.generateDeclaredUidIdentifier(
"dec",
));
return t.assignmentExpression("=", id, expression);
})
.concat([path.node]),
);
} }
/** /**
@ -164,15 +178,15 @@ 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({
CLASS_REF: name, CLASS_REF: name,
DECORATOR: decorator, DECORATOR: decorator,
INNER: acc, INNER: acc,
}).expression; }).expression;
}, classPath.node); }, classPath.node);
} }
/** /**
@ -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,58 +232,79 @@ 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 =
CLASS_REF: name, path.isClass() && !node.static
}).expression : name; ? buildClassPrototype({
CLASS_REF: 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), [ "=",
target, descriptor,
property, t.callExpression(
t.arrayExpression(decorators.map((dec) => dec.expression)), ensureApplyDecoratedDescriptorHelper(path, state),
t.objectExpression([ [
t.objectProperty(t.identifier("enumerable"), t.booleanLiteral(true)), target,
t.objectProperty(t.identifier("initializer"), initializer), property,
]), t.arrayExpression(decorators.map(dec => dec.expression)),
]) t.objectExpression([
t.objectProperty(
t.identifier("enumerable"),
t.booleanLiteral(true),
),
t.objectProperty(t.identifier("initializer"), initializer),
]),
],
),
), ),
]); ]);
} else { } else {
acc = acc.concat( acc = acc.concat(
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.variableDeclarator(ref, t.toExpression(node)), t.variableDeclaration("let", [
])); 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(
path.get("left.object").node, t.callExpression(ensureInitializerDefineProp(path, state), [
t.stringLiteral(path.get("left.property").node.name), path.get("left.object").node,
path.get("right.arguments")[0].node, t.stringLiteral(path.get("left.property").node.name),
path.get("right.arguments")[1].node, path.get("right.arguments")[0].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,41 +135,47 @@ 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: { {
enter(path, state) { Loop: {
state.loopDepth++; enter(path, state) {
state.loopDepth++;
},
exit(path, state) {
state.loopDepth--;
},
}, },
exit(path, state) { Function(path, state) {
state.loopDepth--; // References to block-scoped variables only require added closures if it's
// possible for the code to run more than once -- otherwise it is safe to
// simply rename the variables.
if (state.loopDepth > 0) {
path.traverse(letReferenceFunctionVisitor, state);
}
return path.skip();
}, },
}, },
Function(path, state) { tdzVisitor,
// References to block-scoped variables only require added closures if it's ]);
// possible for the code to run more than once -- otherwise it is safe to
// simply rename the variables. const letReferenceFunctionVisitor = traverse.visitors.merge([
if (state.loopDepth > 0) { {
path.traverse(letReferenceFunctionVisitor, state); ReferencedIdentifier(path, state) {
} const ref = state.letReferences[path.node.name];
return path.skip();
// not a part of our scope
if (!ref) return;
// this scope has a variable with the same name so it couldn't belong
// to our let scope
const localBinding = path.scope.getBindingIdentifier(path.node.name);
if (localBinding && localBinding !== ref) return;
state.closurify = true;
},
}, },
}, tdzVisitor]); tdzVisitor,
]);
const letReferenceFunctionVisitor = traverse.visitors.merge([{
ReferencedIdentifier(path, state) {
const ref = state.letReferences[path.node.name];
// not a part of our scope
if (!ref) return;
// this scope has a variable with the same name so it couldn't belong
// to our let scope
const localBinding = path.scope.getBindingIdentifier(path.node.name);
if (localBinding && localBinding !== ref) return;
state.closurify = true;
},
}, 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.binaryExpression("===", ret, single.test), t.ifStatement(
single.consequent[0] t.binaryExpression("===", ret, single.test),
)); 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.newExpression(t.identifier("ReferenceError"), [ t.throwStatement(
t.stringLiteral(`${node.name} is not defined - temporal dead zone`), t.inherits(
]), t.newExpression(t.identifier("ReferenceError"), [
node t.stringLiteral(
))); `${node.name} is not defined - temporal dead zone`,
),
]),
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.variableDeclarator(ref, t.toExpression(node)), t.variableDeclaration("let", [
])); 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