Refactor CLI to use promises/async fns.

This commit is contained in:
Logan Smyth
2018-05-01 22:32:01 -07:00
parent 41ca312545
commit 8ff675ad69
6 changed files with 194 additions and 204 deletions

View File

@@ -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);
});
});
});
});

View File

@@ -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();
}
}

View File

@@ -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);
});

View File

@@ -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) {

View File

@@ -0,0 +1 @@
🎉 Successfully compiled 0 files with Babel.