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

View File

@ -24,9 +24,21 @@ function collect(value, previousValue): Array<string> {
/* eslint-disable max-len */
program.option("-e, --eval [script]", "Evaluate script");
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("-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(
"-o, --only [globs]",
"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("-b, --presets [string]", "", collect);
/* eslint-enable max-len */
@ -55,23 +67,28 @@ const replPlugin = ({ types: t }) => ({
VariableDeclaration(path) {
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) {
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,
// 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();
if (!code) return undefined;
@ -113,7 +130,7 @@ if (program.eval || program.print) {
let i = 0;
let ignoreNext = false;
args.some(function (arg, i2) {
args.some(function(arg, i2) {
if (ignoreNext) {
ignoreNext = false;
return;
@ -133,7 +150,9 @@ if (program.eval || program.print) {
// make the filename absolute
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
process.argv = ["node"].concat(args);

View File

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

View File

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

View File

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

View File

@ -7,14 +7,14 @@ import fs from "fs";
import * as util from "./util";
export default function (commander, filenames, opts) {
export default function(commander, filenames, opts) {
if (commander.sourceMaps === "inline") {
opts.sourceMaps = true;
}
let results = [];
const buildResult = function () {
const buildResult = function() {
const map = new sourceMap.SourceMapGenerator({
file: path.basename(commander.outFile || "") || "stdout",
sourceRoot: opts.sourceRoot,
@ -23,14 +23,14 @@ export default function (commander, filenames, opts) {
let code = "";
let offset = 0;
results.forEach(function (result) {
results.forEach(function(result) {
code += result.code + "\n";
if (result.map) {
const consumer = new sourceMap.SourceMapConsumer(result.map);
const sources = new Set();
consumer.eachMapping(function (mapping) {
consumer.eachMapping(function(mapping) {
if (mapping.source != null) sources.add(mapping.source);
map.addMapping({
@ -39,14 +39,17 @@ export default function (commander, filenames, opts) {
column: mapping.generatedColumn,
},
source: mapping.source,
original: mapping.source == null ? null : {
line: mapping.originalLine,
column: mapping.originalColumn,
},
original:
mapping.source == null
? null
: {
line: mapping.originalLine,
column: mapping.originalColumn,
},
});
});
sources.forEach((source) => {
sources.forEach(source => {
const content = consumer.sourceContentFor(source, true);
if (content !== null) {
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
// 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();
}
@ -69,7 +75,7 @@ export default function (commander, filenames, opts) {
};
};
const output = function () {
const output = function() {
const result = buildResult();
if (commander.outFile) {
@ -86,36 +92,45 @@ export default function (commander, filenames, opts) {
}
};
const stdin = function () {
const stdin = function() {
let code = "";
process.stdin.setEncoding("utf8");
process.stdin.on("readable", function () {
process.stdin.on("readable", function() {
const chunk = process.stdin.read();
if (chunk !== null) code += chunk;
});
process.stdin.on("end", function () {
results.push(util.transform(commander.filename, code, defaults({
sourceFileName: "stdin",
}, opts)));
process.stdin.on("end", function() {
results.push(
util.transform(
commander.filename,
code,
defaults(
{
sourceFileName: "stdin",
},
opts,
),
),
);
output();
});
};
const walk = function () {
const walk = function() {
const _filenames = [];
results = [];
filenames.forEach(function (filename) {
filenames.forEach(function(filename) {
if (!fs.existsSync(filename)) return;
const stat = fs.statSync(filename);
if (stat.isDirectory()) {
const dirname = filename;
util.readdirFilter(filename).forEach(function (filename) {
util.readdirFilter(filename).forEach(function(filename) {
_filenames.push(path.join(dirname, filename));
});
} else {
@ -123,16 +138,25 @@ export default function (commander, filenames, opts) {
}
});
_filenames.forEach(function (filename) {
_filenames.forEach(function(filename) {
let sourceFilename = filename;
if (commander.outFile) {
sourceFilename = path.relative(path.dirname(commander.outFile), sourceFilename);
sourceFilename = path.relative(
path.dirname(commander.outFile),
sourceFilename,
);
}
sourceFilename = slash(sourceFilename);
const data = util.compile(filename, defaults({
sourceFileName: sourceFilename,
}, opts));
const data = util.compile(
filename,
defaults(
{
sourceFileName: sourceFilename,
},
opts,
),
);
if (!data) return;
@ -142,33 +166,36 @@ export default function (commander, filenames, opts) {
output();
};
const files = function () {
const files = function() {
if (!commander.skipInitialBuild) {
walk();
}
if (commander.watch) {
const chokidar = util.requireChokidar();
chokidar.watch(filenames, {
persistent: true,
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 50,
pollInterval: 10,
},
}).on("all", function (type, filename) {
if (!util.isCompilableExtension(filename, commander.extensions)) return;
if (type === "add" || type === "change") {
util.log(type + " " + filename);
try {
walk();
} catch (err) {
console.error(err.stack);
chokidar
.watch(filenames, {
persistent: true,
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 50,
pollInterval: 10,
},
})
.on("all", function(type, filename) {
if (!util.isCompilableExtension(filename, commander.extensions)) {
return;
}
}
});
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 */
// 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("--presets [list]", "comma-separated list of preset names", collect);
commander.option("--plugins [list]", "comma-separated list of plugin names", collect);
commander.option(
"-f, --filename [filename]",
"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.
commander.option("--source-type [script|module]", "");
commander.option("--no-babelrc", "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);
commander.option(
"--no-babelrc",
"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.
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.
commander.option("--no-comments", "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(
"--no-comments",
"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("--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");
commander.option(
"--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.
commander.option("-s, --source-maps [true|false|inline|both]", "", booleanify);
commander.option("--source-map-target [string]", "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");
commander.option(
"--source-map-target [string]",
"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.
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("--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.
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("--skip-initial-build", "Do not compile files before watching");
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(
"--skip-initial-build",
"Do not compile files before watching",
);
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");
/* eslint-enable max-len */
@ -84,7 +156,7 @@ commander.parse(process.argv);
const errors = [];
let filenames = commander.args.reduce(function (globbed, input) {
let filenames = commander.args.reduce(function(globbed, input) {
let files = glob.sync(input);
if (!files.length) files = [input];
return globbed.concat(files);
@ -92,7 +164,7 @@ let filenames = commander.args.reduce(function (globbed, input) {
filenames = uniq(filenames);
filenames.forEach(function (filename) {
filenames.forEach(function(filename) {
if (!fs.existsSync(filename)) {
errors.push(filename + " doesn't exist");
}

View File

@ -10,7 +10,7 @@ export function chmod(src, dest) {
}
export function readdirFilter(filename) {
return readdir(filename).filter(function (filename) {
return readdir(filename).filter(function(filename) {
return isCompilableExtension(filename);
});
}
@ -20,7 +20,10 @@ export { readdir };
/**
* 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 ext = path.extname(filename);
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));
process.exit(1);
});
@ -74,7 +77,7 @@ export function requireChokidar() {
} catch (err) {
console.error(
"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;
}

View File

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

View File

@ -90,11 +90,11 @@ function getTokenType(match) {
*/
function highlight(defs: Object, text: string) {
return text.replace(jsTokens, function (...args) {
return text.replace(jsTokens, function(...args) {
const type = getTokenType(args);
const colorize = defs[type];
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 {
return args[0];
}
@ -106,9 +106,15 @@ function highlight(defs: Object, text: string) {
*/
function getMarkerLines(
loc: NodeLocation, source: Array<string>, opts: Object
loc: NodeLocation,
source: Array<string>,
opts: 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 linesAbove = opts.linesAbove || 2;
const linesBelow = opts.linesBelow || 3;
@ -165,12 +171,13 @@ function getMarkerLines(
return { start, end, markerLines };
}
export function codeFrameColumns (
export function codeFrameColumns(
rawLines: string,
loc: NodeLocation,
opts: Object = {},
): string {
const highlighted = (opts.highlightCode && Chalk.supportsColor) || opts.forceColor;
const highlighted =
(opts.highlightCode && Chalk.supportsColor) || opts.forceColor;
let chalk = Chalk;
if (opts.forceColor) {
chalk = new Chalk.constructor({ enabled: true });
@ -186,34 +193,39 @@ export function codeFrameColumns (
const numberMaxWidth = String(end).length;
const frame = lines.slice(start, end).map((line, index) => {
const number = start + 1 + index;
const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
const gutter = ` ${paddedNumber} | `;
const hasMarker = markerLines[number];
if (hasMarker) {
let markerLine = "";
if (Array.isArray(hasMarker)) {
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
const numberOfMarkers = hasMarker[1] || 1;
const frame = lines
.slice(start, end)
.map((line, index) => {
const number = start + 1 + index;
const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
const gutter = ` ${paddedNumber} | `;
const hasMarker = markerLines[number];
if (hasMarker) {
let markerLine = "";
if (Array.isArray(hasMarker)) {
const markerSpacing = line
.slice(0, Math.max(hasMarker[0] - 1, 0))
.replace(/[^\t]/g, " ");
const numberOfMarkers = hasMarker[1] || 1;
markerLine = [
"\n ",
maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")),
markerSpacing,
maybeHighlight(defs.marker, "^").repeat(numberOfMarkers),
markerLine = [
"\n ",
maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")),
markerSpacing,
maybeHighlight(defs.marker, "^").repeat(numberOfMarkers),
].join("");
}
return [
maybeHighlight(defs.marker, ">"),
maybeHighlight(defs.gutter, gutter),
line,
markerLine,
].join("");
} else {
return ` ${maybeHighlight(defs.gutter, gutter)}${line}`;
}
return [
maybeHighlight(defs.marker, ">"),
maybeHighlight(defs.gutter, gutter),
line,
markerLine,
].join("");
} else {
return ` ${maybeHighlight(defs.gutter, gutter)}${line}`;
}
}).join("\n");
})
.join("\n");
if (highlighted) {
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.
*/
export default function (
export default function(
rawLines: string,
lineNumber: number,
colNumber: ?number,
@ -236,7 +248,7 @@ export default function (
deprecationWarningShown = true;
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";
@ -249,7 +261,9 @@ export default function (
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);
}

View File

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

View File

@ -7,14 +7,14 @@ import micromatch from "micromatch";
import { findConfigs, loadConfig } from "./loading/files";
type ConfigItem = {
type: "options"|"arguments",
type: "options" | "arguments",
options: {},
dirname: string,
alias: 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) {
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 {
filename: string|null;
filename: string | null;
configs: Array<ConfigItem>;
possibleDirs: null|Array<string>;
possibleDirs: null | Array<string>;
constructor(filename) {
this.configs = [];
@ -57,16 +57,14 @@ class ConfigChainBuilder {
/**
* Tests if a filename should be ignored based on "ignore" and "only" options.
*/
shouldIgnore(
ignore: mixed,
only: mixed,
dirname: string,
): boolean {
shouldIgnore(ignore: mixed, only: mixed, dirname: string): boolean {
if (!this.filename) return false;
if (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;
@ -74,7 +72,9 @@ class ConfigChainBuilder {
if (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;
@ -89,21 +89,27 @@ class ConfigChainBuilder {
*/
matchesPatterns(patterns: Array<mixed>, dirname: string) {
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 strings = [];
const fns = [];
patterns.forEach((pattern) => {
patterns.forEach(pattern => {
if (typeof pattern === "string") strings.push(pattern);
else if (typeof pattern === "function") fns.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 (fns.some((fn) => fn(filename))) return true;
if (res.some(re => re.test(filename))) return true;
if (fns.some(fn => fn(filename))) return true;
if (strings.length > 0) {
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.
const negate = pattern[0] === "!";
if (negate) pattern = pattern.slice(1);
@ -131,7 +137,9 @@ class ConfigChainBuilder {
return (negate ? "!" : "") + path.resolve(dirname, pattern);
});
if (micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0) {
if (
micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0
) {
return true;
}
}
@ -150,16 +158,16 @@ class ConfigChainBuilder {
});
}
mergeConfig({
type,
options: rawOpts,
alias,
dirname,
}) {
mergeConfig({ 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.
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.
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);
@ -168,13 +176,19 @@ class ConfigChainBuilder {
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");
}
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");
}
@ -196,11 +210,13 @@ class ConfigChainBuilder {
});
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 existingConfig = this.configs.some((config) => {
const existingConfig = this.configs.some(config => {
return config.alias === extendsConfig.filepath;
});
if (!existingConfig) {
@ -214,4 +230,3 @@ class ConfigChainBuilder {
}
}
}

View File

@ -13,7 +13,7 @@ type CacheConfiguratorObj = {
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
@ -22,7 +22,7 @@ type CacheEntry<ResultT> = Array<[ ResultT, () => boolean ]>;
export function makeStrongCache<ArgT, ResultT>(
handler: (ArgT, CacheConfigurator) => ResultT,
autoPermacache?: boolean,
): (ArgT) => ResultT {
): ArgT => ResultT {
return makeCachedFunction(new Map(), handler, autoPermacache);
}
@ -34,22 +34,24 @@ export function makeStrongCache<ArgT, ResultT>(
export function makeWeakCache<ArgT: {}, ResultT>(
handler: (ArgT, CacheConfigurator) => ResultT,
autoPermacache?: boolean,
): (ArgT) => ResultT {
): ArgT => ResultT {
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>>(
callCache: Cache,
handler: (ArgT, CacheConfigurator) => ResultT,
autoPermacache: boolean = true,
): (ArgT) => ResultT {
): ArgT => ResultT {
return function cachedFunction(arg) {
let cachedValue: CacheEntry<ResultT>|void = callCache.get(arg);
let cachedValue: CacheEntry<ResultT> | void = callCache.get(arg);
if (cachedValue) {
for (const [ value, valid ] of cachedValue) {
for (const [value, valid] of cachedValue) {
if (valid()) return value;
}
}
@ -64,55 +66,53 @@ function makeCachedFunction<ArgT, ResultT, Cache: CacheMap<ArgT, ResultT>>(
if (!result.configured) {
// eslint-disable-next-line max-len
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:",
"",
"module.exports = function(api) {",
" // The API exposes the following:",
"",
" // 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);",
"",
" // 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.",
" 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.",
" 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",
" // 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)",
" api.cache.never(); // api.cache(false)",
" api.cache.using(fn); // api.cache(fn)",
"",
" // Return the value that will be cached.",
" return { };",
"};",
].join("\n"));
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:",
"",
"module.exports = function(api) {",
" // The API exposes the following:",
"",
" // 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);",
"",
" // 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.",
" 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.",
' 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",
" // 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)",
" api.cache.never(); // api.cache(false)",
" api.cache.using(fn); // api.cache(fn)",
"",
" // Return the value that will be cached.",
" return { };",
"};",
].join("\n"),
);
}
if (!result.never) {
if (result.forever) {
cachedValue = [
[value, () => true],
];
cachedValue = [[value, () => true]];
} else if (result.invalidate) {
cachedValue = [
[value, result.valid],
];
cachedValue = [[value, result.valid]];
} else {
cachedValue = cachedValue || [];
cachedValue.push([ value, result.valid ]);
cachedValue.push([value, result.valid]);
}
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 result = {
@ -137,51 +141,80 @@ function makeCacheConfig(): { cache: CacheConfigurator, result: *, deactivate: (
active = false;
};
const cache: CacheConfigurator = Object.assign((function cacheFn(val) {
if (typeof val === "boolean") {
if (val) cache.forever();
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()");
const cache: CacheConfigurator = Object.assign(
(function cacheFn(val) {
if (typeof val === "boolean") {
if (val) cache.forever();
else cache.never();
return;
}
result.configured = true;
const key = handler();
pairs.push([ key, handler ]);
return key;
},
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;
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();
pairs.push([ key, handler ]);
return key;
},
}: CacheConfiguratorObj));
const key = handler();
pairs.push([key, handler]);
return key;
},
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 };
}

View File

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

View File

@ -5,13 +5,13 @@ import manageOptions from "./option-manager";
export type ResolvedConfig = {
options: Object,
passes: Array<Array<[ Plugin, ?{} ]>>,
passes: Array<Array<[Plugin, ?{}]>>,
};
/**
* 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") {
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_JS_FILENAME,
PACKAGE_FILENAME,
].reduce((previousConfig: ConfigFile|null, name) => {
].reduce((previousConfig: ConfigFile | null, name) => {
const filepath = path.join(loc, name);
const config = readConfig(filepath);
if (config && previousConfig) {
throw new Error(`Multiple configuration files found. Please remove one:\n- ${
path.basename(previousConfig.filepath)}\n- ${name}\nfrom ${loc}`);
throw new Error(
`Multiple configuration files found. Please remove one:\n- ${path.basename(
previousConfig.filepath,
)}\n- ${name}\nfrom ${loc}`,
);
}
return config || previousConfig;
@ -73,7 +76,9 @@ export function loadConfig(name: string, dirname: string): ConfigFile {
const filepath = resolve.sync(name, { basedir: dirname });
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;
}
@ -83,7 +88,9 @@ export function loadConfig(name: string, dirname: string): ConfigFile {
* throw if there are parsing errors while loading a config.
*/
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) => {
@ -96,7 +103,10 @@ const readConfigJS = makeStrongCache((filepath, cache) => {
try {
// $FlowIssue
const configModule = (require(filepath): mixed);
options = configModule && configModule.__esModule ? (configModule.default || undefined) : configModule;
options =
configModule && configModule.__esModule
? configModule.default || undefined
: configModule;
} catch (err) {
err.message = `${filepath}: Error while loading config - ${err.message}`;
throw err;
@ -113,7 +123,9 @@ const readConfigJS = makeStrongCache((filepath, cache) => {
}
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 {
@ -144,8 +156,12 @@ const readConfigFile = makeStaticFileCache((filepath, content) => {
if (!options) throw new Error(`${filepath}: No config detected`);
}
if (typeof options !== "object") throw new Error(`${filepath}: Config returned typeof ${typeof options}`);
if (Array.isArray(options)) throw new Error(`${filepath}: Expected config object but found array`);
if (typeof options !== "object") {
throw new Error(`${filepath}: Config returned typeof ${typeof options}`);
}
if (Array.isArray(options)) {
throw new Error(`${filepath}: Expected config object but found array`);
}
return {
filepath,
@ -157,8 +173,8 @@ const readConfigFile = makeStaticFileCache((filepath, content) => {
const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
const ignore = content
.split("\n")
.map((line) => line.replace(/#(.*?)$/, "").trim())
.filter((line) => !!line);
.map(line => line.replace(/#(.*?)$/, "").trim())
.filter(line => !!line);
return {
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) => {
if (cache.invalidate(() => fileMtime(filepath)) === null) {
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 {
return +fs.statSync(filepath).mtime;
} catch (e) {

View File

@ -16,27 +16,47 @@ export function loadConfig(name: string, dirname: string): ConfigFile {
}
// 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;
}
// 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;
}
export function loadPlugin(name: string, dirname: string): { filepath: string, value: mixed } {
throw new Error(`Cannot load plugin ${name} relative to ${dirname} in a browser`);
export function loadPlugin(
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 } {
throw new Error(`Cannot load preset ${name} relative to ${dirname} in a browser`);
export function loadPreset(
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 } {
throw new Error(`Cannot load parser ${name} relative to ${dirname} in a browser`);
export function loadParser(
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 } {
throw new Error(`Cannot load generator ${name} relative to ${dirname} in a browser`);
export function loadGenerator(
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
// 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 "./plugins";

View File

@ -15,17 +15,22 @@ const BABEL_PRESET_ORG_RE = /^(@babel[/\/])(?!preset-|[^/\/]+[/\/])/;
const OTHER_PLUGIN_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-plugin-|[^/\/]+[/\/])/;
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);
}
export function resolvePreset(name: string, dirname: string): string|null {
export function resolvePreset(name: string, dirname: string): string | null {
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);
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 {
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);
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 {
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 mod = requireModule(filepath);
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") {
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 {
@ -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 mod = requireModule(filepath);
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") {
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 {
@ -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.
if (path.isAbsolute(name)) return name;
const isPreset = type === "preset";
return name
// foo -> babel-preset-foo
.replace(isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE, `babel-${type}-`)
// @babel/es2015 -> @babel/preset-es2015
.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, "");
return (
name
// foo -> babel-preset-foo
.replace(
isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE,
`babel-${type}-`,
)
// @babel/es2015 -> @babel/preset-es2015
.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);
try {
@ -109,7 +148,7 @@ function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname:
try {
resolve.sync(name, { basedir: dirname });
resolvedOriginal = true;
} catch (e2) { }
} catch (e2) {}
if (resolvedOriginal) {
// eslint-disable-next-line max-len
@ -119,9 +158,11 @@ function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname:
let resolvedBabel = false;
try {
resolve.sync(standardizeName(type, "@babel/" + name), { basedir: dirname });
resolve.sync(standardizeName(type, "@babel/" + name), {
basedir: dirname,
});
resolvedBabel = true;
} catch (e2) { }
} catch (e2) {}
if (resolvedBabel) {
// eslint-disable-next-line max-len
@ -133,7 +174,7 @@ function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname:
try {
resolve.sync(standardizeName(oppositeType, name), { basedir: dirname });
resolvedOppositeType = true;
} catch (e2) { }
} catch (e2) {}
if (resolvedOppositeType) {
// eslint-disable-next-line max-len

View File

@ -11,14 +11,19 @@ import path from "path";
import traverse from "babel-traverse";
import clone from "lodash/clone";
import { loadPlugin, loadPreset, loadParser, loadGenerator } from "./loading/files";
import {
loadPlugin,
loadPreset,
loadParser,
loadGenerator,
} from "./loading/files";
type MergeOptions = {
+type: "arguments"|"options"|"preset",
+type: "arguments" | "options" | "preset",
options: {},
alias: string,
loc: string,
dirname: string
dirname: string,
};
const optionNames = new Set([
@ -74,8 +79,8 @@ const ALLOWED_PLUGIN_KEYS = new Set([
export default function manageOptions(opts: {}): {
options: Object,
passes: Array<Array<[ Plugin, ?{} ]>>,
}|null {
passes: Array<Array<[Plugin, ?{}]>>,
} | null {
return new OptionManager().init(opts);
}
@ -100,9 +105,12 @@ class OptionManager {
mergeOptions(config: MergeOptions, pass?: Array<[Plugin, ?{}]>) {
const result = loadConfig(config);
const plugins = result.plugins.map((descriptor) => loadPluginDescriptor(descriptor));
const presets = result.presets.map((descriptor) => loadPresetDescriptor(descriptor));
const plugins = result.plugins.map(descriptor =>
loadPluginDescriptor(descriptor),
);
const presets = result.presets.map(descriptor =>
loadPresetDescriptor(descriptor),
);
if (
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
// to keep things simple we just bail out if re-wrapping the 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}`;
}
@ -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,
// it will be in the right structure to not change behavior.
opts.plugins = this.passes[0];
opts.presets = this.passes.slice(1)
.filter((plugins) => plugins.length > 0)
.map((plugins) => ({ plugins }));
opts.presets = this.passes
.slice(1)
.filter(plugins => plugins.length > 0)
.map(plugins => ({ plugins }));
if (opts.inputSourceMap) {
opts.sourceMaps = true;
@ -199,7 +209,7 @@ class OptionManager {
}
type BasicDescriptor = {
value: {}|Function,
value: {} | Function,
options: ?{},
dirname: string,
alias: string,
@ -209,19 +219,28 @@ type BasicDescriptor = {
/**
* Load and validate the given config into a set of options, plugins, and presets.
*/
function loadConfig(config): {
function loadConfig(
config,
): {
options: {},
plugins: Array<BasicDescriptor>,
presets: Array<BasicDescriptor>,
} {
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");
}
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 {
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");
}
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 {
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.
*/
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;
let item;
@ -266,7 +294,9 @@ function loadDescriptor(descriptor, skipOptions) {
item = value(context, options, { dirname: descriptor.dirname });
}
} 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;
}
@ -282,26 +312,37 @@ function loadDescriptor(descriptor, skipOptions) {
*/
const PLUGIN_CACHE = new WeakMap();
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);
if (!result) {
result = instantiatePlugin(loadDescriptor(descriptor, true /* skipOptions */));
result = instantiatePlugin(
loadDescriptor(descriptor, true /* skipOptions */),
);
PLUGIN_CACHE.set(descriptor.value, result);
}
return [ result, descriptor.options];
return [result, descriptor.options];
}
function instantiatePlugin({ value: pluginObj, descriptor }) {
Object.keys(pluginObj).forEach((key) => {
Object.keys(pluginObj).forEach(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)) {
throw new Error("Plugins aren't allowed to specify catch-all enter/exit handlers. " +
"Please target individual nodes.");
if (
pluginObj.visitor &&
(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, {
@ -325,8 +366,14 @@ function instantiatePlugin({ value: pluginObj, descriptor }) {
plugin.pre = chain(inherits.pre, plugin.pre);
plugin.post = chain(inherits.post, plugin.post);
plugin.manipulateOptions = chain(inherits.manipulateOptions, plugin.manipulateOptions);
plugin.visitor = traverse.visitors.merge([inherits.visitor, plugin.visitor]);
plugin.manipulateOptions = chain(
inherits.manipulateOptions,
plugin.manipulateOptions,
);
plugin.visitor = traverse.visitors.merge([
inherits.visitor,
plugin.visitor,
]);
}
return new Plugin(plugin, descriptor.alias);
@ -371,10 +418,18 @@ function normalizeOptions(config) {
}
if (type === "preset") {
if (options.only !== undefined) throw new Error(`${alias}.only 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.only !== undefined) {
throw new Error(`${alias}.only 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) {
@ -390,7 +445,10 @@ function normalizeOptions(config) {
// check for an unknown option
if (!optionNames.has(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 {
// 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.`;
@ -402,12 +460,21 @@ function normalizeOptions(config) {
if (options.parserOpts && typeof options.parserOpts.parser === "string") {
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.generator = loadGenerator(options.generatorOpts.generator, config.dirname).value;
options.generatorOpts.generator = loadGenerator(
options.generatorOpts.generator,
config.dirname,
).value;
}
delete options.passPerPreset;
@ -420,16 +487,22 @@ function normalizeOptions(config) {
/**
* Given a plugin/preset item, resolve it into a standard format.
*/
function normalizePair(pair: mixed, resolver, dirname): {
filepath: string|null,
value: {}|Function,
function normalizePair(
pair: mixed,
resolver,
dirname,
): {
filepath: string | null,
value: {} | Function,
options: ?{},
} {
let options;
let value = pair;
if (Array.isArray(pair)) {
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;
@ -437,10 +510,7 @@ function normalizePair(pair: mixed, resolver, dirname): {
let filepath = null;
if (typeof value === "string") {
({
filepath,
value,
} = resolver(value, dirname));
({ filepath, value } = resolver(value, dirname));
}
if (!value) {
@ -456,11 +526,15 @@ function normalizePair(pair: mixed, resolver, dirname): {
}
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") {
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 };

View File

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

View File

@ -2,52 +2,58 @@
/* eslint max-len: "off" */
export default {
"auxiliaryComment": {
"message": "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`",
auxiliaryComment: {
message: "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`",
},
"blacklist": {
"message": "Put the specific transforms you want in the `plugins` option",
blacklist: {
message: "Put the specific transforms you want in the `plugins` option",
},
"breakConfig": {
"message": "This is not a necessary option in Babel 6",
breakConfig: {
message: "This is not a necessary option in Babel 6",
},
"experimental": {
"message": "Put the specific transforms you want in the `plugins` option",
experimental: {
message: "Put the specific transforms you want in the `plugins` option",
},
"externalHelpers": {
"message": "Use the `external-helpers` plugin instead. Check out http://babeljs.io/docs/plugins/external-helpers/",
externalHelpers: {
message:
"Use the `external-helpers` plugin instead. Check out http://babeljs.io/docs/plugins/external-helpers/",
},
"extra": {
"message": "",
extra: {
message: "",
},
"jsxPragma": {
"message": "use the `pragma` option in the `react-jsx` plugin . Check out http://babeljs.io/docs/plugins/transform-react-jsx/",
jsxPragma: {
message:
"use the `pragma` option in the `react-jsx` plugin . Check out http://babeljs.io/docs/plugins/transform-react-jsx/",
},
// "keepModuleIdExtensions": {
// "message": ""
// },
"loose": {
"message": "Specify the `loose` option for the relevant plugin you are using or use a preset that sets the option.",
loose: {
message:
"Specify the `loose` option for the relevant plugin you are using or use a preset that sets the option.",
},
"metadataUsedHelpers": {
"message": "Not required anymore as this is enabled by default",
metadataUsedHelpers: {
message: "Not required anymore as this is enabled by default",
},
"modules": {
"message": "Use the corresponding module transform plugin in the `plugins` option. Check out http://babeljs.io/docs/plugins/#modules",
modules: {
message:
"Use the corresponding module transform plugin in the `plugins` option. Check out http://babeljs.io/docs/plugins/#modules",
},
"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/",
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/",
},
"optional": {
"message": "Put the specific transforms you want in the `plugins` option",
optional: {
message: "Put the specific transforms you want in the `plugins` option",
},
"sourceMapName": {
"message": "Use the `sourceMapTarget` option",
sourceMapName: {
message: "Use the `sourceMapTarget` option",
},
"stage": {
"message": "Check out the corresponding stage-x presets http://babeljs.io/docs/plugins/#presets",
stage: {
message:
"Check out the corresponding stage-x presets http://babeljs.io/docs/plugins/#presets",
},
"whitelist": {
"message": "Put the specific transforms you want in the `plugins` option",
whitelist: {
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";
export function loadOptions(opts): Object|null {
export function loadOptions(opts): Object | null {
const config = loadConfig(opts);
return config ? config.options : null;
@ -41,4 +41,10 @@ export {
* 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.
*/
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) {
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([
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([]))
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([]),
),
),
]),
);
builder(body);
@ -39,9 +51,11 @@ function buildGlobal(namespace, builder) {
function buildUmd(namespace, builder) {
const body = [];
body.push(t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.identifier("global")),
]));
body.push(
t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.identifier("global")),
]),
);
builder(body);
@ -51,7 +65,7 @@ function buildUmd(namespace, builder) {
BROWSER_ARGUMENTS: t.assignmentExpression(
"=",
t.memberExpression(t.identifier("root"), namespace),
t.objectExpression([])
t.objectExpression([]),
),
COMMON_ARGUMENTS: t.identifier("exports"),
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
@ -63,31 +77,39 @@ function buildUmd(namespace, builder) {
function buildVar(namespace, builder) {
const body = [];
body.push(t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.objectExpression([])),
]));
body.push(
t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.objectExpression([])),
]),
);
builder(body);
body.push(t.expressionStatement(namespace));
return t.program(body);
}
function buildHelpers(body, namespace, whitelist) {
helpers.list.forEach(function (name) {
helpers.list.forEach(function(name) {
if (whitelist && whitelist.indexOf(name) < 0) return;
const key = t.identifier(name);
body.push(t.expressionStatement(
t.assignmentExpression("=", t.memberExpression(namespace, key), helpers.get(name))
));
body.push(
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(namespace, key),
helpers.get(name),
),
),
);
});
}
export default function (
export default function(
whitelist?: Array<string>,
outputType: "global" | "umd" | "var" = "global",
) {
const namespace = t.identifier("babelHelpers");
const builder = function (body) {
const builder = function(body) {
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.
INTERNAL_PLUGINS = loadConfig({
babelrc: false,
plugins: [ blockHoistPlugin ],
plugins: [blockHoistPlugin],
}).passes[0];
}
@ -61,7 +61,7 @@ export default class File extends Store {
};
for (const pluginPairs of passes) {
for (const [ plugin ] of pluginPairs) {
for (const [plugin] of pluginPairs) {
if (plugin.manipulateOptions) {
plugin.manipulateOptions(this.opts, this.parserOpts, this);
}
@ -150,7 +150,7 @@ export default class File extends Store {
if (opts.sourceRoot != null) {
// remove sourceRoot from filename
const sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
const sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "/?");
filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
}
@ -172,17 +172,25 @@ export default class File extends Store {
resolveModuleSource(source: string): string {
const resolveModuleSource = this.opts.resolveModuleSource;
if (resolveModuleSource) source = resolveModuleSource(source, this.opts.filename);
if (resolveModuleSource) {
source = resolveModuleSource(source, this.opts.filename);
}
return source;
}
addImport(source: string, imported: string, name?: string = imported): Object {
addImport(
source: string,
imported: string,
name?: string = imported,
): Object {
const alias = `${source}:${imported}`;
let id = this.dynamicImportIds[alias];
if (!id) {
source = this.resolveModuleSource(source);
id = this.dynamicImportIds[alias] = this.scope.generateUidIdentifier(name);
id = this.dynamicImportIds[alias] = this.scope.generateUidIdentifier(
name,
);
const specifiers = [];
@ -222,7 +230,9 @@ export default class File extends Store {
}
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) {
ref.body._compact = true;
@ -257,7 +267,9 @@ export default class File extends Store {
const declar = this.declarations[name];
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 init = t.callExpression(helperId, [strings, raw]);
@ -270,7 +282,11 @@ export default class File extends Store {
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 err = new Error(msg);
@ -280,7 +296,8 @@ export default class File extends Store {
} else {
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) {
err.message += ". Location has been estimated.";
@ -308,7 +325,7 @@ export default class File extends Store {
// single source file to a single output file.
const source = outputMapConsumer.sources[0];
inputMapConsumer.eachMapping(function (mapping) {
inputMapConsumer.eachMapping(function(mapping) {
const generatedPosition = outputMapConsumer.generatedPositionFor({
line: mapping.generatedLine,
column: mapping.generatedColumn,
@ -318,10 +335,13 @@ export default class File extends Store {
mergedGenerator.addMapping({
source: mapping.source,
original: mapping.source == null ? null : {
line: mapping.originalLine,
column: mapping.originalColumn,
},
original:
mapping.source == null
? null
: {
line: mapping.originalLine,
column: mapping.originalColumn,
},
generated: generatedPosition,
});
@ -385,15 +405,15 @@ export default class File extends Store {
const passes = [];
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);
passPairs.push([ plugin, pass ]);
passPairs.push([plugin, pass]);
passes.push(pass);
visitors.push(plugin.visitor);
}
for (const [ plugin, pass ] of passPairs) {
for (const [plugin, pass] of passPairs) {
const fn = plugin.pre;
if (fn) fn.call(pass, this);
}
@ -401,16 +421,19 @@ export default class File extends Store {
debug(this.opts, "Start transform traverse");
// 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);
debug(this.opts, "End transform traverse");
for (const [ plugin, pass ] of passPairs) {
for (const [plugin, pass] of passPairs) {
const fn = plugin.post;
if (fn) fn.call(pass, this);
}
}
return this.generate();
@ -428,7 +451,7 @@ export default class File extends Store {
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;
if (loc) {
@ -530,8 +553,11 @@ export default class File extends Store {
debug(this.opts, "Generation start");
const _result = gen(ast, opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : opts,
this.code);
const _result = gen(
ast,
opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : opts,
this.code,
);
result.code = _result.code;
result.map = _result.map;

View File

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

View File

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

View File

@ -5,7 +5,9 @@ import vm from "vm";
describe("browserify", function() {
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) {
if (err) return done(err);

View File

@ -27,7 +27,6 @@ describe("caching API", () => {
return { arg, count: count++ };
});
assert.deepEqual(fn("one"), { arg: "one", count: 0 });
assert.equal(fn("one"), fn("one"));
@ -210,48 +209,97 @@ describe("caching API", () => {
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.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"));
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.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"));
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.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"));
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.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"));
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.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"));
});
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./);
});
@ -259,7 +307,7 @@ describe("caching API", () => {
it("should auto-permacache by default", () => {
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.equal(fn("one"), fn("one"));
@ -333,7 +381,10 @@ describe("caching API", () => {
it("should throw if you configure .forever after exiting", () => {
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", () => {
@ -345,12 +396,18 @@ describe("caching API", () => {
it("should throw if you configure .using after exiting", () => {
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", () => {
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() {
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]);
}
return path.join.apply(path, args);
@ -14,11 +14,11 @@ function base() {
return process.cwd();
}
describe("buildConfigChain", function () {
describe("buildConfigChain", function() {
let oldBabelEnv;
let oldNodeEnv;
beforeEach(function () {
beforeEach(function() {
oldBabelEnv = process.env.BABEL_ENV;
oldNodeEnv = process.env.NODE_ENV;
@ -26,7 +26,7 @@ describe("buildConfigChain", function () {
delete process.env.NODE_ENV;
});
afterEach(function () {
afterEach(function() {
process.env.BABEL_ENV = oldBabelEnv;
process.env.NODE_ENV = oldNodeEnv;
});
@ -52,7 +52,7 @@ describe("buildConfigChain", function () {
});
});
it("dir1", function () {
it("dir1", function() {
const chain = buildConfigChain({
filename: fixture("dir1", "src.js"),
});
@ -61,9 +61,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"extended",
],
plugins: ["extended"],
},
alias: fixture("extended.babelrc.json"),
loc: fixture("extended.babelrc.json"),
@ -72,9 +70,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"root",
],
plugins: ["root"],
},
alias: fixture(".babelrc"),
loc: fixture(".babelrc"),
@ -83,9 +79,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -105,7 +99,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("dir2", function () {
it("dir2", function() {
const chain = buildConfigChain({
filename: fixture("dir2", "src.js"),
});
@ -114,9 +108,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -125,9 +117,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"dir2",
],
plugins: ["dir2"],
},
alias: fixture("dir2", ".babelrc"),
loc: fixture("dir2", ".babelrc"),
@ -147,7 +137,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("dir3", function () {
it("dir3", function() {
const chain = buildConfigChain({
filename: fixture("dir3", "src.js"),
});
@ -156,9 +146,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"extended",
],
plugins: ["extended"],
},
alias: fixture("extended.babelrc.json"),
loc: fixture("extended.babelrc.json"),
@ -167,9 +155,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"root",
],
plugins: ["root"],
},
alias: fixture(".babelrc"),
loc: fixture(".babelrc"),
@ -178,9 +164,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -200,7 +184,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("env - base", function () {
it("env - base", function() {
const chain = buildConfigChain({
filename: fixture("env", "src.js"),
});
@ -209,9 +193,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -220,9 +202,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"env-base",
],
plugins: ["env-base"],
},
alias: fixture("env", ".babelrc"),
loc: fixture("env", ".babelrc"),
@ -242,7 +222,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("env - foo", function () {
it("env - foo", function() {
process.env.NODE_ENV = "foo";
const chain = buildConfigChain({
@ -253,9 +233,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -264,9 +242,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"env-base",
],
plugins: ["env-base"],
},
alias: fixture("env", ".babelrc"),
loc: fixture("env", ".babelrc"),
@ -275,9 +251,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"env-foo",
],
plugins: ["env-foo"],
},
alias: fixture("env", ".babelrc.env.foo"),
loc: fixture("env", ".babelrc.env.foo"),
@ -297,7 +271,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("env - bar", function () {
it("env - bar", function() {
process.env.NODE_ENV = "foo"; // overridden
process.env.NODE_ENV = "bar";
@ -309,9 +283,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -320,9 +292,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"env-base",
],
plugins: ["env-base"],
},
alias: fixture("env", ".babelrc"),
loc: fixture("env", ".babelrc"),
@ -331,9 +301,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"env-bar",
],
plugins: ["env-bar"],
},
alias: fixture("env", ".babelrc.env.bar"),
loc: fixture("env", ".babelrc.env.bar"),
@ -353,8 +321,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("env - foo", function () {
it("env - foo", function() {
process.env.NODE_ENV = "foo";
const chain = buildConfigChain({
@ -394,7 +361,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("js-config", function () {
it("js-config", function() {
const chain = buildConfigChain({
filename: fixture("js-config", "src.js"),
});
@ -403,9 +370,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -414,10 +379,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"foo",
"bar",
],
plugins: ["foo", "bar"],
},
alias: fixture("js-config", ".babelrc.js"),
loc: fixture("js-config", ".babelrc.js"),
@ -437,7 +399,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("js-config-function", function () {
it("js-config-function", function() {
const chain = buildConfigChain({
filename: fixture("js-config-function", "src.js"),
});
@ -446,9 +408,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -477,7 +437,7 @@ describe("buildConfigChain", function () {
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({
filename: fixture("js-config-default", "src.js"),
});
@ -486,9 +446,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -497,10 +455,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"foo",
"bar",
],
plugins: ["foo", "bar"],
},
alias: fixture("js-config-default", ".babelrc.js"),
loc: fixture("js-config-default", ".babelrc.js"),
@ -519,7 +474,7 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("js-config-extended", function () {
it("js-config-extended", function() {
const chain = buildConfigChain({
filename: fixture("js-config-extended", "src.js"),
});
@ -528,9 +483,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -539,9 +492,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"extended",
],
plugins: ["extended"],
},
alias: fixture("extended.babelrc.json"),
loc: fixture("extended.babelrc.json"),
@ -550,10 +501,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
plugins: [
"foo",
"bar",
],
plugins: ["foo", "bar"],
},
alias: fixture("js-config-extended", ".babelrc.js"),
loc: fixture("js-config-extended", ".babelrc.js"),
@ -573,50 +521,49 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});
it("json-pkg-config-no-babel - should not throw if" +
" package.json doesn't contain a `babel` field", function () {
const chain = buildConfigChain({
filename: fixture("json-pkg-config-no-babel", "src.js"),
});
it(
"json-pkg-config-no-babel - should not throw if" +
" package.json doesn't contain a `babel` field",
function() {
const chain = buildConfigChain({
filename: fixture("json-pkg-config-no-babel", "src.js"),
});
const expected = [
{
type: "options",
options: {
ignore: [
"root-ignore",
],
const expected = [
{
type: "options",
options: {
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
dirname: fixture(),
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
dirname: fixture(),
},
{
type: "options",
options: {
plugins: [
"json",
],
{
type: "options",
options: {
plugins: ["json"],
},
alias: fixture("json-pkg-config-no-babel", ".babelrc"),
loc: fixture("json-pkg-config-no-babel", ".babelrc"),
dirname: fixture("json-pkg-config-no-babel"),
},
alias: fixture("json-pkg-config-no-babel", ".babelrc"),
loc: fixture("json-pkg-config-no-babel", ".babelrc"),
dirname: fixture("json-pkg-config-no-babel"),
},
{
type: "arguments",
options: {
filename: fixture("json-pkg-config-no-babel", "src.js"),
{
type: "arguments",
options: {
filename: fixture("json-pkg-config-no-babel", "src.js"),
},
alias: "base",
loc: "base",
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({
filename: fixture("ignore-negate", "src.js"),
});
@ -625,9 +572,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -636,10 +581,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"*",
"!src.js",
],
ignore: ["*", "!src.js"],
},
alias: fixture("ignore-negate", ".babelrc"),
loc: fixture("ignore-negate", ".babelrc"),
@ -665,7 +607,7 @@ describe("buildConfigChain", function () {
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({
filename: fixture("ignore-negate-folder", "folder", "src.js"),
});
@ -674,9 +616,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"root-ignore",
],
ignore: ["root-ignore"],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
@ -685,10 +625,7 @@ describe("buildConfigChain", function () {
{
type: "options",
options: {
ignore: [
"*",
"!folder",
],
ignore: ["*", "!folder"],
},
alias: fixture("ignore-negate-folder", ".babelrc"),
loc: fixture("ignore-negate-folder", ".babelrc"),
@ -714,83 +651,71 @@ describe("buildConfigChain", function () {
assert.equal(chain2, null);
});
it("js-json-config - should throw an error if both a .babelrc" +
" and a .babelrc.js are present", function () {
assert.throws(
function () {
it(
"js-json-config - should throw an error if both a .babelrc" +
" and a .babelrc.js are present",
function() {
assert.throws(function() {
buildConfigChain({
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" +
" and a package.json with a babel field are present", function () {
assert.throws(
function () {
it(
"js-pkg-config - should throw an error if both a .babelrc.js" +
" and a package.json with a babel field are present",
function() {
assert.throws(function() {
buildConfigChain({
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" +
" and a package.json with a babel field are present", function () {
assert.throws(
function () {
it(
"json-pkg-config - should throw an error if both a .babelrc" +
" and a package.json with a babel field are present",
function() {
assert.throws(function() {
buildConfigChain({
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 () {
assert.throws(
function () {
buildConfigChain({
filename: fixture("js-config-error", "src.js"),
});
},
/Error while loading config/
);
it("js-config-error2", function() {
assert.throws(function() {
buildConfigChain({
filename: fixture("js-config-error2", "src.js"),
});
}, /Configuration should be an exported JavaScript object/);
});
it("js-config-error2", function () {
assert.throws(
function () {
buildConfigChain({
filename: fixture("js-config-error2", "src.js"),
});
},
/Configuration should be an exported JavaScript object/
);
it("js-config-error3", function() {
assert.throws(function() {
buildConfigChain({
filename: fixture("js-config-error3", "src.js"),
});
}, /Configuration should be an exported JavaScript object/);
});
it("js-config-error3", function () {
assert.throws(
function () {
buildConfigChain({
filename: fixture("js-config-error3", "src.js"),
});
},
/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/
);
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 { parse } from "babylon";
describe("evaluation", function () {
describe("evaluation", function() {
function addTest(code, type, value, notConfident) {
it(type + ": " + code, function () {
it(type + ": " + code, function() {
const visitor = {};
visitor[type] = function (path) {
visitor[type] = function(path) {
const evaluate = path.evaluate();
assert.equal(evaluate.confident, !notConfident);
assert.deepEqual(evaluate.value, value);
};
traverse(parse(code, {
plugins: ["*"],
}), visitor);
traverse(
parse(code, {
plugins: ["*"],
}),
visitor,
);
});
}
@ -56,14 +59,39 @@ describe("evaluation", function () {
addTest("'abc' === 'xyz' || 1 === 1", "LogicalExpression", true);
addTest("'abc' === 'xyz' || 1 === 10", "LogicalExpression", false);
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("obj.a === 'abc' && 1 === 1", "LogicalExpression", undefined, true);
addTest("'abc' === 'abc' && (1 === 1 || config.flag)", "LogicalExpression", 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(
"'abc' === 'abc' && (1 === 1 || config.flag)",
"LogicalExpression",
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("({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", () => {
return assert.throws(() => {
manageOptions({
plugins: [
({ Plugin }) => new Plugin("object-assign", {}),
],
plugins: [({ Plugin }) => new Plugin("object-assign", {})],
});
}, /Babel 5 plugin is being run with Babel 6/);
});
describe("mergeOptions", () => {
it("throws for removed babel 5 options", () => {
return assert.throws(
() => {
manageOptions({
"randomOption": true,
});
},
/Unknown option: base.randomOption/
);
return assert.throws(() => {
manageOptions({
randomOption: true,
});
}, /Unknown option: base.randomOption/);
});
it("throws for removed babel 5 options", () => {
return assert.throws(
() => {
manageOptions({
"auxiliaryComment": true,
"blacklist": true,
auxiliaryComment: true,
blacklist: true,
});
},
// 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", () => {
return assert.throws(
() => {
manageOptions({
"presets": [path.join(__dirname, "fixtures/option-manager/not-a-preset")],
});
},
/While processing: .*option-manager(?:\/|\\\\)not-a-preset\.js/
);
return assert.throws(() => {
manageOptions({
presets: [
path.join(__dirname, "fixtures/option-manager/not-a-preset"),
],
});
}, /While processing: .*option-manager(?:\/|\\\\)not-a-preset\.js/);
});
});
describe("presets", function () {
describe("presets", function() {
function presetTest(name) {
it(name, function () {
it(name, function() {
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));
@ -65,10 +61,16 @@ describe("option-manager", () => {
}
function presetThrowsTest(name, msg) {
it(name, function () {
assert.throws(() => manageOptions({
"presets": [path.join(__dirname, "fixtures/option-manager/presets", name)],
}), msg);
it(name, function() {
assert.throws(
() =>
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_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("es5_invalid", /Unsupported format: string/);
});

View File

@ -2,152 +2,172 @@ import { transform } from "../lib/index";
import Plugin from "../lib/config/plugin";
import chai from "chai";
describe("traversal path", function () {
it("replaceWithSourceString", function () {
describe("traversal path", function() {
it("replaceWithSourceString", function() {
const expectCode = "function foo() {}";
const actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
FunctionDeclaration: function (path) {
path.replaceWithSourceString("console.whatever()");
plugins: [
new Plugin({
visitor: {
FunctionDeclaration: function(path) {
path.replaceWithSourceString("console.whatever()");
},
},
},
})],
}),
],
}).code;
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 actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
ArrowFunctionExpression: function (path) {
path.get("body").replaceWith({
type: "BlockStatement",
body: [{
type: "ReturnStatement",
argument: {
type: "BooleanLiteral",
value: true,
},
}],
});
plugins: [
new Plugin({
visitor: {
ArrowFunctionExpression: function(path) {
path.get("body").replaceWith({
type: "BlockStatement",
body: [
{
type: "ReturnStatement",
argument: {
type: "BooleanLiteral",
value: true,
},
},
],
});
},
},
},
})],
}),
],
}).code;
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 actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
ArrowFunctionExpression: function (path) {
path.get("body").replaceWith({
type: "BooleanLiteral",
value: true,
});
plugins: [
new Plugin({
visitor: {
ArrowFunctionExpression: function(path) {
path.get("body").replaceWith({
type: "BooleanLiteral",
value: true,
});
},
},
},
})],
}),
],
}).code;
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 actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
ForInStatement: function (path) {
path.get("left").replaceWith({
type: "VariableDeclaration",
kind: "var",
declarations: [{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "KEY",
},
}],
});
plugins: [
new Plugin({
visitor: {
ForInStatement: function(path) {
path.get("left").replaceWith({
type: "VariableDeclaration",
kind: "var",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "KEY",
},
},
],
});
},
},
},
})],
}),
],
}).code;
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 actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
ForInStatement: function (path) {
path.get("left").replaceWith({
type: "Identifier",
name: "KEY",
});
plugins: [
new Plugin({
visitor: {
ForInStatement: function(path) {
path.get("left").replaceWith({
type: "Identifier",
name: "KEY",
});
},
},
},
})],
}),
],
}).code;
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 actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
ForStatement: function (path) {
path.get("init").replaceWith({
type: "VariableDeclaration",
kind: "var",
declarations: [{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "KEY",
},
}],
});
plugins: [
new Plugin({
visitor: {
ForStatement: function(path) {
path.get("init").replaceWith({
type: "VariableDeclaration",
kind: "var",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "KEY",
},
},
],
});
},
},
},
})],
}),
],
}).code;
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 actualCode = transform(expectCode, {
plugins: [new Plugin({
visitor: {
ForStatement: function (path) {
path.get("init").replaceWith({
type: "Identifier",
name: "KEY",
});
plugins: [
new Plugin({
visitor: {
ForStatement: function(path) {
path.get("init").replaceWith({
type: "Identifier",
name: "KEY",
});
},
},
},
})],
}),
],
}).code;
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 path from "path";
describe("addon resolution", function () {
describe("addon resolution", function() {
const base = path.join(__dirname, "fixtures", "resolution");
beforeEach(function() {
@ -20,9 +20,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"module:preset",
],
presets: ["module:preset"],
});
});
@ -32,9 +30,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"module:plugin",
],
plugins: ["module:plugin"],
});
});
@ -44,9 +40,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"mod",
],
presets: ["mod"],
});
});
@ -56,9 +50,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"mod",
],
plugins: ["mod"],
});
});
@ -68,9 +60,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"babel-preset-mod",
],
presets: ["babel-preset-mod"],
});
});
@ -80,9 +70,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"babel-plugin-mod",
],
plugins: ["babel-plugin-mod"],
});
});
@ -92,9 +80,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"@babel/foo",
],
presets: ["@babel/foo"],
});
});
@ -104,9 +90,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"@babel/foo",
],
plugins: ["@babel/foo"],
});
});
@ -116,9 +100,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"@babel/preset-foo",
],
presets: ["@babel/preset-foo"],
});
});
@ -128,9 +110,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"@babel/plugin-foo",
],
plugins: ["@babel/plugin-foo"],
});
});
@ -140,9 +120,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"@foo/mod",
],
presets: ["@foo/mod"],
});
});
@ -152,9 +130,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"@foo/mod",
],
plugins: ["@foo/mod"],
});
});
@ -164,9 +140,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"@foo/babel-preset-mod",
],
presets: ["@foo/babel-preset-mod"],
});
});
@ -176,9 +150,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"@foo/babel-plugin-mod",
],
plugins: ["@foo/babel-plugin-mod"],
});
});
@ -188,9 +160,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"./dir/preset.js",
],
presets: ["./dir/preset.js"],
});
});
@ -200,9 +170,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"./dir/plugin.js",
],
plugins: ["./dir/plugin.js"],
});
});
@ -212,9 +180,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"mod/preset",
],
presets: ["mod/preset"],
});
});
@ -224,9 +190,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"mod/plugin",
],
plugins: ["mod/plugin"],
});
});
@ -236,9 +200,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"@foo/mod/preset",
],
presets: ["@foo/mod/preset"],
});
});
@ -248,9 +210,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"@foo/mod/plugin",
],
plugins: ["@foo/mod/plugin"],
});
});
@ -260,9 +220,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"@babel/mod/preset",
],
presets: ["@babel/mod/preset"],
});
});
@ -272,9 +230,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"@babel/mod/plugin",
],
plugins: ["@babel/mod/plugin"],
});
});
@ -285,9 +241,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"foo",
],
presets: ["foo"],
});
// eslint-disable-next-line max-len
}, /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("", {
filename: "filename.js",
babelrc: false,
plugins: [
"foo",
],
plugins: ["foo"],
});
// eslint-disable-next-line max-len
}, /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("", {
filename: "filename.js",
babelrc: false,
presets: [
"foo",
],
presets: ["foo"],
});
// eslint-disable-next-line max-len
}, /Cannot find module 'babel-preset-foo'.*\n- Did you mean "@babel\/foo"\?/);
@ -330,9 +280,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"foo",
],
plugins: ["foo"],
});
// eslint-disable-next-line max-len
}, /Cannot find module 'babel-plugin-foo'.*\n- Did you mean "@babel\/foo"\?/);
@ -345,9 +293,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
presets: [
"testplugin",
],
presets: ["testplugin"],
});
// eslint-disable-next-line max-len
}, /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("", {
filename: "filename.js",
babelrc: false,
plugins: [
"testpreset",
],
plugins: ["testpreset"],
});
// eslint-disable-next-line max-len
}, /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("", {
filename: "filename.js",
babelrc: false,
presets: [
"foo",
],
presets: ["foo"],
});
}, /Cannot find module 'babel-preset-foo'/);
});
@ -389,9 +331,7 @@ describe("addon resolution", function () {
babel.transform("", {
filename: "filename.js",
babelrc: false,
plugins: [
"foo",
],
plugins: ["foo"],
});
}, /Cannot find module 'babel-plugin-foo'/);
});

View File

@ -54,7 +54,7 @@ export default class Buffer {
configurable: true,
enumerable: true,
get() {
return this.map = map.get();
return (this.map = map.get());
},
set(value) {
Object.defineProperty(this, "map", { value, writable: true });
@ -81,7 +81,11 @@ export default class Buffer {
queue(str: string): void {
// 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;
this._queue.unshift([str, line, column, identifierName, filename]);
@ -89,13 +93,26 @@ export default class Buffer {
_flush(): void {
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 (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);
@ -112,11 +129,15 @@ export default class Buffer {
}
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 {
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 {
@ -133,7 +154,8 @@ export default class Buffer {
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) {
return end.slice(-suffix.length) === suffix;
}
@ -157,10 +179,10 @@ export default class Buffer {
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.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 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 {

View File

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

View File

@ -159,7 +159,10 @@ export function FunctionTypeAnnotation(node: Object, parent: Object) {
this.token(")");
// 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(":");
} else {
this.space();
@ -183,7 +186,10 @@ export function InterfaceExtends(node: Object) {
this.print(node.typeParameters, node);
}
export { InterfaceExtends as ClassImplements, InterfaceExtends as GenericTypeAnnotation };
export {
InterfaceExtends as ClassImplements,
InterfaceExtends as GenericTypeAnnotation,
};
export function _interfaceish(node: Object) {
this.print(node.id, node);

View File

@ -4,7 +4,7 @@ export function _params(node: Object) {
this.print(node.typeParameters, node);
this.token("(");
this.printList(node.params, node, {
iterator: (node) => {
iterator: node => {
if (node.optional) this.token("?");
this.print(node.typeAnnotation, node);
},
@ -79,7 +79,11 @@ export function ArrowFunctionExpression(node: Object) {
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);
} else {
this._params(node);
@ -93,6 +97,11 @@ export function ArrowFunctionExpression(node: Object) {
}
function hasTypes(node, param) {
return node.typeParameters || node.returnType || param.typeAnnotation || param.optional ||
param.trailingComments;
return (
node.typeParameters ||
node.returnType ||
param.typeAnnotation ||
param.optional ||
param.trailingComments
);
}

View File

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

View File

@ -17,7 +17,8 @@ export function IfStatement(node: Object) {
this.token(")");
this.space();
const needsBlock = node.alternate && t.isIfStatement(getLastStatement(node.consequent));
const needsBlock =
node.alternate && t.isIfStatement(getLastStatement(node.consequent));
if (needsBlock) {
this.token("{");
this.newline();
@ -80,8 +81,8 @@ export function WhileStatement(node: Object) {
this.printBlock(node);
}
const buildForXStatement = function (op) {
return function (node: Object) {
const buildForXStatement = function(op) {
return function(node: Object) {
this.word("for");
this.space();
if (op === "of" && node.await) {
@ -116,7 +117,7 @@ export function DoWhileStatement(node: Object) {
}
function buildLabelStatement(prefix, key = "label") {
return function (node: Object) {
return function(node: Object) {
this.word(prefix);
const label = node[key];
@ -261,7 +262,10 @@ export function VariableDeclaration(node: Object, parent: Object) {
let separator;
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);
}
export {
RestElement as SpreadElement,
};
export { RestElement as SpreadElement };
export function ObjectExpression(node: Object) {
const props = node.properties;
@ -45,8 +43,11 @@ export function ObjectProperty(node: Object) {
this.token("]");
} else {
// print `({ foo: foo = 5 } = {})` as `({ foo = 5 } = {});`
if (t.isAssignmentPattern(node.value) && t.isIdentifier(node.key) &&
node.key.name === node.value.left.name) {
if (
t.isAssignmentPattern(node.value) &&
t.isIdentifier(node.key) &&
node.key.name === node.value.left.name
) {
this.print(node.value, node);
return;
}
@ -54,10 +55,12 @@ export function ObjectProperty(node: Object) {
this.print(node.key, node);
// shorthand!
if (node.shorthand &&
if (
node.shorthand &&
(t.isIdentifier(node.key) &&
t.isIdentifier(node.value) &&
node.key.name === node.value.name)) {
t.isIdentifier(node.value) &&
node.key.name === node.value.name)
) {
return;
}
}
@ -111,7 +114,7 @@ export function NumericLiteral(node: Object) {
const raw = this.getPossibleRaw(node);
const value = node.value + "";
if (raw == null) {
this.number(value); // normalize
this.number(value); // normalize
} else if (this.format.minified) {
this.number(raw.length < value.length ? raw : value);
} else {

View File

@ -61,17 +61,23 @@ function normalizeOptions(code, opts): Format {
if (format.minified) {
format.compact = true;
format.shouldPrintComment = format.shouldPrintComment || (() => format.comments);
format.shouldPrintComment =
format.shouldPrintComment || (() => format.comments);
} else {
format.shouldPrintComment = format.shouldPrintComment || ((value) => format.comments ||
(value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0));
format.shouldPrintComment =
format.shouldPrintComment ||
(value =>
format.comments ||
(value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0));
}
if (format.compact === "auto") {
format.compact = code.length > 500_000; // 500KB
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);
return gen.generate();
}

View File

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

View File

@ -38,11 +38,19 @@ export function UpdateExpression(node: Object, parent: Object): boolean {
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 });
}
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);
}
@ -55,7 +63,8 @@ export function Binary(node: Object, parent: Object): boolean {
}
if (
((t.isCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node) ||
((t.isCallExpression(parent) || t.isNewExpression(parent)) &&
parent.callee === node) ||
t.isUnaryLike(parent) ||
(t.isMemberExpression(parent) && parent.object === node) ||
t.isAwaitExpression(parent)
@ -72,7 +81,9 @@ export function Binary(node: Object, parent: Object): boolean {
if (
// 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
) {
return true;
@ -85,11 +96,13 @@ export function Binary(node: Object, parent: Object): boolean {
export function BinaryExpression(node: Object, parent: Object): boolean {
// let i = (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 {
if (
// Although parentheses wouldn"t hurt around sequence
// 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 {
return t.isBinary(parent) ||
t.isUnaryLike(parent) ||
t.isCallExpression(parent) ||
t.isMemberExpression(parent) ||
t.isNewExpression(parent) ||
(t.isConditionalExpression(parent) && node === parent.test);
return (
t.isBinary(parent) ||
t.isUnaryLike(parent) ||
t.isCallExpression(parent) ||
t.isMemberExpression(parent) ||
t.isNewExpression(parent) ||
(t.isConditionalExpression(parent) && node === parent.test)
);
}
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 });
}
export function UnaryLike(node: Object, parent: Object): boolean {
return t.isMemberExpression(parent, { object: node }) ||
t.isCallExpression(parent, { callee: node }) ||
t.isNewExpression(parent, { callee: node }) ||
t.isBinaryExpression(parent, { operator: "**", left: node });
return (
t.isMemberExpression(parent, { object: node }) ||
t.isCallExpression(parent, { callee: 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 });
}
@ -167,10 +191,10 @@ export function AssignmentExpression(node: Object): boolean {
// Walk up the print stack to deterimine if our node can come first
// in statement.
function isFirstInStatement(printStack: Array<Object>, {
considerArrow = false,
considerDefaultExports = false,
} = {}): boolean {
function isFirstInStatement(
printStack: Array<Object>,
{ considerArrow = false, considerDefaultExports = false } = {},
): boolean {
let i = printStack.length - 1;
let node = printStack[i];
i--;
@ -179,8 +203,9 @@ function isFirstInStatement(printStack: Array<Object>, {
if (
t.isExpressionStatement(parent, { expression: node }) ||
t.isTaggedTemplateExpression(parent) ||
considerDefaultExports && t.isExportDefaultDeclaration(parent, { declaration: node }) ||
considerArrow && t.isArrowFunctionExpression(parent, { body: node })
(considerDefaultExports &&
t.isExportDefaultDeclaration(parent, { declaration: node })) ||
(considerArrow && t.isArrowFunctionExpression(parent, { body: node }))
) {
return true;
}

View File

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

View File

@ -14,21 +14,21 @@ const ZERO_DECIMAL_INTEGER = /\.0+$/;
const NON_DECIMAL_LITERAL = /^0[box]/;
export type Format = {
shouldPrintComment: (comment: string) => boolean;
retainLines: boolean;
retainFunctionParens: boolean;
comments: boolean;
auxiliaryCommentBefore: string;
auxiliaryCommentAfter: string;
compact: boolean | "auto";
minified: boolean;
quotes: "single" | "double";
concise: boolean;
shouldPrintComment: (comment: string) => boolean,
retainLines: boolean,
retainFunctionParens: boolean,
comments: boolean,
auxiliaryCommentBefore: string,
auxiliaryCommentAfter: string,
compact: boolean | "auto",
minified: boolean,
quotes: "single" | "double",
concise: boolean,
indent: {
adjustMultilineComment: boolean;
style: string;
base: number;
}
adjustMultilineComment: boolean,
style: string,
base: number,
},
};
export default class Printer {
@ -107,7 +107,10 @@ export default class Printer {
space(force: boolean = false): void {
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();
}
}
@ -149,14 +152,14 @@ export default class Printer {
token(str: string): void {
// space is mandatory to avoid outputting <!--
// 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`
(str[0] === "+" && this.endsWith("+")) ||
(str[0] === "-" && this.endsWith("-")) ||
// 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();
}
@ -294,9 +297,9 @@ export default class Printer {
*/
startTerminatorless(): Object {
return this._parenPushNewlineState = {
return (this._parenPushNewlineState = {
printed: false,
};
});
}
/**
@ -322,7 +325,11 @@ export default class Printer {
const printMethod = this[node.type];
if (!printMethod) {
// 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);
@ -335,7 +342,8 @@ export default class Printer {
if (
this.format.retainFunctionParens &&
node.type === "FunctionExpression" &&
node.extra && node.extra.parenthesized
node.extra &&
node.extra.parenthesized
) {
needsParens = true;
}
@ -343,7 +351,7 @@ export default class Printer {
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[node.type](node, parent);
});
@ -392,7 +400,12 @@ export default class Printer {
getPossibleRaw(node) {
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;
}
}
@ -490,14 +503,24 @@ export default class Printer {
// user node
if (leading) {
const comments = node.leadingComments;
const comment = comments && find(comments, (comment) =>
!!comment.loc && this.format.shouldPrintComment(comment.value));
const comment =
comments &&
find(
comments,
comment =>
!!comment.loc && this.format.shouldPrintComment(comment.value),
);
lines = this._whitespace.getNewlinesBefore(comment || node);
} else {
const comments = node.trailingComments;
const comment = comments && findLast(comments, (comment) =>
!!comment.loc && this.format.shouldPrintComment(comment.value));
const comment =
comments &&
findLast(
comments,
comment =>
!!comment.loc && this.format.shouldPrintComment(comment.value),
);
lines = this._whitespace.getNewlinesAfter(comment || node);
}
@ -520,7 +543,9 @@ export default class Printer {
_getComments(leading, node) {
// Note, we use a boolean flag here instead of passing in the attribute name as it is faster
// because this is called extremely frequently.
return (node && (leading ? node.leadingComments : node.trailingComments)) || [];
return (
(node && (leading ? node.leadingComments : node.trailingComments)) || []
);
}
_printComment(comment) {
@ -539,21 +564,32 @@ export default class Printer {
}
// 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();
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;
if (offset) {
const newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
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)}`);
}
@ -565,9 +601,11 @@ export default class Printer {
});
// whitespace after
this.newline((this._whitespace ? this._whitespace.getNewlinesAfter(comment) : 0) +
// Subtract one to account for the line force-added above.
(comment.type === "CommentLine" ? -1 : 0));
this.newline(
(this._whitespace ? this._whitespace.getNewlinesAfter(comment) : 0) +
// Subtract one to account for the line force-added above.
(comment.type === "CommentLine" ? -1 : 0),
);
}
_printComments(comments?: Array<Object>) {

View File

@ -18,16 +18,16 @@ export default class SourceMap {
get() {
if (!this._cachedMap) {
const map = this._cachedMap = new sourceMap.SourceMapGenerator({
const map = (this._cachedMap = new sourceMap.SourceMapGenerator({
file: this._opts.sourceMapTarget,
sourceRoot: this._opts.sourceRoot,
});
}));
const code = this._code;
if (typeof code === "string") {
map.setSourceContent(this._opts.sourceFileName, code);
} else if (typeof code === "object") {
Object.keys(code).forEach((sourceFileName) => {
Object.keys(code).forEach(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
// the previous one covers it.
if (this._lastGenLine === generatedLine && this._lastSourceLine === line &&
this._lastSourceColumn === column) {
if (
this._lastGenLine === generatedLine &&
this._lastSourceLine === line &&
this._lastSourceColumn === column
) {
return;
}
@ -80,10 +83,13 @@ export default class SourceMap {
column: generatedColumn,
},
source: line == null ? undefined : filename || this._opts.sourceFileName,
original: line == null ? undefined : {
line: line,
column: column,
},
original:
line == null
? undefined
: {
line: line,
column: column,
},
});
}
}

View File

@ -17,7 +17,11 @@ export default class Whitespace {
let endToken;
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) {
while (index && node.start === tokens[index - 1].start) --index;
startToken = tokens[index - 1];
@ -36,7 +40,11 @@ export default class Whitespace {
let endToken;
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) {
while (index && node.end === tokens[index - 1].end) --index;
startToken = tokens[index];

View File

@ -9,125 +9,164 @@ import fs from "fs";
import path from "path";
import fixtures from "babel-helper-fixtures";
describe("generation", function () {
it("completeness", function () {
Object.keys(t.VISITOR_KEYS).forEach(function (type) {
describe("generation", function() {
it("completeness", function() {
Object.keys(t.VISITOR_KEYS).forEach(function(type) {
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;
assert.ok(t.VISITOR_KEYS[type], type + " should not exist");
});
});
it("multiple sources", function () {
it("multiple sources", function() {
const sources = {
"a.js": "function hi (msg) { console.log(msg); }\n",
"b.js": "hi('hello');\n",
};
const parsed = Object.keys(sources).reduce(function (_parsed, filename) {
_parsed[filename] = parse(sources[filename], { sourceFilename: filename });
const parsed = Object.keys(sources).reduce(function(_parsed, filename) {
_parsed[filename] = parse(sources[filename], {
sourceFilename: filename,
});
return _parsed;
}, {});
const combinedAst = {
"type": "File",
"program": {
"type": "Program",
"sourceType": "module",
"body": [].concat(parsed["a.js"].program.body, parsed["b.js"].program.body),
type: "File",
program: {
type: "Program",
sourceType: "module",
body: [].concat(
parsed["a.js"].program.body,
parsed["b.js"].program.body,
),
},
};
const generated = generate(combinedAst, { sourceMaps: true }, sources);
chai.expect(generated.map).to.deep.equal({
version: 3,
sources: [ "a.js", "b.js" ],
mappings: "AAAA,SAASA,EAAT,CAAaC,GAAb,EAAkB;AAAEC,UAAQC,GAAR,CAAYF,GAAZ;AAAmB;;ACAvCD,GAAG,OAAH",
names: [
"hi",
"msg",
"console",
"log",
],
sourcesContent: [
"function hi (msg) { console.log(msg); }\n",
"hi('hello');\n",
],
}, "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.map).to.deep.equal(
{
version: 3,
sources: ["a.js", "b.js"],
mappings:
"AAAA,SAASA,EAAT,CAAaC,GAAb,EAAkB;AAAEC,UAAQC,GAAR,CAAYF,GAAZ;AAAmB;;ACAvCD,GAAG,OAAH",
names: ["hi", "msg", "console", "log"],
sourcesContent: [
"function hi (msg) { console.log(msg); }\n",
"hi('hello');\n",
],
},
"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",
);
});
it("identifierName", function () {
it("identifierName", function() {
const code = "function foo() { bar; }\n";
const ast = parse(code, { filename: "inline" }).program;
@ -141,51 +180,75 @@ describe("generation", function () {
id2.name += "2";
id2.loc.identiferName = "bar";
const generated = generate(ast, {
filename: "inline",
sourceFileName: "inline",
sourceMaps: true,
}, code);
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"
const generated = generate(
ast,
{
filename: "inline",
sourceFileName: "inline",
sourceMaps: true,
},
code,
);
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() {
@ -199,17 +262,22 @@ describe("generation", function () {
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");
});
});
describe("programmatic generation", function() {
it("numeric member expression", function() {
// 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);
});
@ -220,10 +288,10 @@ describe("programmatic generation", function() {
t.stringLiteral("while cond"),
t.ifStatement(
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);
@ -233,35 +301,22 @@ describe("programmatic generation", function() {
it("prints directives in block with empty body", function() {
const blockStatement = t.blockStatement(
[],
[t.directive(t.directiveLiteral("use strict"))]
[t.directive(t.directiveLiteral("use strict"))],
);
const output = generate(blockStatement).code;
assert.equal(output, [
"{",
" \"use strict\";",
"}",
].join("\n"));
assert.equal(output, ["{", ' "use strict";', "}"].join("\n"));
});
it("flow object indentation", function() {
const objectStatement = t.objectTypeAnnotation(
[
t.objectTypeProperty(
t.identifier("bar"),
t.stringTypeAnnotation()
),
],
[t.objectTypeProperty(t.identifier("bar"), t.stringTypeAnnotation())],
null,
null,
null
);
const output = generate(objectStatement).code;
assert.equal(output, [
"{",
" bar: string,",
"}",
].join("\n"));
assert.equal(output, ["{", " bar: string,", "}"].join("\n"));
});
it("flow object indentation with empty leading ObjectTypeProperty", function() {
@ -273,21 +328,17 @@ describe("programmatic generation", function() {
t.anyTypeAnnotation(),
t.identifier("Test"),
),
]
],
);
const output = generate(objectStatement).code;
assert.equal(output, [
"{",
" [key: any]: Test,",
"}",
].join("\n"));
assert.equal(output, ["{", " [key: any]: Test,", "}"].join("\n"));
});
});
describe("whitespace", function () {
it("empty token list", function () {
describe("whitespace", function() {
it("empty token list", function() {
const w = new Whitespace([]);
assert.equal(w.getNewlinesBefore(t.stringLiteral("1")), 0);
});
@ -295,47 +346,55 @@ describe("whitespace", function () {
const suites = fixtures(`${__dirname}/fixtures`);
suites.forEach(function (testSuite) {
describe("generation/" + testSuite.title, function () {
testSuite.tests.forEach(function (task) {
it(task.title, !task.disabled && function () {
const expect = task.expect;
const actual = task.actual;
const actualCode = actual.code;
suites.forEach(function(testSuite) {
describe("generation/" + testSuite.title, function() {
testSuite.tests.forEach(function(task) {
it(
task.title,
!task.disabled &&
function() {
const expect = task.expect;
const actual = task.actual;
const actualCode = actual.code;
if (actualCode) {
const actualAst = parse(actualCode, {
filename: actual.loc,
plugins: [
"asyncGenerators",
"classProperties",
"decorators",
"doExpressions",
"dynamicImport",
"exportExtensions",
"flow",
"functionBind",
"functionSent",
"jsx",
"objectRestSpread",
"optionalChaining",
],
strictMode: false,
sourceType: "module",
});
const result = generate(actualAst, task.options, actualCode);
if (actualCode) {
const actualAst = parse(actualCode, {
filename: actual.loc,
plugins: [
"asyncGenerators",
"classProperties",
"decorators",
"doExpressions",
"dynamicImport",
"exportExtensions",
"flow",
"functionBind",
"functionSent",
"jsx",
"objectRestSpread",
"optionalChaining",
],
strictMode: false,
sourceType: "module",
});
const result = generate(actualAst, task.options, actualCode);
if (
!expect.code && result.code && fs.statSync(path.dirname(expect.loc)).isDirectory() &&
!process.env.CI
) {
console.log(`New test file created: ${expect.loc}`);
fs.writeFileSync(expect.loc, result.code);
} else {
chai.expect(result.code).to.be.equal(expect.code, actual.loc + " !== " + expect.loc);
}
}
});
if (
!expect.code &&
result.code &&
fs.statSync(path.dirname(expect.loc)).isDirectory() &&
!process.env.CI
) {
console.log(`New test file created: ${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 * 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) {
const decorator = decoratorPath.node;
const expression = decorator.expression;
@ -19,13 +21,15 @@ export default function bindifyDecorators(decorators: Array<NodePath>): Array<No
ref = expression.object;
}
nodes.push(t.callExpression(
t.memberExpression(
t.memberExpression(ref, expression.property, expression.computed),
t.identifier("bind")
nodes.push(
t.callExpression(
t.memberExpression(
t.memberExpression(ref, expression.property, expression.computed),
t.identifier("bind"),
),
[ref],
),
[ref]
));
);
if (nodes.length === 1) {
decorator.expression = nodes[0];

View File

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

View File

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

View File

@ -12,7 +12,13 @@ function toKind(node: Object) {
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);
//
@ -33,9 +39,11 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope
}
if (node.decorators) {
const decorators = map.decorators = map.decorators || t.arrayExpression([]);
const decorators = (map.decorators =
map.decorators || t.arrayExpression([]));
decorators.elements = decorators.elements.concat(
node.decorators.map((dec) => dec.expression).reverse());
node.decorators.map(dec => dec.expression).reverse(),
);
}
if (map.value || map.initializer) {
@ -45,14 +53,24 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope
let key, value;
// 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);
}
if (t.isObjectProperty(node) || t.isClassProperty(node)) {
value = node.value;
} 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;
}
@ -62,8 +80,12 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope
}
// infer function name
if (scope && t.isStringLiteral(key) && (kind === "value" || kind === "initializer") &&
t.isFunctionExpression(value)) {
if (
scope &&
t.isStringLiteral(key) &&
(kind === "value" || kind === "initializer") &&
t.isFunctionExpression(value)
) {
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++) {
const prop = obj.properties[i];
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);
}
@ -100,13 +124,13 @@ export function toComputedObjectFromClass(obj: Object): Object {
export function toClassObject(mutatorMap: Object): Object {
const objExpr = t.objectExpression([]);
Object.keys(mutatorMap).forEach(function (mutatorMapKey) {
Object.keys(mutatorMap).forEach(function(mutatorMapKey) {
const map = mutatorMap[mutatorMapKey];
const mapNode = t.objectExpression([]);
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];
if (key[0] === "_") return;
@ -127,7 +151,7 @@ export function toClassObject(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];
if (map.value) map.writable = 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)) {
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
// so as per the previous comment we can be 100% sure evaluating
// it multiple times will be safe
@ -32,9 +32,7 @@ function getObjRef(node, nodes, file, scope) {
}
const temp = scope.generateUidIdentifierBasedOnNode(ref);
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(temp, ref),
]));
nodes.push(t.variableDeclaration("var", [t.variableDeclarator(temp, ref)]));
return temp;
}
@ -44,21 +42,19 @@ function getPropRef(node, nodes, file, scope) {
if (t.isLiteral(key) && t.isPureish(key)) return key;
const temp = scope.generateUidIdentifierBasedOnNode(prop);
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(temp, prop),
]));
nodes.push(t.variableDeclaration("var", [t.variableDeclarator(temp, prop)]));
return temp;
}
export default function (
export default function(
node: Object,
nodes: Array<Object>,
file,
scope: Scope,
allowedSingleIdent?: boolean,
): {
uid: Object;
ref: Object;
uid: Object,
ref: Object,
} {
let obj;
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 * as t from "babel-types";
export default function (classPath) {
export default function(classPath) {
classPath.assertClass();
const memoisedExpressions = [];
@ -44,6 +44,8 @@ export default function (classPath) {
}
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 = {
loc: string;
code: string;
filename: string;
loc: string,
code: string,
filename: string,
};
type Test = {
title: string;
disabled: boolean;
options: Object;
exec: TestFile;
actual: TestFile;
expected: TestFile;
title: string,
disabled: boolean,
options: Object,
exec: TestFile,
actual: TestFile,
expected: TestFile,
};
type Suite = {
options: Object;
tests: Array<Test>;
title: string;
filename: string;
options: Object,
tests: Array<Test>,
title: string,
filename: string,
};
function assertDirectory(loc) {
@ -50,7 +50,9 @@ function shouldIgnore(name, blacklist?: Array<string>) {
const ext = path.extname(name);
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> {
@ -133,7 +135,9 @@ export default function get(entryLoc): Array<Suite> {
const minimumVersion = semver.clean(taskOpts.minNodeVersion);
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)) {

View File

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

View File

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

View File

@ -21,9 +21,11 @@ const visitor = {
firstId = declar.node.id;
if (declar.node.init) {
nodes.push(t.expressionStatement(
t.assignmentExpression("=", declar.node.id, declar.node.init)
));
nodes.push(
t.expressionStatement(
t.assignmentExpression("=", declar.node.id, declar.node.init),
),
);
}
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 });
}

View File

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

View File

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

View File

@ -48,13 +48,17 @@ const forAwaitVisitor = {
const callee = path.node.callee;
// 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]);
}
},
};
export default function (path, helpers) {
export default function(path, helpers) {
const { node, scope, parent } = path;
const stepKey = scope.generateUidIdentifier("step");
@ -64,7 +68,9 @@ export default function (path, helpers) {
if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) {
// 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)) {
// for await (let i of test)
declar = t.variableDeclaration(left.kind, [
@ -76,7 +82,9 @@ export default function (path, helpers) {
traverse(template, forAwaitVisitor, null, {
ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"),
ITERATOR_COMPLETION: scope.generateUidIdentifier("iteratorNormalCompletion"),
ITERATOR_COMPLETION: scope.generateUidIdentifier(
"iteratorNormalCompletion",
),
ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"),
ITERATOR_KEY: scope.generateUidIdentifier("iterator"),
GET_ITERATOR: helpers.getAsyncIterator,

View File

@ -70,7 +70,6 @@ const awaitVisitor = {
path.replaceWithMultiple(build.node);
}
},
};
function classOrObjectMethod(path: NodePath, callId: Object) {
@ -79,12 +78,16 @@ function classOrObjectMethod(path: NodePath, callId: Object) {
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 = [
t.returnStatement(t.callExpression(
t.callExpression(callId, [container]),
[]
)),
t.returnStatement(
t.callExpression(t.callExpression(callId, [container]), []),
),
];
// 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;
// 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) {
@ -121,25 +126,29 @@ function plainFunction(path: NodePath, callId: Object) {
NAME: asyncFnId || null,
REF: path.scope.generateUidIdentifier("ref"),
FUNCTION: built,
PARAMS: node.params.reduce((acc, param) => {
acc.done = acc.done || t.isAssignmentPattern(param) || t.isRestElement(param);
PARAMS: node.params.reduce(
(acc, param) => {
acc.done =
acc.done || t.isAssignmentPattern(param) || t.isRestElement(param);
if (!acc.done) {
acc.params.push(path.scope.generateUidIdentifier("x"));
}
if (!acc.done) {
acc.params.push(path.scope.generateUidIdentifier("x"));
}
return acc;
}, {
params: [],
done: false,
}).params,
return acc;
},
{
params: [],
done: false,
},
).params,
}).expression;
if (isDeclaration) {
const declar = t.variableDeclaration("let", [
t.variableDeclarator(
t.identifier(asyncFnId.name),
t.callExpression(container, [])
t.callExpression(container, []),
),
]);
declar._blockHoist = true;
@ -149,14 +158,12 @@ function plainFunction(path: NodePath, callId: Object) {
// the identifier into an expressionStatement
path.parentPath.insertBefore(declar);
path.parentPath.replaceWith(
t.exportNamedDeclaration(null,
[
t.exportSpecifier(
t.identifier(asyncFnId.name),
t.identifier("default")
),
]
)
t.exportNamedDeclaration(null, [
t.exportSpecifier(
t.identifier(asyncFnId.name),
t.identifier("default"),
),
]),
);
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) {
// bc for 6.15 and earlier
helpers = { wrapAsync: file };

View File

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

View File

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

View File

@ -38,7 +38,9 @@ runCodeInTestContext(buildExternalHelpers());
* This allows us to run our unittests
*/
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
// the context's global scope.
@ -46,20 +48,22 @@ function runModuleInTestContext(id: string, relativeFilename: string) {
if (moduleCache[filename]) return moduleCache[filename].exports;
const module = moduleCache[filename] = {
const module = (moduleCache[filename] = {
id: filename,
exports: {},
};
});
const dirname = path.dirname(filename);
const req = (id) => runModuleInTestContext(id, filename);
const req = id => runModuleInTestContext(id, filename);
const src = fs.readFileSync(filename, "utf8");
const code = `(function (exports, require, module, __filename, __dirname) {${src}\n});`;
vm.runInContext(code, testContext, {
filename,
displayErrors: true,
}).call(module.exports, module.exports, req, module, filename, dirname);
vm
.runInContext(code, testContext, {
filename,
displayErrors: true,
})
.call(module.exports, module.exports, req, module, filename, dirname);
return module.exports;
}
@ -69,10 +73,13 @@ function runModuleInTestContext(id: string, relativeFilename: string) {
*
* 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 dirname = filename ? path.dirname(filename) : null;
const req = filename ? ((id) => runModuleInTestContext(id, filename)) : null;
const req = filename ? id => runModuleInTestContext(id, filename) : null;
const module = {
id: filename,
@ -90,21 +97,21 @@ export function runCodeInTestContext(code: string, opts: {filename?: string} = {
}
function wrapPackagesArray(type, names, optionsDir) {
return (names || []).map(function (val) {
return (names || []).map(function(val) {
if (typeof val === "string") val = [val];
// relative path (outside of monorepo)
if (val[0][0] === ".") {
if (!optionsDir) {
throw new Error("Please provide an options.json in test dir when using a " +
"relative plugin path.");
throw new Error(
"Please provide an options.json in test dir when using a " +
"relative plugin path.",
);
}
val[0] = path.resolve(optionsDir, val[0]);
}
// check node_modules/babel-x-y
else {
} else {
// check node_modules/babel-x-y
val[0] = __dirname + "/../../babel-" + type + "-" + val[0];
}
@ -120,15 +127,25 @@ function run(task) {
const optionsDir = task.optionsDir;
function getOpts(self) {
const newOpts = merge({
filename: self.loc,
}, opts);
const newOpts = merge(
{
filename: self.loc,
},
opts,
);
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) {
throw new Error("Unexpected extra options " + JSON.stringify(val.slice(2)) +
" passed to preset.");
throw new Error(
"Unexpected extra options " +
JSON.stringify(val.slice(2)) +
" passed to preset.",
);
}
return val;
@ -160,14 +177,19 @@ function run(task) {
if (!execCode || actualCode) {
result = babel.transform(actualCode, getOpts(actual));
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
) {
console.log(`New test file created: ${expect.loc}`);
fs.writeFileSync(expect.loc, result.code);
} else {
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) {
const consumer = new sourceMap.SourceMapConsumer(result.map);
task.sourceMappings.forEach(function (mapping) {
task.sourceMappings.forEach(function(mapping) {
const actual = mapping.original;
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,
name: string,
suiteOpts = {},
@ -203,49 +227,59 @@ export default function (
for (const testSuite of suites) {
if (includes(suiteOpts.ignoreSuites, testSuite.title)) continue;
describe(name + "/" + testSuite.title, function () {
describe(name + "/" + testSuite.title, function() {
for (const task of testSuite.tests) {
if (includes(suiteOpts.ignoreTasks, task.title) ||
includes(suiteOpts.ignoreTasks, testSuite.title + "/" + task.title)) continue;
if (
includes(suiteOpts.ignoreTasks, task.title) ||
includes(suiteOpts.ignoreTasks, testSuite.title + "/" + task.title)
) {
continue;
}
it(task.title, !task.disabled && function () {
function runTask() {
run(task);
}
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;
it(
task.title,
!task.disabled &&
function() {
function runTask() {
run(task);
}
} 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(`
(function (subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
@ -395,7 +394,6 @@ helpers.instanceof = template(`
});
`);
helpers.interopRequireDefault = template(`
(function (obj) {
return obj && obj.__esModule ? obj : { default: obj };

View File

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

View File

@ -8,38 +8,55 @@ import * as util from "util";
*/
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",
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",
settersNoRest: "Setters aren't allowed to have a rest",
noAssignmentsInForHead: "No assignments allowed in for-in/of head",
expectedMemberExpressionOrIdentifier: "Expected type MemberExpression or Identifier",
invalidParentForThisNode: "We don't know how to handle this node within the current parent - please open an issue",
expectedMemberExpressionOrIdentifier:
"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",
unknownForHead: "Unknown node type $1 in ForStatement",
didYouMean: "Did you mean $1?",
codeGeneratorDeopt: "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",
codeGeneratorDeopt:
"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",
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",
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",
undeclaredVariableType: "Referencing a type alias outside of a type annotation",
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
undeclaredVariableType:
"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.",
traverseVerifyRootFunction: "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",
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.",
traverseVerifyRootFunction:
"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",
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",
pluginNotObject:
"Plugin $2 specified in $1 was expected to return an object when invoked but returned $3",
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",
};
@ -55,7 +72,7 @@ export function get(key: string, ...args: Array<any>): string {
args = parseArgs(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];
});
}
@ -65,7 +82,7 @@ export function get(key: string, ...args: Array<any>): string {
*/
export function parseArgs(args: Array<any>): Array<string> {
return args.map(function (val) {
return args.map(function(val) {
if (val != null && val.inspect) {
return val.inspect();
} else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";
import syntaxAsyncGenerators from "babel-plugin-syntax-async-generators";
export default function ({ types: t }) {
export default function({ types: t }) {
const yieldStarVisitor = {
Function(path) {
path.skip();
@ -12,7 +12,10 @@ export default function ({ types: t }) {
const callee = state.addHelper("asyncGeneratorDelegate");
node.argument = t.callExpression(callee, [
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, {
wrapAsync: t.memberExpression(
state.addHelper("asyncGenerator"), t.identifier("wrap")),
state.addHelper("asyncGenerator"),
t.identifier("wrap"),
),
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 syntaxAsyncFunctions from "babel-plugin-syntax-async-functions";
export default function () {
export default function() {
return {
inherits: syntaxAsyncFunctions,

View File

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

View File

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

View File

@ -15,7 +15,6 @@ const buildGetDescriptor = template(`
Object.getOwnPropertyDescriptor(TARGET, PROPERTY);
`);
const buildGetObjectInitializer = template(`
(TEMP = Object.getOwnPropertyDescriptor(TARGET, PROPERTY), (TEMP = TEMP ? TEMP.value : undefined), {
enumerable: true,
@ -88,7 +87,9 @@ export default function({ types: t }) {
*/
function ensureApplyDecoratedDescriptorHelper(path, state) {
if (!state.applyDecoratedDescriptor) {
state.applyDecoratedDescriptor = path.scope.generateUidIdentifier("applyDecoratedDescriptor");
state.applyDecoratedDescriptor = path.scope.generateUidIdentifier(
"applyDecoratedDescriptor",
);
const helper = buildApplyDecoratedDescriptor({
NAME: state.applyDecoratedDescriptor,
});
@ -103,7 +104,9 @@ export default function({ types: t }) {
*/
function ensureInitializerDefineProp(path, state) {
if (!state.initializerDefineProp) {
state.initializerDefineProp = path.scope.generateUidIdentifier("initDefineProp");
state.initializerDefineProp = path.scope.generateUidIdentifier(
"initDefineProp",
);
const helper = buildInitializerDefineProperty({
NAME: state.initializerDefineProp,
});
@ -119,7 +122,9 @@ export default function({ types: t }) {
*/
function ensureInitializerWarning(path, state) {
if (!state.initializerWarningHelper) {
state.initializerWarningHelper = path.scope.generateUidIdentifier("initializerWarningHelper");
state.initializerWarningHelper = path.scope.generateUidIdentifier(
"initializerWarningHelper",
);
const helper = buildInitializerWarningHelper({
NAME: state.initializerWarningHelper,
});
@ -135,20 +140,29 @@ export default function({ types: t }) {
*/
function applyEnsureOrdering(path) {
// TODO: This should probably also hoist computed properties.
const decorators = (
path.isClass()
const decorators = (path.isClass()
? [path].concat(path.get("body.body"))
: path.get("properties")
).reduce((acc, prop) => acc.concat(prop.node.decorators || []), []);
: path.get("properties")).reduce(
(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;
return t.sequenceExpression(identDecorators.map((decorator) => {
const expression = decorator.expression;
const id = decorator.expression = path.scope.generateDeclaredUidIdentifier("dec");
return t.assignmentExpression("=", id, expression);
}).concat([path.node]));
return t.sequenceExpression(
identDecorators
.map(decorator => {
const expression = decorator.expression;
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");
return decorators
.map((dec) => dec.expression)
.reverse()
.reduce(function(acc, decorator) {
return buildClassDecorator({
CLASS_REF: name,
DECORATOR: decorator,
INNER: acc,
}).expression;
}, classPath.node);
.map(dec => dec.expression)
.reverse()
.reduce(function(acc, decorator) {
return buildClassDecorator({
CLASS_REF: name,
DECORATOR: decorator,
INNER: acc,
}).expression;
}, classPath.node);
}
/**
@ -207,7 +221,9 @@ export default function({ types: t }) {
* A helper to pull out property decorators into a sequence expression.
*/
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 decorators = node.decorators || [];
@ -216,58 +232,79 @@ export default function({ types: t }) {
if (decorators.length === 0) return acc;
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({
CLASS_REF: name,
}).expression : name;
const target =
path.isClass() && !node.static
? buildClassPrototype({
CLASS_REF: name,
}).expression
: name;
if (t.isClassProperty(node, { static: false })) {
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 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(),
]);
acc = acc.concat([
t.assignmentExpression(
"=", descriptor, t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [
target,
property,
t.arrayExpression(decorators.map((dec) => dec.expression)),
t.objectExpression([
t.objectProperty(t.identifier("enumerable"), t.booleanLiteral(true)),
t.objectProperty(t.identifier("initializer"), initializer),
]),
])
"=",
descriptor,
t.callExpression(
ensureApplyDecoratedDescriptorHelper(path, state),
[
target,
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 {
acc = acc.concat(
t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [
target,
property,
t.arrayExpression(decorators.map((dec) => dec.expression)),
(
t.isObjectProperty(node) ||
t.isClassProperty(node, { static: true })) ?
buildGetObjectInitializer({
t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [
target,
property,
t.arrayExpression(decorators.map(dec => dec.expression)),
t.isObjectProperty(node) ||
t.isClassProperty(node, { static: true })
? buildGetObjectInitializer({
TEMP: path.scope.generateDeclaredUidIdentifier("init"),
TARGET: target,
PROPERTY: property,
}).expression : buildGetDescriptor({
}).expression
: buildGetDescriptor({
TARGET: target,
PROPERTY: property,
}
).expression,
target,
])
}).expression,
target,
]),
);
}
@ -289,35 +326,42 @@ export default function({ types: t }) {
if (!path.get("declaration").isClassDeclaration()) return;
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;
// Split the class declaration and the export into two separate statements.
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) {
const { node } = path;
const ref = node.id || path.scope.generateUidIdentifier("class");
path.replaceWith(t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)),
]));
path.replaceWith(
t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)),
]),
);
},
ClassExpression(path, state) {
// 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.
const decoratedClass = (
const decoratedClass =
applyEnsureOrdering(path) ||
applyClassDecorators(path, state) ||
applyMethodDecorators(path, state)
);
applyMethodDecorators(path, state);
if (decoratedClass) path.replaceWith(decoratedClass);
},
ObjectExpression(path, state) {
const decoratedObject = applyEnsureOrdering(path) || applyObjectDecorators(path, state);
const decoratedObject =
applyEnsureOrdering(path) || applyObjectDecorators(path, state);
if (decoratedObject) path.replaceWith(decoratedObject);
},
@ -328,14 +372,22 @@ export default function({ types: t }) {
if (!path.get("left").isMemberExpression()) return;
if (!path.get("left.property").isIdentifier()) 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.get("left.object").node,
t.stringLiteral(path.get("left.property").node.name),
path.get("right.arguments")[0].node,
path.get("right.arguments")[1].node,
]));
path.replaceWith(
t.callExpression(ensureInitializerDefineProp(path, state), [
path.get("left.object").node,
t.stringLiteral(path.get("left.property").node.name),
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";
export default function () {
export default function() {
return {
inherits: syntaxDoExpressions,

View File

@ -2,10 +2,13 @@
import type NodePath from "babel-traverse";
export default function () {
export default function() {
return {
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
// was queued up.
if (!path.isArrowFunctionExpression()) return;

View File

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

View File

@ -8,7 +8,7 @@ import values from "lodash/values";
import extend from "lodash/extend";
import template from "babel-template";
export default function () {
export default function() {
return {
visitor: {
VariableDeclaration(path, file) {
@ -44,20 +44,38 @@ export default function () {
Loop(path, file) {
const { node, parent, scope } = path;
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();
if (replace) path.replaceWith(replace);
},
CatchClause(path, file) {
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();
},
"BlockStatement|SwitchStatement|Program"(path, file) {
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();
}
},
@ -80,7 +98,13 @@ function isBlockScoped(node) {
return true;
}
function convertBlockScopedToVar(path, node, parent, scope, moveBindingsToParent = false) {
function convertBlockScopedToVar(
path,
node,
parent,
scope,
moveBindingsToParent = false,
) {
if (!node) {
node = path.node;
}
@ -111,41 +135,47 @@ function isVar(node) {
return t.isVariableDeclaration(node, { kind: "var" }) && !isBlockScoped(node);
}
const letReferenceBlockVisitor = traverse.visitors.merge([{
Loop: {
enter(path, state) {
state.loopDepth++;
const letReferenceBlockVisitor = traverse.visitors.merge([
{
Loop: {
enter(path, state) {
state.loopDepth++;
},
exit(path, state) {
state.loopDepth--;
},
},
exit(path, state) {
state.loopDepth--;
Function(path, state) {
// 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) {
// 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();
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 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]);
tdzVisitor,
]);
const hoistVarDeclarationsVisitor = {
enter(path, self) {
@ -166,7 +196,9 @@ const hoistVarDeclarationsVisitor = {
node.left = node.left.declarations[0].id;
}
} 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()) {
return path.skip();
}
@ -184,7 +216,12 @@ const continuationVisitor = {
if (path.isAssignmentExpression() || path.isUpdateExpression()) {
const bindings = path.getBindingIdentifiers();
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;
}
}
@ -252,7 +289,10 @@ const loopVisitor = {
if (path.isReturnStatement()) {
state.hasReturn = true;
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 {
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.scope = scope;
this.file = file;
@ -281,7 +327,8 @@ class BlockScoping {
if (loopPath) {
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.loop = loopPath.node;
}
@ -360,11 +407,13 @@ class BlockScoping {
// 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
// individually
if (scope.hasOwnBinding(key))
{scope.rename(ref.name);}
if (scope.hasOwnBinding(key)) {
scope.rename(ref.name);
}
if (this.blockPath.scope.hasOwnBinding(key))
{this.blockPath.scope.rename(ref.name);}
if (this.blockPath.scope.hasOwnBinding(key)) {
this.blockPath.scope.rename(ref.name);
}
}
}
}
@ -373,7 +422,7 @@ class BlockScoping {
if (this.file.opts.throwIfClosureRequired) {
throw this.blockPath.buildCodeFrameError(
"Compiling let/const in this block would add a closure " +
"(throwIfClosureRequired)."
"(throwIfClosureRequired).",
);
}
const block = this.block;
@ -385,7 +434,10 @@ class BlockScoping {
for (const name in outsideRefs) {
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 this.letReferences[id.name];
@ -411,8 +463,11 @@ class BlockScoping {
const isSwitch = this.blockPath.isSwitchStatement();
// build the closure that we're going to wrap the block with, possible wrapping switch(){}
const fn = t.functionExpression(null, params,
t.blockStatement(isSwitch ? [block] : block.body));
const fn = t.functionExpression(
null,
params,
t.blockStatement(isSwitch ? [block] : block.body),
);
// continuation
this.addContinuations(fn);
@ -421,7 +476,12 @@ class BlockScoping {
let basePath = ".callee";
// 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) {
fn.generator = true;
call = t.yieldExpression(call, true);
@ -429,7 +489,12 @@ class BlockScoping {
}
// 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) {
fn.async = true;
call = t.awaitExpression(call);
@ -441,9 +506,9 @@ class BlockScoping {
if (this.has.hasReturn || this.has.hasBreakContinue) {
const ret = this.scope.generateUidIdentifier("ret");
this.body.push(t.variableDeclaration("var", [
t.variableDeclarator(ret, call),
]));
this.body.push(
t.variableDeclaration("var", [t.variableDeclarator(ret, call)]),
);
placeholderPath = "declarations.0.init" + basePath;
index = this.body.length - 1;
@ -471,9 +536,9 @@ class BlockScoping {
let fnPath;
if (this.loop) {
const ref = this.scope.generateUidIdentifier("loop");
const p = this.loopPath.insertBefore(t.variableDeclaration("var", [
t.variableDeclarator(ref, fn),
]));
const p = this.loopPath.insertBefore(
t.variableDeclaration("var", [t.variableDeclarator(ref, fn)]),
);
placeholder.replaceWith(ref);
fnPath = p[0].get("declarations.0.init");
@ -512,7 +577,9 @@ class BlockScoping {
this.scope.rename(param.name, newParam.name, fn);
// 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) => {
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)) {
convertBlockScopedToVar(path, node, block, this.scope);
}
@ -585,7 +656,7 @@ class BlockScoping {
};
const loopOrFunctionParent = this.blockPath.find(
(path) => path.isLoop() || path.isFunction()
path => path.isLoop() || path.isFunction(),
);
if (loopOrFunctionParent && loopOrFunctionParent.isLoop()) {
// There is a loop ancestor closer than the closest function, so we
@ -686,18 +757,20 @@ class BlockScoping {
if (cases.length === 1) {
const single = cases[0];
body.push(t.ifStatement(
t.binaryExpression("===", ret, single.test),
single.consequent[0]
));
body.push(
t.ifStatement(
t.binaryExpression("===", ret, single.test),
single.consequent[0],
),
);
} else {
if (this.loop) {
// https://github.com/babel/babel/issues/998
for (let i = 0; i < cases.length; i++) {
const caseConsequent = cases[i].consequent[0];
if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) {
caseConsequent.label = this.loopLabel = this.loopLabel ||
this.scope.generateUidIdentifier("loop");
caseConsequent.label = this.loopLabel =
this.loopLabel || this.scope.generateUidIdentifier("loop");
}
}
}

View File

@ -13,10 +13,11 @@ function getTDZStatus(refPath, bindingPath) {
}
function buildTDZAssert(node, file) {
return t.callExpression(
file.addHelper("temporalRef"),
[node, t.stringLiteral(node.name), file.addHelper("temporalUndefined")]
);
return t.callExpression(file.addHelper("temporalRef"), [
node,
t.stringLiteral(node.name),
file.addHelper("temporalUndefined"),
]);
}
function isReference(node, scope, state) {
@ -56,12 +57,18 @@ export const visitor = {
path.replaceWith(assert);
}
} else if (status === "outside") {
path.replaceWith(t.throwStatement(t.inherits(
t.newExpression(t.identifier("ReferenceError"), [
t.stringLiteral(`${node.name} is not defined - temporal dead zone`),
]),
node
)));
path.replaceWith(
t.throwStatement(
t.inherits(
t.newExpression(t.identifier("ReferenceError"), [
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 nameFunction from "babel-helper-function-name";
export default function ({ types: t }) {
export default function({ types: t }) {
// todo: investigate traversal requeueing
const VISITED = Symbol();
@ -12,15 +12,17 @@ export default function ({ types: t }) {
if (!path.get("declaration").isClassDeclaration()) return;
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;
// Split the class declaration and the export into two separate statements.
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) {
@ -28,9 +30,11 @@ export default function ({ types: t }) {
const ref = node.id || path.scope.generateUidIdentifier("class");
path.replaceWith(t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)),
]));
path.replaceWith(
t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)),
]),
);
},
ClassExpression(path, state) {
@ -47,7 +51,10 @@ export default function ({ types: t }) {
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();
}
},

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