Skip to content

Commit

Permalink
feat(exposed/file): adds remove
Browse files Browse the repository at this point in the history
  • Loading branch information
rafamel committed Apr 28, 2019
1 parent 69532e0 commit 75d114f
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/exposed/file/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as json } from './json';
export { default as remove } from './remove';

// TODO: copy, mkdir, move, rw
File renamed without changes.
92 changes: 92 additions & 0 deletions src/exposed/file/remove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import path from 'path';
import fs from 'fs-extra';
import { rejects } from 'errorish';
import core from '~/core';
import { wrap } from '~/utils/errors';
import { absolute, exists } from '~/utils/file';
import { TScriptAsyncFn } from '~/types';
import confirm from '../prompts/confirm';
import { parallel } from 'promist';
import logger from '~/utils/logger';
import chalk from 'chalk';

/**
* Options taken by `remove`.
*/
export interface IRemoveOptions {
/**
* If `true`, it will require user confirmation for removal.
*/
confirm?: boolean;
/**
* If `true`, it will fail if a path doesn't exist.
*/
fail?: boolean;
}

/**
* Removes a file, a directory -recursively-, or an array of them.
* @param paths a path for a file or directory, or an array of them.
* @param options a `IRemoveOptions` object.
* @returns An asynchronous function, as a `TScriptAsyncFn`, that won't be executed until called by `kpo` -hence, calling `remove` won't have any effect until the returned function is called.
*/
export default function remove(
paths: string | string[],
options: IRemoveOptions = {}
): TScriptAsyncFn {
return (): Promise<void> => {
return wrap.throws(async () => {
const cwd = await core.cwd();
paths = Array.isArray(paths) ? paths : [paths];
paths = paths.map((path) => absolute(path, cwd));

const existingPaths = await parallel.filter(paths, (path) =>
exists(path)
);
const nonExistingPaths = paths.filter(
(path) => !existingPaths.includes(path)
);
const relatives = {
existing: existingPaths.map((x) => path.relative(cwd, x)),
nonExisting: nonExistingPaths.map((x) => path.relative(cwd, x))
};

if (options.fail && nonExistingPaths.length) {
throw Error(
`Path to remove doesn't exist: ${relatives.nonExisting[0]}`
);
}

// eslint-disable-next-line no-console
(options.confirm ? console.log : logger.debug)(
chalk.bold.yellow(
relatives.existing.length ? 'Paths to remove' : 'No paths to remove'
) +
(relatives.existing.length
? `\n Existing paths: "${relatives.existing.join('", "')}"`
: '') +
(relatives.nonExisting.length
? `\n Non existing paths: "${relatives.nonExisting.join(
'", "'
)}"`
: '')
);

if (!existingPaths.length) return;
if (options.confirm) {
await confirm({ no: false })().then(async (x) => {
if (x === false) throw Error(`Cancelled by user`);
});
}

await parallel.each(existingPaths, async (absolute, i) => {
await fs.remove(absolute).catch(rejects);

const relative = relatives.existing[i];
logger.debug(`Removed: ${relative}`);
});

logger.info(`Removed: "${relatives.existing.join('", "')}"`);
});
};
}
2 changes: 1 addition & 1 deletion src/exposed/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './exec';
export * from './file';
export * from './prompts';
export * from './tags';
export { default as json } from './json';
export { default as options } from './options';

0 comments on commit 75d114f

Please sign in to comment.