Refactor CLI to use promises/async fns.
This commit is contained in:
@@ -6,15 +6,14 @@ import fs from "fs";
|
||||
|
||||
import * as util from "./util";
|
||||
|
||||
let compiledFiles = 0;
|
||||
|
||||
export default function({ cliOptions, babelOptions }) {
|
||||
export default async function({ cliOptions, babelOptions }) {
|
||||
const filenames = cliOptions.filenames;
|
||||
|
||||
function write(src, base, callback) {
|
||||
async function write(src, base) {
|
||||
let relative = path.relative(base, src);
|
||||
|
||||
if (!util.isCompilableExtension(relative, cliOptions.extensions)) {
|
||||
return process.nextTick(callback);
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove extension and then append back on .js
|
||||
@@ -22,45 +21,47 @@ export default function({ cliOptions, babelOptions }) {
|
||||
|
||||
const dest = getDest(relative, base);
|
||||
|
||||
util.compile(
|
||||
src,
|
||||
defaults(
|
||||
{
|
||||
sourceFileName: slash(path.relative(dest + "/..", src)),
|
||||
},
|
||||
babelOptions,
|
||||
),
|
||||
function(err, res) {
|
||||
if (err && cliOptions.watch) {
|
||||
console.error(err);
|
||||
err = null;
|
||||
}
|
||||
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 &&
|
||||
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));
|
||||
}
|
||||
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);
|
||||
|
||||
if (cliOptions.verbose) {
|
||||
console.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(filename, base) {
|
||||
@@ -77,84 +78,62 @@ export default function({ cliOptions, babelOptions }) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleFile(src, base, callback) {
|
||||
write(src, base, function(err, res) {
|
||||
if (err) return callback(err);
|
||||
if (!res && cliOptions.copyFiles) {
|
||||
const filename = path.relative(base, src);
|
||||
const dest = getDest(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(cliOptions.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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handle(filename, callback) {
|
||||
if (!fs.existsSync(filename)) return;
|
||||
|
||||
const stat = fs.statSync(filename);
|
||||
|
||||
if (stat.isDirectory(filename)) {
|
||||
const dirname = filename;
|
||||
|
||||
if (cliOptions.deleteDirOnStart) {
|
||||
util.deleteDir(cliOptions.outDir);
|
||||
}
|
||||
let count = 0;
|
||||
|
||||
const files = util.readdir(dirname, cliOptions.includeDotfiles);
|
||||
sequentialHandleFile(files, dirname, callback);
|
||||
} else {
|
||||
write(filename, path.dirname(filename), callback);
|
||||
}
|
||||
}
|
||||
for (const filename of files) {
|
||||
const src = path.join(dirname, filename);
|
||||
|
||||
function sequentialHandle(filenames, index = 0) {
|
||||
const filename = filenames[index];
|
||||
|
||||
handle(filename, function(err) {
|
||||
if (err) throw new Error(err);
|
||||
index++;
|
||||
if (index !== filenames.length) {
|
||||
sequentialHandle(filenames, index);
|
||||
} else {
|
||||
console.log(
|
||||
`🎉 Successfully compiled ${compiledFiles} ${
|
||||
compiledFiles > 1 ? "files" : "file"
|
||||
} with Babel.`,
|
||||
);
|
||||
const written = await handleFile(src, dirname);
|
||||
if (written) count += 1;
|
||||
}
|
||||
});
|
||||
|
||||
return count;
|
||||
} else {
|
||||
const filename = filenameOrDir;
|
||||
const written = await handleFile(filename, path.dirname(filename));
|
||||
|
||||
return written ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cliOptions.skipInitialBuild) {
|
||||
sequentialHandle(filenames);
|
||||
if (cliOptions.deleteDirOnStart) {
|
||||
util.deleteDir(cliOptions.outDir);
|
||||
}
|
||||
|
||||
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 (cliOptions.watch) {
|
||||
@@ -177,10 +156,9 @@ export default function({ cliOptions, babelOptions }) {
|
||||
filename === filenameOrDir
|
||||
? path.dirname(filenameOrDir)
|
||||
: filenameOrDir,
|
||||
function(err) {
|
||||
if (err) console.error(err.stack);
|
||||
},
|
||||
);
|
||||
).catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,12 +7,8 @@ import fs from "fs";
|
||||
|
||||
import * as util from "./util";
|
||||
|
||||
export default function({ cliOptions, babelOptions }) {
|
||||
const filenames = cliOptions.filenames;
|
||||
|
||||
let results = [];
|
||||
|
||||
const buildResult = function() {
|
||||
export default async function({ cliOptions, babelOptions }) {
|
||||
function buildResult(fileResults) {
|
||||
const map = new sourceMap.SourceMapGenerator({
|
||||
file:
|
||||
cliOptions.sourceMapTarget ||
|
||||
@@ -24,7 +20,9 @@ export default function({ cliOptions, babelOptions }) {
|
||||
let code = "";
|
||||
let offset = 0;
|
||||
|
||||
results.forEach(function(result) {
|
||||
for (const result of fileResults) {
|
||||
if (!result) continue;
|
||||
|
||||
code += result.code + "\n";
|
||||
|
||||
if (result.map) {
|
||||
@@ -59,7 +57,7 @@ export default function({ cliOptions, babelOptions }) {
|
||||
|
||||
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
|
||||
@@ -74,10 +72,10 @@ export default function({ cliOptions, babelOptions }) {
|
||||
map: map,
|
||||
code: code,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const output = function() {
|
||||
const result = buildResult();
|
||||
function output(fileResults) {
|
||||
const result = buildResult(fileResults);
|
||||
|
||||
if (cliOptions.outFile) {
|
||||
// we've requested for a sourcemap to be written to disk
|
||||
@@ -91,40 +89,45 @@ export default function({ cliOptions, babelOptions }) {
|
||||
} 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(
|
||||
cliOptions.filename,
|
||||
code,
|
||||
defaults(
|
||||
{
|
||||
sourceFileName: "stdin",
|
||||
},
|
||||
babelOptions,
|
||||
),
|
||||
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;
|
||||
@@ -143,55 +146,51 @@ export default function({ cliOptions, babelOptions }) {
|
||||
}
|
||||
});
|
||||
|
||||
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 (cliOptions.outFile) {
|
||||
sourceFilename = path.relative(
|
||||
path.dirname(cliOptions.outFile),
|
||||
sourceFilename,
|
||||
);
|
||||
}
|
||||
sourceFilename = slash(sourceFilename);
|
||||
|
||||
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,
|
||||
),
|
||||
function(err, res) {
|
||||
if (err && cliOptions.watch) {
|
||||
console.error(err);
|
||||
err = null;
|
||||
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;
|
||||
}
|
||||
|
||||
if (err) throw err;
|
||||
console.error(err);
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
filesProcessed++;
|
||||
if (res) results[index] = res;
|
||||
output(results);
|
||||
}
|
||||
|
||||
if (filesProcessed === _filenames.length) {
|
||||
output();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const files = function() {
|
||||
async function files(filenames) {
|
||||
if (!cliOptions.skipInitialBuild) {
|
||||
walk();
|
||||
await walk(filenames);
|
||||
}
|
||||
|
||||
if (cliOptions.watch) {
|
||||
@@ -214,19 +213,18 @@ export default function({ cliOptions, babelOptions }) {
|
||||
if (cliOptions.verbose) {
|
||||
console.log(type + " " + filename);
|
||||
}
|
||||
try {
|
||||
walk();
|
||||
} catch (err) {
|
||||
console.error(err.stack);
|
||||
}
|
||||
|
||||
walk(filenames).catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (filenames.length) {
|
||||
files();
|
||||
if (cliOptions.filenames.length) {
|
||||
await files(cliOptions.filenames);
|
||||
} else {
|
||||
stdin();
|
||||
await stdin();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,7 @@ import fileCommand from "./file";
|
||||
const opts = parseArgv(process.argv);
|
||||
|
||||
const fn = opts.cliOptions.outDir ? dirCommand : fileCommand;
|
||||
fn(opts);
|
||||
fn(opts).catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -45,17 +45,27 @@ export function addSourceMappingUrl(code, loc) {
|
||||
return code + "\n//# sourceMappingURL=" + path.basename(loc);
|
||||
}
|
||||
|
||||
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, callback);
|
||||
export function compile(filename, opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
babel.transformFile(filename, opts, (err, result) => {
|
||||
if (err) reject(err);
|
||||
else resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteDir(path) {
|
||||
|
||||
Reference in New Issue
Block a user