Skip to content

Commit

Permalink
feat(public/kpo): adds raise
Browse files Browse the repository at this point in the history
  • Loading branch information
rafamel committed Apr 30, 2019
1 parent 1dd5648 commit 4408633
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/public/kpo/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as run } from './run';
export { default as list } from './list';
export { default as raise } from './raise';
113 changes: 113 additions & 0 deletions src/public/kpo/raise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import fs from 'fs-extra';
import core, { options as _options } from '~/core';
import toArgv from 'string-argv';
import { IOfType } from '~/types';
import chalk from 'chalk';
import logger from '~/utils/logger';
import expose from '~/utils/expose';
import confirm from '~/utils/confirm';
import { rejects } from 'errorish';

export interface IRaiseOptions {
/**
* Prompt for changes confirmation before performing a write operation
*/
confirm?: boolean;
/**
* Dry run
*/
dry?: boolean;
/**
* Fails if there are any changes to be made on dry mode, or if the user cancels the action when confirmation is required
*/
fail?: boolean;
}

export default expose(raise);

/**
* Raises *kpo* tasks to the `package.json` in the project context.
* It is an *exposed* function: call `raise.fn()`, which takes the same arguments, in order to execute on call.
* @returns An asynchronous function -hence, calling `raise` won't have any effect until the returned function is called.
*/
function raise(options: IRaiseOptions = {}): () => Promise<void> {
return async () => {
if (options.confirm && options.dry) {
throw Error(`raise can't be run with both confirm and dry options`);
}
if (options.fail && (!options.confirm && !options.dry)) {
throw Error(
`raise can't be run in fail mode without confirm or dry options`
);
}

const paths = await core.paths();
const { pkg } = await core.load();

if (!paths.kpo) throw Error(`No kpo scripts found`);
if (!paths.pkg || !pkg) throw Error(`No package.json found`);

const tasks = await core.tasks();
const taskNames = (tasks.kpo || [])
.filter((task) => !task.hidden)
.map((task) => task.path);

const scripts: IOfType<string> = pkg.scripts || {};

const selected = Object.keys(scripts).filter((key) => {
const value = scripts[key];
let argv = toArgv(value);
if (argv.shift() !== 'kpo') return false;
if (argv[0] === ':run') argv.shift();
return (
argv.length === 1 &&
argv[0][0] !== ':' &&
argv[0][0] !== '@' &&
argv[0] === key
);
});
const nonSelected = Object.keys(scripts).filter(
(key) => !selected.includes(key)
);

const toRemove = selected.filter((key) => !taskNames.includes(key));
const toAdd = taskNames.filter((key) => !selected.includes(key));

let msg = chalk.bold.green('No pending scripts changes');
if (toRemove.length || toAdd.length) {
msg = toRemove.length
? chalk.bold.red('Scripts to remove: ') + toRemove.join(', ')
: chalk.bold.green('No scripts to remove');
msg +=
'\n' +
(toAdd.length
? chalk.bold.yellow('Scripts to add: ') + toAdd.join(', ')
: chalk.bold.green('No scripts to add'));
}

// eslint-disable-next-line no-console
(options.confirm || options.dry ? console.log : logger.info)(msg);

if (!toRemove.length && !toAdd.length) return;
if (options.dry) {
if (options.fail) throw Error(`There are pending scripts changes`);
return;
}

if (!(await confirm('Confirm?', options))) return;

pkg.scripts = {
...nonSelected.reduce((acc: IOfType<string>, key) => {
acc[key] = scripts[key];
return acc;
}, {}),
...taskNames.reduce((acc: IOfType<string>, key) => {
acc[key] = `kpo ${key}`;
return acc;
}, {})
};

await fs.writeFile(paths.pkg, JSON.stringify(pkg, null, 2)).catch(rejects);
_options.forceUpdate();
};
}

0 comments on commit 4408633

Please sign in to comment.