Skip to content

Commit

Permalink
feat(exposed/fs): moves file to fs; improves functions implementation…
Browse files Browse the repository at this point in the history
… and typings; adds rw
  • Loading branch information
rafamel committed Apr 28, 2019
1 parent 9684c42 commit 3a235cd
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 52 deletions.
31 changes: 0 additions & 31 deletions src/exposed/file/json.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/exposed/file/index.ts → src/exposed/fs/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as json } from './json';
export { default as remove } from './remove';
export { default as rw } from './rw';

// TODO: copy, mkdir, move, rw
28 changes: 28 additions & 0 deletions src/exposed/fs/json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { IOfType } from '~/types';
import expose from '~/utils/expose';
import rw from './rw';
import { IFsReadOptions } from './types';

export default expose(json);

/**
* Reads a JSON `file` and passes it as an argument to a callback `fn`. If the callback returns other than `undefined`, **`file` will be overwritten** with the JSON parsed response. `file` can be relative to the project's directory.
* It is an *exposed* function: call `json.fn()`, which takes the same arguments, in order to execute on call.
* @returns An asynchronous function -hence, calling `json` won't have any effect until the returned function is called.
*/
function json(
file: string,
fn: (
json?: IOfType<any>
) => IOfType<any> | void | Promise<IOfType<any> | void>,
options: IFsReadOptions = {}
): () => Promise<void> {
return async () => {
const _fn = async (raw?: string): Promise<string | undefined> => {
const json = await fn(raw ? JSON.parse(raw) : undefined);
return json ? JSON.stringify(json, null, 2) : undefined;
};

return rw.fn(file, _fn, options);
};
}
28 changes: 10 additions & 18 deletions src/exposed/file/remove.ts → src/exposed/fs/remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,7 @@ import { parallel } from 'promist';
import logger from '~/utils/logger';
import chalk from 'chalk';
import expose from '~/utils/expose';

/**
* 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;
}
import { IFsReadOptions } from './types';

export default expose(remove);
/**
Expand All @@ -33,9 +20,11 @@ export default expose(remove);
*/
function remove(
paths: string | string[],
options: IRemoveOptions = {}
options: IFsReadOptions = {}
): () => Promise<void> {
return async () => {
options = Object.assign({ confirm: false, fail: true }, options);

const cwd = await core.cwd();
paths = Array.isArray(paths) ? paths : [paths];
paths = paths.map((path) => absolute({ path, cwd }));
Expand Down Expand Up @@ -68,9 +57,12 @@ function remove(

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

if (!action) {
if (options.fail) throw Error(`Cancelled by user`);
else return;
}
}

await parallel.each(existingPaths, async (absolute, i) => {
Expand Down
55 changes: 55 additions & 0 deletions src/exposed/fs/rw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import path from 'path';
import fs from 'fs-extra';
import { exists, absolute } from '~/utils/file';
import core from '~/core';
import { rejects } from 'errorish';
import expose from '~/utils/expose';
import confirm from '../prompts/confirm';
import { IFsReadOptions } from './types';
import ensure from '../tags/ensure';

export default expose(rw);

/**
* Reads a `file` and passes it as an argument to a callback `fn`. If the callback returns other than `undefined`, **`file` will be overwritten** with its contents. `file` can be relative to the project's directory.
* It is an *exposed* function: call `rw.fn()`, which takes the same arguments, in order to execute on call.
* @returns An asynchronous function -hence, calling `rw` won't have any effect until the returned function is called.
*/
function rw(
file: string,
fn: (raw?: string) => string | void | Promise<string | void>,
options: IFsReadOptions = {}
): () => Promise<void> {
return async () => {
options = Object.assign({ confirm: false, fail: true }, options);

const cwd = await core.cwd();
file = absolute({ path: file, cwd });

const read = await exists(file, { fail: options.fail });

const raw = read
? await fs
.readFile(file)
.then(String)
.catch(rejects)
: undefined;

const response = await fn(raw);
if (response !== undefined) {
if (options.confirm) {
const action = await confirm
.fn(`Write "${path.relative(file, cwd)}"?`, { no: false })
.then((x) => x !== false);

if (!action) {
if (options.fail) throw Error(`Cancelled by user`);
else return;
}
}

await ensure.fn(path.parse(file).dir);
await fs.writeFile(file, String(response)).catch(rejects);
}
};
}
19 changes: 19 additions & 0 deletions src/exposed/fs/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Options taken by *fs* functions.
*/
export interface IFsOptions {
/**
* If `true`, it will require user confirmation for removal. Defaults to `false`.
*/
confirm?: boolean;
}

/**
* Options taken by *fs* functions that perform file reads.
*/
export interface IFsReadOptions extends IFsOptions {
/**
* If `false`, it won't fail if a path doesn't exist or the user doesn't confirm. Defaults to `true`.
*/
fail?: boolean;
}
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 './fs';
export * from './prompts';
export * from './tags';
export { default as options } from './options';
4 changes: 2 additions & 2 deletions src/exposed/tags/rm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import asTag from '~/utils/as-tag';
import expose, { TExposedOverload } from '~/utils/expose';
import remove from '../file/remove';
import remove from '../fs/remove';

export default expose(rm) as TExposedOverload<
typeof rm,
Expand All @@ -20,6 +20,6 @@ function rm(
function rm(...args: any[]): () => Promise<void> {
return async () => {
let file = asTag(args.shift(), ...args);
return remove.fn(file);
return remove.fn(file, { confirm: false, fail: false });
};
}

0 comments on commit 3a235cd

Please sign in to comment.