diff --git a/babel.config.js b/babel.config.js index 086c4e5d20..6eca3d188b 100644 --- a/babel.config.js +++ b/babel.config.js @@ -24,7 +24,7 @@ module.exports = function(api) { case "production": // Config during builds before publish. envOpts.targets = { - node: 6, + node: "6.9", }; break; case "development": diff --git a/package.json b/package.json index b01c651c6c..2858ee66aa 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "webpack-stream": "^4.0.0" }, "engines": { - "node": ">= 6.x <= 9.x", + "node": ">= 6.9.0 <= 11.0.0-0", "npm": ">= 2.x <= 5.x", "yarn": ">=0.27.5 || >=1.0.0-20170811" }, diff --git a/packages/babel-cli/src/babel/dir.js b/packages/babel-cli/src/babel/dir.js index 6acd1d0512..5ae00b440b 100644 --- a/packages/babel-cli/src/babel/dir.js +++ b/packages/babel-cli/src/babel/dir.js @@ -6,58 +6,69 @@ import fs from "fs"; import * as util from "./util"; -let compiledFiles = 0; +export default async function({ cliOptions, babelOptions }) { + const filenames = cliOptions.filenames; -export default function(commander, filenames, opts) { - function write(src, base, callback) { + async function write(src, base) { let relative = path.relative(base, src); - if (!util.isCompilableExtension(relative, commander.extensions)) { - return process.nextTick(callback); + + if (!util.isCompilableExtension(relative, cliOptions.extensions)) { + return false; } // remove extension and then append back on .js - relative = util.adjustRelative(relative, commander.keepFileExtension); + relative = util.adjustRelative(relative, cliOptions.keepFileExtension); - const dest = getDest(commander, relative, base); + const dest = getDest(relative, base); - util.compile( - src, - defaults( - { - sourceFileName: slash(path.relative(dest + "/..", src)), - }, - opts, - ), - function(err, res) { - if (err) return callback(err); - if (!res) return callback(); + try { + const res = await util.compile( + src, + defaults( + { + sourceFileName: slash(path.relative(dest + "/..", src)), + }, + babelOptions, + ), + ); - // we've requested explicit sourcemaps to be written to disk - if ( - res.map && - commander.sourceMaps && - commander.sourceMaps !== "inline" - ) { - const mapLoc = dest + ".map"; - res.code = util.addSourceMappingUrl(res.code, mapLoc); - res.map.file = path.basename(relative); - outputFileSync(mapLoc, JSON.stringify(res.map)); - } + if (!res) return false; - outputFileSync(dest, res.code); - util.chmod(src, dest); + // we've requested explicit sourcemaps to be written to disk + if ( + res.map && + babelOptions.sourceMaps && + babelOptions.sourceMaps !== "inline" + ) { + const mapLoc = dest + ".map"; + res.code = util.addSourceMappingUrl(res.code, mapLoc); + res.map.file = path.basename(relative); + outputFileSync(mapLoc, JSON.stringify(res.map)); + } - compiledFiles += 1; + outputFileSync(dest, res.code); + util.chmod(src, dest); - util.log(src + " -> " + dest); - return callback(null, true); - }, - ); + if (cliOptions.verbose) { + console.log(src + " -> " + dest); + } + + return true; + } catch (err) { + if (cliOptions.watch) { + console.error(err); + return false; + } + + throw err; + } } - function getDest(commander, filename, base) { - if (commander.relative) return path.join(base, commander.outDir, filename); - return path.join(commander.outDir, filename); + function getDest(filename, base) { + if (cliOptions.relative) { + return path.join(base, cliOptions.outDir, filename); + } + return path.join(cliOptions.outDir, filename); } function outputDestFolder(outDir) { @@ -67,88 +78,65 @@ export default function(commander, filenames, opts) { } } - function handleFile(src, base, callback) { - write(src, base, function(err, res) { - if (err) return callback(err); - if (!res && commander.copyFiles) { - const filename = path.relative(base, src); - const dest = getDest(commander, filename, base); - outputFileSync(dest, fs.readFileSync(src)); - util.chmod(src, dest); - } + async function handleFile(src, base) { + const written = await write(src, base); - return callback(); - }); + if (!written && cliOptions.copyFiles) { + const filename = path.relative(base, src); + const dest = getDest(filename, base); + outputFileSync(dest, fs.readFileSync(src)); + util.chmod(src, dest); + } + return written; } - function sequentialHandleFile(files, dirname, index, callback) { - if (files.length === 0) { - outputDestFolder(commander.outDir); - return; - } + async function handle(filenameOrDir) { + if (!fs.existsSync(filenameOrDir)) return 0; - if (typeof index === "function") { - callback = index; - index = 0; - } + const stat = fs.statSync(filenameOrDir); - const filename = files[index]; - const src = path.join(dirname, filename); + if (stat.isDirectory(filenameOrDir)) { + const dirname = filenameOrDir; - handleFile(src, dirname, function(err) { - if (err) return callback(err); - index++; - if (index !== files.length) { - sequentialHandleFile(files, dirname, index, callback); - } else { - callback(); - } - }); - } + let count = 0; - function handle(filename, callback) { - if (!fs.existsSync(filename)) return; + const files = util.readdir(dirname, cliOptions.includeDotfiles); + for (const filename of files) { + const src = path.join(dirname, filename); - const stat = fs.statSync(filename); - - if (stat.isDirectory(filename)) { - const dirname = filename; - - if (commander.deleteDirOnStart) { - util.deleteDir(commander.outDir); + const written = await handleFile(src, dirname); + if (written) count += 1; } - const files = util.readdir(dirname, commander.includeDotfiles); - sequentialHandleFile(files, dirname, callback); + return count; } else { - write(filename, path.dirname(filename), callback); + const filename = filenameOrDir; + const written = await handleFile(filename, path.dirname(filename)); + + return written ? 1 : 0; } } - function sequentialHandle(filenames, index = 0) { - const filename = filenames[index]; + if (!cliOptions.skipInitialBuild) { + if (cliOptions.deleteDirOnStart) { + util.deleteDir(cliOptions.outDir); + } - handle(filename, function(err) { - if (err) throw new Error(err); - index++; - if (index !== filenames.length) { - sequentialHandle(filenames, index); - } else { - util.log( - `🎉 Successfully compiled ${compiledFiles} ${ - compiledFiles > 1 ? "files" : "file" - } with Babel.`, - true, - ); - } - }); + outputDestFolder(cliOptions.outDir); + + let compiledFiles = 0; + for (const filename of cliOptions.filenames) { + compiledFiles += await handle(filename); + } + + console.log( + `🎉 Successfully compiled ${compiledFiles} ${ + compiledFiles !== 1 ? "files" : "file" + } with Babel.`, + ); } - if (!commander.skipInitialBuild) { - sequentialHandle(filenames); - } - - if (commander.watch) { + if (cliOptions.watch) { const chokidar = util.requireChokidar(); filenames.forEach(function(filenameOrDir) { @@ -168,10 +156,9 @@ export default function(commander, filenames, opts) { filename === filenameOrDir ? path.dirname(filenameOrDir) : filenameOrDir, - function(err) { - if (err) console.error(err.stack); - }, - ); + ).catch(err => { + console.error(err); + }); }); }); }); diff --git a/packages/babel-cli/src/babel/file.js b/packages/babel-cli/src/babel/file.js index def6aa3eb7..31433b33da 100644 --- a/packages/babel-cli/src/babel/file.js +++ b/packages/babel-cli/src/babel/file.js @@ -7,26 +7,22 @@ import fs from "fs"; import * as util from "./util"; -export default function(commander, filenames, opts) { - if (commander.sourceMaps === "inline") { - opts.sourceMaps = true; - } - - let results = []; - - const buildResult = function() { +export default async function({ cliOptions, babelOptions }) { + function buildResult(fileResults) { const map = new sourceMap.SourceMapGenerator({ file: - commander.sourceMapTarget || - path.basename(commander.outFile || "") || + cliOptions.sourceMapTarget || + path.basename(cliOptions.outFile || "") || "stdout", - sourceRoot: opts.sourceRoot, + sourceRoot: babelOptions.sourceRoot, }); let code = ""; let offset = 0; - results.forEach(function(result) { + for (const result of fileResults) { + if (!result) continue; + code += result.code + "\n"; if (result.map) { @@ -61,13 +57,13 @@ export default function(commander, filenames, opts) { offset = code.split("\n").length - 1; } - }); + } // 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) + babelOptions.sourceMaps === "inline" || + (!cliOptions.outFile && babelOptions.sourceMaps) ) { code += "\n" + convertSourceMap.fromObject(map).toComment(); } @@ -76,57 +72,62 @@ export default function(commander, filenames, opts) { map: map, code: code, }; - }; + } - const output = function() { - const result = buildResult(); + function output(fileResults) { + const result = buildResult(fileResults); - if (commander.outFile) { + if (cliOptions.outFile) { // we've requested for a sourcemap to be written to disk - if (commander.sourceMaps && commander.sourceMaps !== "inline") { - const mapLoc = commander.outFile + ".map"; + if (babelOptions.sourceMaps && babelOptions.sourceMaps !== "inline") { + const mapLoc = cliOptions.outFile + ".map"; result.code = util.addSourceMappingUrl(result.code, mapLoc); fs.writeFileSync(mapLoc, JSON.stringify(result.map)); } - fs.writeFileSync(commander.outFile, result.code); + fs.writeFileSync(cliOptions.outFile, result.code); } else { process.stdout.write(result.code + "\n"); } - }; + } - const stdin = function() { - let code = ""; + function readStdin() { + return new Promise((resolve, reject) => { + let code = ""; - process.stdin.setEncoding("utf8"); + process.stdin.setEncoding("utf8"); - process.stdin.on("readable", function() { - const chunk = process.stdin.read(); - if (chunk !== null) code += chunk; + process.stdin.on("readable", function() { + const chunk = process.stdin.read(); + if (chunk !== null) code += chunk; + }); + + process.stdin.on("end", function() { + resolve(code); + }); + process.stdin.on("error", reject); }); + } - process.stdin.on("end", function() { - util.transform( - commander.filename, - code, - defaults( - { - sourceFileName: "stdin", - }, - opts, - ), - function(err, res) { - if (err) throw err; - results.push(res); - output(); + async function stdin() { + const code = await readStdin(); + + const res = await util.transform( + cliOptions.filename, + code, + defaults( + { + sourceFileName: "stdin", }, - ); - }); - }; + babelOptions, + ), + ); - const walk = function() { + output([res]); + } + + async function walk(filenames) { const _filenames = []; - results = []; filenames.forEach(function(filename) { if (!fs.existsSync(filename)) return; @@ -136,7 +137,7 @@ export default function(commander, filenames, opts) { const dirname = filename; util - .readdirForCompilable(filename, commander.includeDotfiles) + .readdirForCompilable(filename, cliOptions.includeDotfiles) .forEach(function(filename) { _filenames.push(path.join(dirname, filename)); }); @@ -145,46 +146,54 @@ export default function(commander, filenames, opts) { } }); - let filesProcessed = 0; + const results = await Promise.all( + _filenames.map(async function(filename) { + let sourceFilename = filename; + if (cliOptions.outFile) { + sourceFilename = path.relative( + path.dirname(cliOptions.outFile), + sourceFilename, + ); + } + sourceFilename = slash(sourceFilename); - _filenames.forEach(function(filename, index) { - let sourceFilename = filename; - if (commander.outFile) { - sourceFilename = path.relative( - path.dirname(commander.outFile), - sourceFilename, - ); - } - sourceFilename = slash(sourceFilename); - - util.compile( - filename, - defaults( - { - sourceFileName: sourceFilename, - }, - opts, - ), - function(err, res) { - if (err) throw err; - - filesProcessed++; - if (res) results[index] = res; - - if (filesProcessed === _filenames.length) { - output(); + try { + return await util.compile( + filename, + defaults( + { + sourceFileName: sourceFilename, + // Since we're compiling everything to be merged together, + // "inline" applies to the final output file, but to the individual + // files being concatenated. + sourceMaps: + babelOptions.sourceMaps === "inline" + ? true + : babelOptions.sourceMaps, + }, + babelOptions, + ), + ); + } catch (err) { + if (!cliOptions.watch) { + throw err; } - }, - ); - }); - }; - const files = function() { - if (!commander.skipInitialBuild) { - walk(); + console.error(err); + return null; + } + }), + ); + + output(results); + } + + async function files(filenames) { + if (!cliOptions.skipInitialBuild) { + await walk(filenames); } - if (commander.watch) { + if (cliOptions.watch) { const chokidar = util.requireChokidar(); chokidar .watch(filenames, { @@ -196,25 +205,26 @@ export default function(commander, filenames, opts) { }, }) .on("all", function(type, filename) { - if (!util.isCompilableExtension(filename, commander.extensions)) { + if (!util.isCompilableExtension(filename, cliOptions.extensions)) { return; } if (type === "add" || type === "change") { - util.log(type + " " + filename); - try { - walk(); - } catch (err) { - console.error(err.stack); + if (cliOptions.verbose) { + console.log(type + " " + filename); } + + walk(filenames).catch(err => { + console.error(err); + }); } }); } - }; + } - if (filenames.length) { - files(); + if (cliOptions.filenames.length) { + await files(cliOptions.filenames); } else { - stdin(); + await stdin(); } } diff --git a/packages/babel-cli/src/babel/index.js b/packages/babel-cli/src/babel/index.js index 696c42fe18..f319457607 100755 --- a/packages/babel-cli/src/babel/index.js +++ b/packages/babel-cli/src/babel/index.js @@ -1,264 +1,13 @@ #!/usr/bin/env node -import fs from "fs"; -import commander from "commander"; -import { version } from "@babel/core"; -import uniq from "lodash/uniq"; -import glob from "glob"; - +import parseArgv from "./options"; import dirCommand from "./dir"; import fileCommand from "./file"; -import pkg from "../../package.json"; +const opts = parseArgv(process.argv); -function booleanify(val: any): boolean | any { - if (val === "true" || val == 1) { - return true; - } - - if (val === "false" || val == 0 || !val) { - return false; - } - - return val; -} - -function collect(value, previousValue): Array { - // If the user passed the option with no value, like "babel file.js --presets", do nothing. - if (typeof value !== "string") return previousValue; - - const values = value.split(","); - - return previousValue ? previousValue.concat(values) : values; -} - -// 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("--config-file [path]", "Path a to .babelrc file to use"); -commander.option( - "--env-name [name]", - "The name of the 'env' to use when loading configs and plugins. " + - "Defaults to the value of BABEL_ENV, or else NODE_ENV, or else 'development'.", -); - -// 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, -); - -// Misc babel config. -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("--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", -); - -// 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", -); - -// 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("-M, --module-ids", "insert an explicit id for modules"); -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( - "--keep-file-extension", - "Preserve the file extensions of the input files", -); -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( - "--relative", - "Compile into an output directory relative to input directory or file. Requires --out-dir [out]", -); -commander.option( - "-D, --copy-files", - "When compiling a directory copy over non-compilable files", -); -commander.option( - "--include-dotfiles", - "Include dotfiles when compiling and copying non-compilable files", -); -commander.option("--verbose", "Log everything"); -commander.option( - "--delete-dir-on-start", - "Delete the out directory before compilation", -); - -commander.version(pkg.version + " (@babel/core " + version + ")"); -commander.usage("[options] "); -commander.parse(process.argv); - -// - -const errors = []; - -let filenames = commander.args.reduce(function(globbed, input) { - let files = glob.sync(input); - if (!files.length) files = [input]; - return globbed.concat(files); -}, []); - -filenames = uniq(filenames); - -filenames.forEach(function(filename) { - if (!fs.existsSync(filename)) { - errors.push(filename + " doesn't exist"); - } +const fn = opts.cliOptions.outDir ? dirCommand : fileCommand; +fn(opts).catch(err => { + console.error(err); + process.exit(1); }); - -if (commander.outDir && !filenames.length) { - errors.push("filenames required for --out-dir"); -} - -if (commander.outFile && commander.outDir) { - errors.push("cannot have --out-file and --out-dir"); -} - -if (commander.relative && !commander.outDir) { - errors.push("output directory required for --relative"); -} - -if (commander.watch) { - if (!commander.outFile && !commander.outDir) { - errors.push("--watch requires --out-file or --out-dir"); - } - - if (!filenames.length) { - errors.push("--watch requires filenames"); - } -} - -if (commander.skipInitialBuild && !commander.watch) { - errors.push("--skip-initial-build requires --watch"); -} -if (commander.deleteDirOnStart && !commander.outDir) { - errors.push("--delete-dir-on-start requires --out-dir"); -} - -if ( - !commander.outDir && - filenames.length === 0 && - typeof commander.filename !== "string" && - commander.babelrc !== false -) { - errors.push( - "stdin compilation requires either -f/--filename [filename] or --no-babelrc", - ); -} - -if (errors.length) { - console.error(errors.join(". ")); - process.exit(2); -} - -// - -const opts = commander.opts(); - -// Delete options that are specific to @babel/cli and shouldn't be passed to @babel/core. -delete opts.version; -delete opts.extensions; -delete opts.watch; -delete opts.skipInitialBuild; -delete opts.outFile; -delete opts.outDir; -delete opts.copyFiles; -delete opts.includeDotfiles; -delete opts.verbose; -delete opts.deleteDirOnStart; -delete opts.keepFileExtension; -delete opts.relative; -delete opts.sourceMapTarget; - -// Commander will default the "--no-" arguments to true, but we want to leave them undefined so that -// @babel/core can handle the default-assignment logic on its own. -if (opts.babelrc === true) opts.babelrc = undefined; -if (opts.comments === true) opts.comments = undefined; -if (opts.highlightCode === true) opts.highlightCode = undefined; - -const fn = commander.outDir ? dirCommand : fileCommand; -fn(commander, filenames, opts); diff --git a/packages/babel-cli/src/babel/options.js b/packages/babel-cli/src/babel/options.js new file mode 100644 index 0000000000..a058d48be1 --- /dev/null +++ b/packages/babel-cli/src/babel/options.js @@ -0,0 +1,283 @@ +import fs from "fs"; + +import commander from "commander"; +import { version } from "@babel/core"; +import uniq from "lodash/uniq"; +import glob from "glob"; + +import pkg from "../../package.json"; + +// 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("--config-file [path]", "Path a to .babelrc file to use"); +commander.option( + "--env-name [name]", + "The name of the 'env' to use when loading configs and plugins. " + + "Defaults to the value of BABEL_ENV, or else NODE_ENV, or else 'development'.", +); + +// 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, +); + +// Misc babel config. +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("--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", +); + +// 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", +); + +// 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("-M, --module-ids", "insert an explicit id for modules"); +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( + "--keep-file-extension", + "Preserve the file extensions of the input files", +); +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( + "--relative", + "Compile into an output directory relative to input directory or file. Requires --out-dir [out]", +); +commander.option( + "-D, --copy-files", + "When compiling a directory copy over non-compilable files", +); +commander.option( + "--include-dotfiles", + "Include dotfiles when compiling and copying non-compilable files", +); +commander.option("--verbose", "Log everything"); +commander.option( + "--delete-dir-on-start", + "Delete the out directory before compilation", +); + +commander.version(pkg.version + " (@babel/core " + version + ")"); +commander.usage("[options] "); + +export default function parseArgv(args: Array) { + // + commander.parse(args); + + const errors = []; + + let filenames = commander.args.reduce(function(globbed, input) { + let files = glob.sync(input); + if (!files.length) files = [input]; + return globbed.concat(files); + }, []); + + filenames = uniq(filenames); + + filenames.forEach(function(filename) { + if (!fs.existsSync(filename)) { + errors.push(filename + " doesn't exist"); + } + }); + + if (commander.outDir && !filenames.length) { + errors.push("filenames required for --out-dir"); + } + + if (commander.outFile && commander.outDir) { + errors.push("cannot have --out-file and --out-dir"); + } + + if (commander.relative && !commander.outDir) { + errors.push("output directory required for --relative"); + } + + if (commander.watch) { + if (!commander.outFile && !commander.outDir) { + errors.push("--watch requires --out-file or --out-dir"); + } + + if (!filenames.length) { + errors.push("--watch requires filenames"); + } + } + + if (commander.skipInitialBuild && !commander.watch) { + errors.push("--skip-initial-build requires --watch"); + } + if (commander.deleteDirOnStart && !commander.outDir) { + errors.push("--delete-dir-on-start requires --out-dir"); + } + + if ( + !commander.outDir && + filenames.length === 0 && + typeof commander.filename !== "string" && + commander.babelrc !== false + ) { + errors.push( + "stdin compilation requires either -f/--filename [filename] or --no-babelrc", + ); + } + + if (errors.length) { + console.error(errors.join(". ")); + process.exit(2); + } + + const opts = commander.opts(); + + return { + babelOptions: { + presets: opts.presets, + plugins: opts.plugins, + configFile: opts.configFile, + envName: opts.envName, + sourceType: opts.sourceType, + ignore: opts.ignore, + only: opts.only, + retainLines: opts.retainLines, + compact: opts.compact, + minified: opts.minified, + auxiliaryCommentBefore: opts.auxiliaryCommentBefore, + auxiliaryCommentAfter: opts.auxiliaryCommentAfter, + sourceMaps: opts.sourceMaps, + sourceFileName: opts.sourceFileName, + sourceRoot: opts.sourceRoot, + moduleRoot: opts.moduleRoot, + moduleIds: opts.moduleIds, + moduleId: opts.moduleId, + + // Commander will default the "--no-" arguments to true, but we want to + // leave them undefined so that @babel/core can handle the + // default-assignment logic on its own. + babelrc: opts.babelrc === true ? undefined : opts.babelrc, + highlightCode: + opts.highlightCode === true ? undefined : opts.highlightCode, + comments: opts.comments === true ? undefined : opts.comments, + }, + cliOptions: { + filename: opts.filename, + filenames, + extensions: opts.extensions, + keepFileExtension: opts.keepFileExtension, + watch: opts.watch, + skipInitialBuild: opts.skipInitialBuild, + outFile: opts.outFile, + outDir: opts.outDir, + relative: opts.relative, + copyFiles: opts.copyFiles, + includeDotfiles: opts.includeDotfiles, + verbose: opts.verbose, + deleteDirOnStart: opts.deleteDirOnStart, + sourceMapTarget: opts.sourceMapTarget, + }, + }; +} + +function booleanify(val: any): boolean | any { + if (val === "true" || val == 1) { + return true; + } + + if (val === "false" || val == 0 || !val) { + return false; + } + + return val; +} + +function collect(value, previousValue): Array { + // If the user passed the option with no value, like "babel file.js --presets", do nothing. + if (typeof value !== "string") return previousValue; + + const values = value.split(","); + + return previousValue ? previousValue.concat(values) : values; +} diff --git a/packages/babel-cli/src/babel/util.js b/packages/babel-cli/src/babel/util.js index 9baa0c72ef..5d0cdc479e 100644 --- a/packages/babel-cli/src/babel/util.js +++ b/packages/babel-cli/src/babel/util.js @@ -1,4 +1,3 @@ -import commander from "commander"; import readdirRecursive from "fs-readdir-recursive"; import * as babel from "@babel/core"; import includes from "lodash/includes"; @@ -46,30 +45,26 @@ export function addSourceMappingUrl(code, loc) { return code + "\n//# sourceMappingURL=" + path.basename(loc); } -export function log(msg, force) { - if (force === true || commander.verbose) console.log(msg); -} - -export function transform(filename, code, opts, callback) { +export function transform(filename, code, opts) { opts = { ...opts, filename, }; - babel.transform(code, opts, callback); + return new Promise((resolve, reject) => { + babel.transform(code, opts, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); } -export function compile(filename, opts, callback) { - babel.transformFile(filename, opts, function(err, res) { - if (err) { - if (commander.watch) { - console.error(err); - return callback(null, null); - } else { - return callback(err); - } - } - return callback(null, res); +export function compile(filename, opts) { + return new Promise((resolve, reject) => { + babel.transformFile(filename, opts, (err, result) => { + if (err) reject(err); + else resolve(result); + }); }); } diff --git a/packages/babel-cli/test/fixtures/babel/empty dir --out-dir/stdout.txt b/packages/babel-cli/test/fixtures/babel/empty dir --out-dir/stdout.txt index e69de29bb2..32542635ae 100644 --- a/packages/babel-cli/test/fixtures/babel/empty dir --out-dir/stdout.txt +++ b/packages/babel-cli/test/fixtures/babel/empty dir --out-dir/stdout.txt @@ -0,0 +1 @@ +🎉 Successfully compiled 0 files with Babel. diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json index 10b801eb1b..7401358575 100644 --- a/packages/babel-core/package.json +++ b/packages/babel-core/package.json @@ -22,6 +22,9 @@ "babel-core", "compiler" ], + "engines": { + "node": ">=6.9.0" + }, "browser": { "./lib/config/files/index.js": "./lib/config/files/index-browser.js", "./lib/transform-file.js": "./lib/transform-file-browser.js",