Make CLI perform static analysis of config lazily (#2593)

This commit is contained in:
Benjamin Woodruff 2018-01-12 23:04:57 -08:00 committed by CHaBou
parent 2c5b3d5ccd
commit a9e4aa59da

View file

@ -6,37 +6,51 @@ const recast = require('recast');
const fileName = `${os.homedir()}/.hyper.js`; const fileName = `${os.homedir()}/.hyper.js`;
let fileContents; /**
let parsedFile; * We need to make sure the file reading and parsing is lazy so that failure to
let plugins; * statically analyze the hyper configuration isn't fatal for all kinds of
let localPlugins; * subcommands. We can use memoization to make reading and parsing lazy.
*/
try { function memoize(fn) {
fileContents = fs.readFileSync(fileName, 'utf8'); let hasResult = false;
let result;
parsedFile = recast.parse(fileContents); return (...args) => {
if (!hasResult) {
const properties = parsedFile.program.body[0].expression.right.properties; result = fn(...args);
plugins = properties.find(property => { hasResult = true;
return property.key.name === 'plugins'; }
}).value.elements; return result;
};
localPlugins = properties.find(property => {
return property.key.name === 'localPlugins';
}).value.elements;
} catch (err) {
if (err.code !== 'ENOENT') {
// ENOENT === !exists()
throw err;
}
} }
const getFileContents = memoize(() => {
try {
return fs.readFileSync(fileName, 'utf8');
} catch (err) {
if (err.code !== 'ENOENT') {
// ENOENT === !exists()
throw err;
}
}
return null;
});
const getParsedFile = memoize(() => recast.parse(getFileContents()));
const getProperties = memoize(() => getParsedFile().program.body[0].expression.right.properties);
const getPlugins = memoize(() => getProperties().find(property => property.key.name === 'plugins').value.elements);
const getLocalPlugins = memoize(
() => getProperties().find(property => property.key.name === 'localPlugins').value.elements
);
function exists() { function exists() {
return fileContents !== undefined; return getFileContents() !== undefined;
} }
function isInstalled(plugin, locally) { function isInstalled(plugin, locally) {
const array = locally ? localPlugins : plugins; const array = locally ? getLocalPlugins() : getPlugins();
if (array && Array.isArray(array)) { if (array && Array.isArray(array)) {
return array.find(entry => entry.value === plugin) !== undefined; return array.find(entry => entry.value === plugin) !== undefined;
} }
@ -44,7 +58,7 @@ function isInstalled(plugin, locally) {
} }
function save() { function save() {
return pify(fs.writeFile)(fileName, recast.print(parsedFile).code, 'utf8'); return pify(fs.writeFile)(fileName, recast.print(getParsedFile()).code, 'utf8');
} }
function existsOnNpm(plugin) { function existsOnNpm(plugin) {
@ -59,7 +73,7 @@ function existsOnNpm(plugin) {
} }
function install(plugin, locally) { function install(plugin, locally) {
const array = locally ? localPlugins : plugins; const array = locally ? getLocalPlugins() : getPlugins();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
existsOnNpm(plugin) existsOnNpm(plugin)
.then(() => { .then(() => {
@ -88,8 +102,8 @@ function uninstall(plugin) {
return reject(`${plugin} is not installed`); return reject(`${plugin} is not installed`);
} }
const index = plugins.findIndex(entry => entry.value === plugin); const index = getPlugins().findIndex(entry => entry.value === plugin);
plugins.splice(index, 1); getPlugins().splice(index, 1);
save() save()
.then(resolve) .then(resolve)
.catch(err => reject(err)); .catch(err => reject(err));
@ -97,8 +111,10 @@ function uninstall(plugin) {
} }
function list() { function list() {
if (Array.isArray(plugins)) { if (Array.isArray(getPlugins())) {
return plugins.map(plugin => plugin.value).join('\n'); return getPlugins()
.map(plugin => plugin.value)
.join('\n');
} }
return false; return false;
} }