diff --git a/src/public/fs/copy.ts b/src/public/fs/copy.ts index 4754f3a..af955a2 100644 --- a/src/public/fs/copy.ts +++ b/src/public/fs/copy.ts @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs-extra'; import { absolute, exists } from '~/utils/file'; -import { IFsUpdateOptions } from './types'; +import { IFsUpdateOptions, TSource } from './types'; import expose, { TExposedOverload } from '~/utils/expose'; import confirm from '~/utils/confirm'; import logger from '~/utils/logger'; @@ -13,24 +13,20 @@ export type TCopyFilterFn = export default expose(copy) as TExposedOverload< typeof copy, - | [string | string[] | Promise, string] - | [string | string[] | Promise, string, IFsUpdateOptions] - | [string | string[] | Promise, string, TCopyFilterFn] - | [ - string | string[] | Promise, - string, - IFsUpdateOptions | undefined, - TCopyFilterFn - ] + | [TSource, string] + | [TSource, string, IFsUpdateOptions] + | [TSource, string, TCopyFilterFn] + | [TSource, string, IFsUpdateOptions | undefined, TCopyFilterFn] >; +// TODO allow to take an option to duplicate folder structure on dest from a base + don't allow it when src is upwards instead of nested in that folder function copy( - src: string | string[] | Promise, + src: TSource, dest: string, filter?: TCopyFilterFn ): () => Promise; function copy( - src: string | string[] | Promise, + src: TSource, dest: string, options?: IFsUpdateOptions, filter?: TCopyFilterFn @@ -40,14 +36,18 @@ function copy( * It is an *exposed* function: call `copy.fn()`, which takes the same arguments, in order to execute on call. * @returns An asynchronous function -hence, calling `copy` won't have any effect until the returned function is called. */ -function copy( - src: string | string[] | Promise, - dest: string, - ...args: any[] -): () => Promise { +function copy(src: TSource, dest: string, ...args: any[]): () => Promise { return async () => { - src = await src; + src = typeof src === 'function' ? await src() : await src; + if (Array.isArray(src)) { + // Check dest is a folder + if (await exists(dest)) { + const stat = await fs.stat(dest); + if (!stat.isDirectory()) { + throw Error('Destination must be a folder for an array of sources'); + } + } for (let source of src) { await trunk(source, path.join(dest, path.parse(source).base), args); } diff --git a/src/public/fs/mkdir.ts b/src/public/fs/mkdir.ts index a7d79fd..32c1ae8 100644 --- a/src/public/fs/mkdir.ts +++ b/src/public/fs/mkdir.ts @@ -6,7 +6,7 @@ import { parallel } from 'promist'; import logger from '~/utils/logger'; import chalk from 'chalk'; import expose from '~/utils/expose'; -import { IFsCreateDeleteOptions } from './types'; +import { IFsCreateDeleteOptions, TSource } from './types'; export default expose(mkdir); /** @@ -17,11 +17,12 @@ export default expose(mkdir); * @returns An asynchronous function -hence, calling `mkdir` won't have any effect until the returned function is called. */ function mkdir( - paths: string | string[], + paths: TSource, options: IFsCreateDeleteOptions = {} ): () => Promise { return async () => { const cwd = process.cwd(); + paths = typeof paths === 'function' ? await paths() : await paths; paths = Array.isArray(paths) ? paths : [paths]; paths = paths.map((path) => absolute({ path, cwd })); diff --git a/src/public/fs/move.ts b/src/public/fs/move.ts index e2c7294..df50450 100644 --- a/src/public/fs/move.ts +++ b/src/public/fs/move.ts @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs-extra'; import { absolute, exists } from '~/utils/file'; -import { IFsUpdateOptions } from './types'; +import { IFsUpdateOptions, TSource } from './types'; import expose from '~/utils/expose'; import confirm from '~/utils/confirm'; import logger from '~/utils/logger'; @@ -14,13 +14,21 @@ export default expose(move); * @returns An asynchronous function -hence, calling `move` won't have any effect until the returned function is called. */ function move( - src: string | string[] | Promise, + src: TSource, dest: string, options: IFsUpdateOptions = {} ): () => Promise { return async () => { - src = await src; + src = typeof src === 'function' ? await src() : await src; + if (Array.isArray(src)) { + // Check dest is a folder + if (await exists(dest)) { + const stat = await fs.stat(dest); + if (!stat.isDirectory()) { + throw Error('Destination must be a folder for an array of sources'); + } + } for (let source of src) { await trunk(source, path.join(dest, path.parse(source).base), options); } diff --git a/src/public/fs/remove.ts b/src/public/fs/remove.ts index c3f13f1..b27bf9d 100644 --- a/src/public/fs/remove.ts +++ b/src/public/fs/remove.ts @@ -6,7 +6,7 @@ import { parallel } from 'promist'; import logger from '~/utils/logger'; import chalk from 'chalk'; import expose from '~/utils/expose'; -import { IFsCreateDeleteOptions } from './types'; +import { IFsCreateDeleteOptions, TSource } from './types'; export default expose(remove); /** @@ -17,12 +17,12 @@ export default expose(remove); * @returns An asynchronous function -hence, calling `remove` won't have any effect until the returned function is called. */ function remove( - paths: string | string[] | Promise, + paths: TSource, options: IFsCreateDeleteOptions = {} ): () => Promise { return async () => { const cwd = process.cwd(); - paths = await paths; + paths = typeof paths === 'function' ? await paths() : await paths; paths = Array.isArray(paths) ? paths : [paths]; paths = paths.map((path) => absolute({ path, cwd })); diff --git a/src/public/fs/types.ts b/src/public/fs/types.ts index e3fd208..a3c79a9 100644 --- a/src/public/fs/types.ts +++ b/src/public/fs/types.ts @@ -1,3 +1,9 @@ +export type TSource = + | string + | string[] + | Promise + | (() => string[] | Promise); + /** * Options taken by read *fs* functions. */