Skip to content

Commit

Permalink
Update codebase to async-await
Browse files Browse the repository at this point in the history
  • Loading branch information
juanjoDiaz committed Jul 19, 2019
1 parent c3bf41d commit d157d5e
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 108 deletions.
28 changes: 17 additions & 11 deletions bin/removeNPMAbsolutePaths
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,24 @@
const cli = require('../src/cli');
const removeNPMAbsolutePaths = require('../src/removeNPMAbsolutePaths');

Promise.resolve()
.then(() => cli.parseArguments(process.argv.slice(2)))
.then((args) => {
async function main() {
try {
const args = await cli.parseArguments(process.argv.slice(2));

if (args.ignored.length) {
console.warn(`The following options are unknown and will be ignored:\n${args.ignored.join('\n')}`);
}

return removeNPMAbsolutePaths(args.path, args.opts);
})
.then(results => results.forEach((result) => {
if (!result.success) {
console.log(result.err.message);
}
}))
.catch(err => console.log(err.message));
const results = await removeNPMAbsolutePaths(args.path, args.opts);

results.forEach((result) => {
if (!result.success) {
console.log(result.err.message);
}
});
} catch (err) {
console.error(err.message);
}
}

main();
2 changes: 1 addition & 1 deletion src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function parseArguments(args) {
}

const path = args[0];
const opts = Object.assign({}, defaultOpts);
const opts = { ...defaultOpts };

const ignored = [];

Expand Down
184 changes: 89 additions & 95 deletions src/removeNPMAbsolutePaths.js
Original file line number Diff line number Diff line change
@@ -1,105 +1,99 @@
'use strict';

const fs = require('fs');
const path = require('path');
const {
stat, readdir, readFile, writeFile,
} = require('fs');
const { promisify } = require('util');
const errno = require('./errno');

function createError(message, rootErr) {
const err = new Error(message + (rootErr.errno ? ` (${errno[rootErr.errno]})` : ''));
err.cause = rootErr;
return err;
}
const statAsync = promisify(stat);
const readdirAsync = promisify(readdir);
const readFileAsync = promisify(readFile);
const writeFileAsync = promisify(writeFile);

function getStats(filePath) {
return new Promise((resolve, reject) => {
fs.stat(filePath, (err, stats) => {
if (err) {
reject(createError(`Can't read directory/file at "${filePath}"`, err));
return;
}
class ProcessingError extends Error {
constructor(message, err) {
super(message + ((err && err.errno) ? ` (${errno[err.errno]})` : ''));
this.cause = err;
}
}

resolve(stats);
});
});
async function getStats(filePath) {
try {
return await statAsync(filePath);
} catch (err) {
throw new ProcessingError(`Can't read directory/file at "${filePath}"`, err);
}
}

function processFile(filePath, opts) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
reject(createError(`Can't read file at "${filePath}"`, err));
return;
async function processFile(filePath, opts) {
try {
let data;
try {
data = await readFileAsync(filePath, 'utf8');
} catch (err) {
throw new ProcessingError(`Can't read file at "${filePath}"`, err);
}

let shouldWriteFile = false;
let obj;
try {
obj = JSON.parse(data);
} catch (err) {
throw new ProcessingError(`Malformed package.json file at "${filePath}"`, err);
}

Object.keys(obj).forEach((key) => {
const shouldBeDeleted = opts.fields ? (opts.fields.indexOf(key) !== -1) : (key[0] === '_');
if (shouldBeDeleted) {
delete obj[key];
shouldWriteFile = true;
}

resolve(data);
});
})
.then((data) => {
let writeFile = false;
let obj;

if (shouldWriteFile || opts.force) {
try {
obj = JSON.parse(data);
await writeFileAsync(filePath, JSON.stringify(obj, null, ' '));
} catch (err) {
throw createError(`Malformed package.json file at "${filePath}"`, err);
throw new ProcessingError(`Can't write processed file to "${filePath}"`, err);
}

Object.keys(obj).forEach((key) => {
const shouldBeDeleted = opts.fields ? (opts.fields.indexOf(key) !== -1) : (key[0] === '_');
if (shouldBeDeleted) {
delete obj[key];
writeFile = true;
}
});

if (writeFile || opts.force) {
return new Promise((resolve, reject) => {
fs.writeFile(filePath, JSON.stringify(obj, null, ' '), (err) => {
if (err) {
reject(createError(`Can't write processed file to "${filePath}"`, err));
return;
}

resolve({ rewritten: true });
});
});
}
return { filePath, rewritten: true, success: true };
}

return { rewritten: false };
})
.then(
r => ({ filePath, rewritten: r.rewritten, success: true }),
err => ({ filePath, err, success: false })
);
return { filePath, rewritten: false, success: true };
} catch (err) {
return { filePath, err, success: false };
}
}

function processDir(dirPath, opts) {
return new Promise((resolve, reject) => {
fs.readdir(dirPath, (err, files) => {
if (err) {
reject(createError(`Can't read directory at "${dirPath}"`, err));
return;
}
async function processDir(dirPath, opts) {
try {
let files;
try {
files = await readdirAsync(dirPath);
} catch (err) {
throw new ProcessingError(`Can't read directory at "${dirPath}"`, err);
}

resolve(files);
});
})
.then(files => Promise.all(files.map((fileName) => {
const results = await Promise.all(files.map(async (fileName) => {
const filePath = path.join(dirPath, fileName);

return getStats(filePath)
.then((stats) => {
if (stats.isDirectory()) {
return processDir(filePath, opts);
}
const stats = await getStats(filePath);

if (fileName === 'package.json') {
return processFile(filePath, opts);
}
if (stats.isDirectory()) {
return processDir(filePath, opts);
}

if (fileName === 'package.json') {
return processFile(filePath, opts);
}

return undefined;
}));

return undefined;
});
})))
.then(results => results.reduce((arr, value) => {
return results.reduce((arr, value) => {
if (!value) {
return arr;
}
Expand All @@ -110,34 +104,34 @@ function processDir(dirPath, opts) {

arr.push(value);
return arr;
}, [{ dirPath, success: true }]))
.catch(err => [{ dirPath, err, success: false }]);
}, [{ dirPath, success: true }]);
} catch (err) {
return [{ dirPath, err, success: false }];
}
}

function removeNPMAbsolutePaths(filePath, opts) {
async function removeNPMAbsolutePaths(filePath, opts) {
opts = opts || {}; // eslint-disable-line no-param-reassign

if (!filePath) {
return Promise.reject(new Error('Missing path.\nThe first argument should be the path to a directory or a package.json file.'));
throw new ProcessingError('Missing path.\nThe first argument should be the path to a directory or a package.json file.');
}

if (opts.fields && (opts.fields.constructor !== Array || opts.fields.length === 0)) {
return Promise.reject(new Error('Invalid option: fields.\nThe fields option should be an array cotaining the names of the specific fields that should be removed.'));
throw new ProcessingError('Invalid option: fields.\nThe fields option should be an array cotaining the names of the specific fields that should be removed.');
}

return getStats(filePath)
.then((stats) => {
if (stats.isDirectory()) {
return processDir(filePath, opts);
}
const stats = await getStats(filePath);

if (path.basename(filePath) === 'package.json') {
return processFile(filePath, opts)
.then(result => [result]);
}
if (stats.isDirectory()) {
return processDir(filePath, opts);
}

throw new Error('Invalid path provided. The path should be a directory or a package.json file.');
});
if (path.basename(filePath) === 'package.json') {
return [await processFile(filePath, opts)];
}

throw new Error('Invalid path provided. The path should be a directory or a package.json file.');
}

module.exports = removeNPMAbsolutePaths;
13 changes: 12 additions & 1 deletion test/removeNPMAbsolutePaths.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ const expect = chai.expect;
chai.use(sinonChai);
chai.use(chaiAsPromised);

const removeNPMAbsolutePaths = require('../src/removeNPMAbsolutePaths');
let removeNPMAbsolutePaths = require('../src/removeNPMAbsolutePaths');

function clearCachedModuleSoNewMocksWork() {
delete require.cache[require.resolve('../src/removeNPMAbsolutePaths')];
// eslint-disable-next-line global-require
removeNPMAbsolutePaths = require('../src/removeNPMAbsolutePaths');
}

describe('removeNPMAbsolutePaths.js', function () {
describe('valid permissions', function () {
Expand All @@ -27,6 +33,7 @@ describe('removeNPMAbsolutePaths.js', function () {
readdir = sinon.spy(fs, 'readdir');
readFile = sinon.spy(fs, 'readFile');
writeFile = sinon.stub(fs, 'writeFile');
clearCachedModuleSoNewMocksWork();
});

beforeEach(function () {
Expand Down Expand Up @@ -384,6 +391,7 @@ describe('removeNPMAbsolutePaths.js', function () {
readdir = sinon.stub(fs, 'readdir');
readFile = sinon.spy(fs, 'readFile');
writeFile = sinon.spy(fs, 'writeFile');
clearCachedModuleSoNewMocksWork();
});

beforeEach(function () {
Expand All @@ -403,6 +411,7 @@ describe('removeNPMAbsolutePaths.js', function () {
it('return error if can\'t read file', function () {
const err = new Error('Can\'t read directory.');
readdir.yields(err);
clearCachedModuleSoNewMocksWork();
const dirPath = `${__dirname}/data/underscore_fields`;
const promise = removeNPMAbsolutePaths(dirPath);
return expect(promise).be.fulfilled
Expand Down Expand Up @@ -452,6 +461,7 @@ describe('removeNPMAbsolutePaths.js', function () {
it('return error if can\'t read file', function () {
const err = new Error('Can\'t read file.');
readFile.yields(err);
clearCachedModuleSoNewMocksWork();
const filePath = `${__dirname}/data/underscore_fields/module/package.json`;
const promise = removeNPMAbsolutePaths(filePath);
return expect(promise).be.fulfilled
Expand Down Expand Up @@ -501,6 +511,7 @@ describe('removeNPMAbsolutePaths.js', function () {
it('return error if can\'t write to file', function () {
const err = new Error('Can\'t write to file.');
writeFile.yields(err);
clearCachedModuleSoNewMocksWork();
const filePath = `${__dirname}/data/underscore_fields/module/package.json`;
const promise = removeNPMAbsolutePaths(filePath);
return expect(promise).be.fulfilled
Expand Down

0 comments on commit d157d5e

Please sign in to comment.