From ab935006bd2dc9c00368bed4684b3a7985e88427 Mon Sep 17 00:00:00 2001 From: bdistin Date: Tue, 12 May 2020 17:01:13 -0500 Subject: [PATCH] Prepare v0.5.0 breaking changes (#441) --- .github/workflows/codequality.yml | 18 +- .github/workflows/test.yml | 23 +- package.json | 6 +- src/fs.ts | 383 ----------------------------- src/index.ts | 86 +++---- src/nextra/copy.ts | 47 ++-- src/nextra/copyFileAtomic.ts | 10 +- src/nextra/createFile.ts | 15 +- src/nextra/createFileAtomic.ts | 6 +- src/nextra/createFileCopy.ts | 14 +- src/nextra/createFileCopyAtomic.ts | 6 +- src/nextra/createLink.ts | 16 +- src/nextra/createLinkAtomic.ts | 6 +- src/nextra/createSymlink.ts | 32 +-- src/nextra/createSymlinkAtomic.ts | 6 +- src/nextra/emptyDir.ts | 13 +- src/nextra/gunzip.ts | 6 +- src/nextra/gunzipAtomic.ts | 6 +- src/nextra/gzip.ts | 6 +- src/nextra/gzipAtomic.ts | 6 +- src/nextra/linkAtomic.ts | 10 +- src/nextra/mkdirs.ts | 28 +-- src/nextra/move.ts | 19 +- src/nextra/outputFile.ts | 15 +- src/nextra/outputFileAtomic.ts | 4 +- src/nextra/outputJSON.ts | 12 +- src/nextra/outputJSONAtomic.ts | 6 +- src/nextra/pathExists.ts | 6 +- src/nextra/readJSON.ts | 12 +- src/nextra/remove.ts | 32 +-- src/nextra/scan.ts | 30 ++- src/nextra/symlinkAtomic.ts | 10 +- src/nextra/targz.ts | 21 +- src/nextra/targzAtomic.ts | 6 +- src/nextra/unTargz.ts | 10 +- src/nextra/unTargzAtomic.ts | 5 +- src/nextra/writeFileAtomic.ts | 10 +- src/nextra/writeJSON.ts | 14 +- src/nextra/writeJSONAtomic.ts | 6 +- src/utils/Header.ts | 2 +- src/utils/Tar.ts | 8 +- src/utils/Untar.ts | 6 +- src/utils/util.ts | 8 +- test/gunzip.ts | 8 +- test/gunzipAtomic.ts | 4 +- test/gzip.ts | 4 +- test/gzipAtomic.ts | 2 +- test/scan.ts | 32 +-- test/targz.ts | 20 +- test/targzAtomic.ts | 10 +- test/unTargz.ts | 22 +- test/unTargzAtomic.ts | 10 +- 52 files changed, 355 insertions(+), 748 deletions(-) delete mode 100644 src/fs.ts diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml index eb19af24..15c63fc1 100644 --- a/.github/workflows/codequality.yml +++ b/.github/workflows/codequality.yml @@ -14,15 +14,15 @@ jobs: steps: - name: Checkout Project uses: actions/checkout@v1 - - name: Use Node.js 10 + - name: Use Node.js 12 uses: actions/setup-node@v1 with: - node-version: 10 + node-version: 12 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: ${{ runner.os }}-10-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-12-${{ hashFiles('**/yarn.lock') }} - name: Install Dependencies run: yarn - name: Run ESLint @@ -38,15 +38,15 @@ jobs: steps: - name: Checkout Project uses: actions/checkout@v1 - - name: Use Node.js 10 + - name: Use Node.js 12 uses: actions/setup-node@v1 with: - node-version: 10 + node-version: 12 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: ${{ runner.os }}-10-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-12-${{ hashFiles('**/yarn.lock') }} - name: Install Dependencies run: yarn - name: Run TSC @@ -62,15 +62,15 @@ jobs: steps: - name: Checkout Project uses: actions/checkout@v1 - - name: Use Node.js 10 + - name: Use Node.js 12 uses: actions/setup-node@v1 with: - node-version: 10 + node-version: 12 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: ${{ runner.os }}-10-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-12-${{ hashFiles('**/yarn.lock') }} - name: Install Dependencies run: yarn - name: Test Docs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 67489372..14a9014b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node_version: [10, 12, 14] + node_version: [12, 14] os: [ubuntu-latest, windows-latest, macOS-latest] steps: @@ -47,22 +47,17 @@ jobs: steps: - name: Checkout Project uses: actions/checkout@v1 - - name: Use Node.js 10 + - name: Use Node.js 12 uses: actions/setup-node@v1 with: - node-version: 10 + node-version: 12 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: Windows-10-${{ hashFiles('**\yarn.lock') }} + key: Windows-12-${{ hashFiles('**\yarn.lock') }} - name: Install Dependencies run: yarn - - uses: actions/download-artifact@v1 - name: Download Windows-10 Coverage Data - with: - name: Windows-10 - path: .nyc_output - uses: actions/download-artifact@v1 name: Download Windows-12 Coverage Data with: @@ -73,11 +68,6 @@ jobs: with: name: Windows-14 path: .nyc_output - - uses: actions/download-artifact@v1 - name: Download macOS-10 Coverage Data - with: - name: macOS-10 - path: .nyc_output - uses: actions/download-artifact@v1 name: Download macOS-12 Coverage Data with: @@ -88,11 +78,6 @@ jobs: with: name: macOS-14 path: .nyc_output - - uses: actions/download-artifact@v1 - name: Download Linux-10 Coverage Data - with: - name: Linux-10 - path: .nyc_output - uses: actions/download-artifact@v1 name: Download Linux-12 Coverage Data with: diff --git a/package.json b/package.json index 8b4566cf..8a9669bf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "fs-nextra", - "version": "0.4.7", - "description": "Node.js native fs promises with next-generation extra methods.", + "version": "0.5.0", + "description": "Node.js fs next-gen extra (nextra) methods.", "main": "dist/index.js", "scripts": { "prepublishOnly": "yarn build", @@ -37,7 +37,7 @@ "author": "BDISTIN", "license": "MIT", "engines": { - "node": ">=10.1.0" + "node": ">=12.12.0" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", diff --git a/src/fs.ts b/src/fs.ts deleted file mode 100644 index 21ee168c..00000000 --- a/src/fs.ts +++ /dev/null @@ -1,383 +0,0 @@ -/* istanbul ignore file: Types and Docs for fs-promises, should not test or require coverage */ - -import * as fs from 'fs'; -import { URL } from 'url'; - -export { createReadStream, createWriteStream, unwatchFile, watch, watchFile, Dirent, Stats, ReadStream, WriteStream, constants } from 'fs'; - -/* eslint-disable max-len */ - -/** - * Valid types for path values in 'fs'. - */ -type PathLike = string | Buffer | URL; - -export interface MakeDirectoryOptions { - /** - * Indicates whether parent folders should be created. - * @default false - */ - recursive?: boolean; - /** - * A file mode. If a string is passed, it is parsed as an octal integer. If not specified - * @default 0o777. - */ - mode?: number; -} - -/** - * [fs.promises] Asynchronously tests a user's permissions for the file specified by path. - * @param path A path to a file or directory. If a URL is provided, it must use the `file:` protocol. - * URL support is _experimental_. - */ -export function access(path: PathLike, mode?: number): Promise { return fs.promises.access(path, mode); } - -/** - * [fs.promises] Asynchronously copies `src` to `dest`. By default, `dest` is overwritten if it already exists. - * Node.js makes no guarantees about the atomicity of the copy operation. - * If an error occurs after the destination file has been opened for writing, Node.js will attempt - * to remove the destination. - * @param src A path to the source file. - * @param dest A path to the destination file. - * @param flags An optional integer that specifies the behavior of the copy operation. The only - * supported flag is `fs.constants.COPYFILE_EXCL`, which causes the copy operation to fail if - * `dest` already exists. - */ -export function copyFile(src: PathLike, dest: PathLike, flags?: number): Promise { return fs.promises.copyFile(src, dest, flags); } - -/** - * [fs.promises] Asynchronous open(2) - open and possibly create a file. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param mode A file mode. If a string is passed, it is parsed as an octal integer. If not - * supplied, defaults to `0o666`. - */ -export function open(path: PathLike, flags: string | number, mode?: string | number): Promise { return fs.promises.open(path, flags, mode); } - -/** - * [fs.promises] Asynchronously reads data from the file referenced by the supplied `FileHandle`. - * @param handle A `FileHandle`. - * @param buffer The buffer that the data will be written to. - * @param offset The offset in the buffer at which to start writing. - * @param length The number of bytes to read. - * @param position The offset from the beginning of the file from which data should be read. If - * `null`, data will be read from the current position. - */ -export function read( - handle: fs.promises.FileHandle, - buffer: any, - offset?: number | null, - length?: number | null, - position?: number | null -): Promise<{ bytesRead: number, buffer: Uint8Array }> { return fs.promises.read(handle, buffer, offset, length, position); } - -/** - * [fs.promises] Asynchronously writes `buffer` to the file referenced by the supplied `FileHandle`. - * It is unsafe to call `fsPromises.write()` multiple times on the same file without waiting for the `Promise` - * to be resolved (or rejected). For this scenario, `fs.createWriteStream` is strongly recommended. - * @param handle A `FileHandle`. - * @param buffer The buffer that the data will be written to. - * @param offset The part of the buffer to be written. If not supplied, defaults to `0`. - * @param length The number of bytes to write. If not supplied, defaults to `buffer.length - offset`. - * @param position The offset from the beginning of the file where this data should be written. If not supplied, defaults to the current position. - */ -export function write( - handle: fs.promises.FileHandle, - buffer: TBuffer, - offset?: number | null, - length?: number | null, - position?: number | null -): Promise<{ bytesWritten: number, buffer: TBuffer }>; - -/** - * [fs.promises] Asynchronously writes `string` to the file referenced by the supplied `FileHandle`. - * It is unsafe to call `fsPromises.write()` multiple times on the same file without waiting for the `Promise` - * to be resolved (or rejected). For this scenario, `fs.createWriteStream` is strongly recommended. - * @param handle A `FileHandle`. - * @param data A string to write. If something other than a string is supplied it will be coerced to a string. - * @param position The offset from the beginning of the file where this data should be written. If not supplied, defaults to the current position. - * @param encoding The expected string encoding. - */ -export function write(handle: fs.promises.FileHandle, data: any, position?: number | null, encoding?: string | null): Promise<{ bytesWritten: number, buffer: string }>; - -export function write(handle: fs.promises.FileHandle, data: TBuffer | any, offsetOrPosition?: number | null, encodingOrLength?: (TBuffer extends Buffer ? number : string) | null): Promise<{ bytesWritten: number, buffer: string | TBuffer }> { - return fs.promises.write(handle, data, offsetOrPosition, encodingOrLength as (string | null)); -} - -/** - * [fs.promises] Asynchronous rename(2) - Change the name or location of a file or directory. - * @param oldPath A path to a file. If a URL is provided, it must use the `file:` protocol. - * URL support is _experimental_. - * @param newPath A path to a file. If a URL is provided, it must use the `file:` protocol. - * URL support is _experimental_. - */ -export function rename(oldPath: PathLike, newPath: PathLike): Promise { - return fs.promises.rename(oldPath, newPath); -} - -/** - * [fs.promises] Asynchronous truncate(2) - Truncate a file to a specified length. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param len If not specified, defaults to `0`. - */ -export function truncate(path: PathLike, len?: number): Promise { - return fs.promises.truncate(path, len); -} - -/** - * [fs.promises] Asynchronous ftruncate(2) - Truncate a file to a specified length. - * @param handle A `FileHandle`. - * @param len If not specified, defaults to `0`. - */ -export function ftruncate(handle: fs.promises.FileHandle, len?: number): Promise { - return fs.promises.ftruncate(handle, len); -} - -/** - * [fs.promises] Asynchronous rmdir(2) - delete a directory. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function rmdir(path: PathLike): Promise { - return fs.promises.rmdir(path); -} - -/** - * Asynchronous fdatasync(2) - synchronize a file's in-core state with storage device. - * @param handle A `FileHandle`. - */ -export function fdatasync(handle: fs.promises.FileHandle): Promise { - return fs.promises.fdatasync(handle); -} - -/** - * [fs.promises] Asynchronous fsync(2) - synchronize a file's in-core state with the underlying storage device. - * @param handle A `FileHandle`. - */ -export function fsync(handle: fs.promises.FileHandle): Promise { - return fs.promises.fsync(handle); -} - -/** - * [fs.promises] Asynchronous mkdir(2) - create a directory. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders - * should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`. - */ -export function mkdir(path: PathLike, options?: number | string | MakeDirectoryOptions | null): Promise { - return fs.promises.mkdir(path, options); -} - -/** - * [fs.promises] Asynchronous readdir(3) - read a directory. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. - */ -export function readdir(path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): Promise; -export function readdir(path: PathLike, options: { encoding: 'buffer' } | 'buffer'): Promise; -export function readdir(path: PathLike, options?: { encoding?: string | null } | string | null): Promise { - return fs.promises.readdir(path, options); -} - -/** - * [fs.promises] Asynchronous readlink(2) - read value of a symbolic link. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. - */ -export function readlink(path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): Promise; -export function readlink(path: PathLike, options: { encoding: 'buffer' } | 'buffer'): Promise; -export function readlink(path: PathLike, options?: { encoding?: string | null } | string | null): Promise { - return fs.promises.readlink(path, options); -} - -/** - * [fs.promises] Asynchronous symlink(2) - Create a new symbolic link to an existing file. - * @param target A path to an existing file. If a URL is provided, it must use the `file:` protocol. - * @param path A path to the new symlink. If a URL is provided, it must use the `file:` protocol. - * @param type May be set to `'dir'`, `'file'`, or `'junction'` (default is `'file'`) and is only available on Windows (ignored on other platforms). - * When using `'junction'`, the `target` argument will automatically be normalized to an absolute path. - */ -export function symlink(target: PathLike, path: PathLike, type?: string | null): Promise { - return fs.promises.symlink(target, path, type); -} - -/** - * [fs.promises] Asynchronous fstat(2) - Get file status. - * @param handle A `FileHandle`. - */ -export function fstat(handle: fs.promises.FileHandle): Promise { - return fs.promises.fstat(handle); -} - -/** - * [fs.promises] Asynchronous lstat(2) - Get file status. Does not dereference symbolic links. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function lstat(path: PathLike): Promise { - return fs.promises.lstat(path); -} - -/** - * [fs.promises] Asynchronous stat(2) - Get file status. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function stat(path: PathLike): Promise { - return fs.promises.stat(path); -} - -/** - * [fs.promises] Asynchronous link(2) - Create a new link (also known as a hard link) to an existing file. - * @param existingPath A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param newPath A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function link(existingPath: PathLike, newPath: PathLike): Promise { - return fs.promises.link(existingPath, newPath); -} - -/** - * [fs.promises] Asynchronous unlink(2) - delete a name and possibly the file it refers to. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function unlink(path: PathLike): Promise { - return fs.promises.unlink(path); -} - -/** - * [fs.promises] Asynchronous fchmod(2) - Change permissions of a file. - * @param handle A `FileHandle`. - * @param mode A file mode. If a string is passed, it is parsed as an octal integer. - */ -export function fchmod(handle: fs.promises.FileHandle, mode: string | number): Promise { - return fs.promises.fchmod(handle, mode); -} - -/** - * [fs.promises] Asynchronous chmod(2) - Change permissions of a file. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param mode A file mode. If a string is passed, it is parsed as an octal integer. - */ -export function chmod(path: PathLike, mode: string | number): Promise { - return fs.promises.chmod(path, mode); -} - -/** - * [fs.promises] Asynchronous lchmod(2) - Change permissions of a file. Does not dereference symbolic links. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param mode A file mode. If a string is passed, it is parsed as an octal integer. - */ -export function lchmod(path: PathLike, mode: string | number): Promise { - return fs.promises.lchmod(path, mode); -} - -/** - * [fs.promises] Asynchronous lchown(2) - Change ownership of a file. Does not dereference symbolic links. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function lchown(path: PathLike, uid: number, gid: number): Promise { - return fs.promises.lchown(path, uid, gid); -} - -/** - * [fs.promises] Asynchronous fchown(2) - Change ownership of a file. - * @param handle A `FileHandle`. - */ -export function fchown(handle: fs.promises.FileHandle, uid: number, gid: number): Promise { - return fs.promises.fchown(handle, uid, gid); -} - -/** - * [fs.promises] Asynchronous chown(2) - Change ownership of a file. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - */ -export function chown(path: PathLike, uid: number, gid: number): Promise { - return fs.promises.chown(path, uid, gid); -} - -/** - * [fs.promises] Asynchronously change file timestamps of the file referenced by the supplied path. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param atime The last access time. If a string is provided, it will be coerced to number. - * @param mtime The last modified time. If a string is provided, it will be coerced to number. - */ -export function utimes(path: PathLike, atime: string | number | Date, mtime: string | number | Date): Promise { - return fs.promises.utimes(path, atime, mtime); -} - -/** - * [fs.promises] Asynchronously change file timestamps of the file referenced by the supplied `FileHandle`. - * @param handle A `FileHandle`. - * @param atime The last access time. If a string is provided, it will be coerced to number. - * @param mtime The last modified time. If a string is provided, it will be coerced to number. - */ -export function futimes(handle: fs.promises.FileHandle, atime: string | number | Date, mtime: string | number | Date): Promise { - return fs.promises.futimes(handle, atime, mtime); -} - -/** - * [fs.promises] Asynchronous realpath(3) - return the canonicalized absolute pathname. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. - */ -export function realpath(path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): Promise; -export function realpath(path: PathLike, options: { encoding: 'buffer' } | 'buffer'): Promise; -export function realpath(path: PathLike, options?: { encoding?: string | null } | string | null): Promise { - return fs.promises.realpath(path, options); -} - -/** - * [fs.promises] Asynchronously creates a unique temporary directory. - * Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory. - * @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used. - */ -export function mkdtemp(prefix: string, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): Promise; -export function mkdtemp(prefix: string, options: { encoding: 'buffer' } | 'buffer'): Promise; -export function mkdtemp(prefix: string, options?: { encoding?: string | null } | string | null): Promise { - return fs.promises.mkdtemp(prefix, options); -} - -/** - * [fs.promises] Asynchronously writes data to a file, replacing the file if it already exists. - * It is unsafe to call `fsPromises.writeFile()` multiple times on the same file without waiting for the `Promise` to be resolved (or rejected). - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * URL support is _experimental_. - * If a `FileHandle` is provided, the underlying file will _not_ be closed automatically. - * @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string. - * @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag. - * If `encoding` is not supplied, the default of `'utf8'` is used. - * If `mode` is not supplied, the default of `0o666` is used. - * If `mode` is a string, it is parsed as an octal integer. - * If `flag` is not supplied, the default of `'w'` is used. - */ -export function writeFile(path: PathLike | fs.promises.FileHandle, data: any, options?: { encoding?: string | null, mode?: string | number, flag?: string | number } | string | null): Promise { - return fs.promises.writeFile(path, data, options); -} - -/** - * [fs.promises] Asynchronously append data to a file, creating the file if it does not exist. - * @param file A path to a file. If a URL is provided, it must use the `file:` protocol. - * URL support is _experimental_. - * If a `FileHandle` is provided, the underlying file will _not_ be closed automatically. - * @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string. - * @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag. - * If `encoding` is not supplied, the default of `'utf8'` is used. - * If `mode` is not supplied, the default of `0o666` is used. - * If `mode` is a string, it is parsed as an octal integer. - * If `flag` is not supplied, the default of `'a'` is used. - */ -export function appendFile(path: PathLike | fs.promises.FileHandle, data: any, options?: { encoding?: string | null, mode?: string | number, flag?: string | number } | string | null): Promise { - return fs.promises.appendFile(path, data, options); -} - -/** - * [fs.promises] Asynchronously reads the entire contents of a file. - * @param path A path to a file. If a URL is provided, it must use the `file:` protocol. - * If a `FileHandle` is provided, the underlying file will _not_ be closed automatically. - * @param options An object that may contain an optional flag. - * If a flag is not provided, it defaults to `'r'`. - */ -export function readFile(path: PathLike | fs.promises.FileHandle, options?: { encoding?: null, flag?: string | number } | null): Promise; -export function readFile(path: PathLike | fs.promises.FileHandle, options?: { encoding?: BufferEncoding, flag?: string | number } | BufferEncoding): Promise; -export function readFile(path: PathLike | fs.promises.FileHandle, options?: { encoding?: string | null, flag?: string | number } | string | null): Promise { - return fs.promises.readFile(path, options); -} - - -/* eslint-enable max-len */ diff --git a/src/index.ts b/src/index.ts index f3568e63..3fbfc26e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,52 +1,34 @@ -export * from './fs'; - -export { default as copy } from './nextra/copy'; -export { default as copyFileAtomic } from './nextra/copyFileAtomic'; -export { default as createFile } from './nextra/createFile'; -export { default as createFileAtomic } from './nextra/createFileAtomic'; -export { default as createFileCopy } from './nextra/createFileCopy'; -export { default as createFileCopyAtomic } from './nextra/createFileCopyAtomic'; -export { default as createLink } from './nextra/createLink'; -export { default as createLinkAtomic } from './nextra/createLinkAtomic'; -export { default as createSymlink } from './nextra/createSymlink'; -export { default as createSymlinkAtomic } from './nextra/createSymlinkAtomic'; -export { default as emptyDir } from './nextra/emptyDir'; -export { default as emptydir } from './nextra/emptyDir'; -export { default as ensureDir } from './nextra/mkdirs'; -export { default as ensureFile } from './nextra/createFile'; -export { default as ensureFileAtomic } from './nextra/createFileAtomic'; -export { default as ensureFileCopy } from './nextra/createFileCopy'; -export { default as ensureFileCopyAtomic } from './nextra/createFileCopyAtomic'; -export { default as ensureLink } from './nextra/createLink'; -export { default as ensureLinkAtomic } from './nextra/createLinkAtomic'; -export { default as ensureSymlink } from './nextra/createSymlink'; -export { default as ensureSymlinkAtomic } from './nextra/createSymlinkAtomic'; -export { default as gunzip } from './nextra/gunzip'; -export { default as gunzipAtomic } from './nextra/gunzipAtomic'; -export { default as gzip } from './nextra/gzip'; -export { default as gzipAtomic } from './nextra/gzip'; -export { default as linkAtomic } from './nextra/linkAtomic'; -export { default as mkdirp } from './nextra/mkdirs'; -export { default as mkdirs } from './nextra/mkdirs'; -export { default as move } from './nextra/move'; -export { default as outputFile } from './nextra/outputFile'; -export { default as outputFileAtomic } from './nextra/outputFileAtomic'; -export { default as outputJSON } from './nextra/outputJSON'; -export { default as outputJSONAtomic } from './nextra/outputJSONAtomic'; -export { default as outputJson } from './nextra/outputJSON'; -export { default as outputJsonAtomic } from './nextra/outputJSONAtomic'; -export { default as pathExists } from './nextra/pathExists'; -export { default as readJSON } from './nextra/readJSON'; -export { default as readJson } from './nextra/readJSON'; -export { default as remove } from './nextra/remove'; -export { default as scan } from './nextra/scan'; -export { default as symlinkAtomic } from './nextra/symlinkAtomic'; -export { default as targz } from './nextra/targz'; -export { default as targzAtomic } from './nextra/targzAtomic'; -export { default as unTargz } from './nextra/unTargz'; -export { default as unTargzAtomic } from './nextra/unTargzAtomic'; -export { default as writeFileAtomic } from './nextra/writeFileAtomic'; -export { default as writeJSON } from './nextra/writeJSON'; -export { default as writeJSONAtomic } from './nextra/writeJSONAtomic'; -export { default as writeJson } from './nextra/writeJSON'; -export { default as writeJsonAtomic } from './nextra/writeJSONAtomic'; +export * from './nextra/copy'; +export * from './nextra/copyFileAtomic'; +export * from './nextra/createFile'; +export * from './nextra/createFileAtomic'; +export * from './nextra/createFileCopy'; +export * from './nextra/createFileCopyAtomic'; +export * from './nextra/createLink'; +export * from './nextra/createLinkAtomic'; +export * from './nextra/createSymlink'; +export * from './nextra/createSymlinkAtomic'; +export * from './nextra/emptyDir'; +export * from './nextra/mkdirs'; +export * from './nextra/gunzip'; +export * from './nextra/gunzipAtomic'; +export * from './nextra/gzip'; +export * from './nextra/gzipAtomic'; +export * from './nextra/linkAtomic'; +export * from './nextra/move'; +export * from './nextra/outputFile'; +export * from './nextra/outputFileAtomic'; +export * from './nextra/outputJSON'; +export * from './nextra/outputJSONAtomic'; +export * from './nextra/pathExists'; +export * from './nextra/readJSON'; +export * from './nextra/remove'; +export * from './nextra/scan'; +export * from './nextra/symlinkAtomic'; +export * from './nextra/targz'; +export * from './nextra/targzAtomic'; +export * from './nextra/unTargz'; +export * from './nextra/unTargzAtomic'; +export * from './nextra/writeFileAtomic'; +export * from './nextra/writeJSON'; +export * from './nextra/writeJSONAtomic'; diff --git a/src/nextra/copy.ts b/src/nextra/copy.ts index 6119d028..82e9dcb7 100644 --- a/src/nextra/copy.ts +++ b/src/nextra/copy.ts @@ -1,10 +1,9 @@ import { resolve, dirname, join, basename } from 'path'; +import { promises as fsp, Stats } from 'fs'; import { replaceEsc, isSrcKid } from '../utils/util'; -import { access, readlink, mkdir, symlink, copyFile, lstat, stat, chmod, readdir, Stats } from '../fs'; - -import mkdirs from './mkdirs'; -import remove from './remove'; +import { mkdirs } from './mkdirs'; +import { remove } from './remove'; type CopyFilter = (source: string, target: string) => boolean; @@ -40,19 +39,19 @@ interface CopyData { * @param destination The destination path * @param options Options for the copy, or a filter function */ -export default async function copy(source: string, destination: string, options: CopyOptions | CopyFilter = {}): Promise { +export async function copy(source: string, destination: string, options: CopyOptions | CopyFilter = {}): Promise { const copyOptions = resolveCopyOptions(source, destination, options); if (resolve(source) === resolve(destination)) { if (copyOptions.errorOnExist) throw new Error('FS-NEXTRA: Source and destination must not be the same.'); - await access(source); + await fsp.access(source); } else { await mkdirs(dirname(destination)); await startCopy(source, copyOptions); } } -const resolveCopyOptions = (source: string, destination: string, options: CopyOptions | CopyFilter): CopyData => { +function resolveCopyOptions(source: string, destination: string, options: CopyOptions | CopyFilter): CopyData { if (typeof options === 'function') options = { filter: options }; return { @@ -63,39 +62,39 @@ const resolveCopyOptions = (source: string, destination: string, options: CopyOp preserveTimestamps: Boolean(options.preserveTimestamps), errorOnExist: Boolean(options.errorOnExist) }; -}; +} -const isWritable = async (myPath: string): Promise => { +async function isWritable(myPath: string): Promise { try { - await lstat(myPath); + await fsp.lstat(myPath); return false; } catch (err) { return err.code === 'ENOENT'; } -}; +} -const startCopy = async (mySource: string, options: CopyData): Promise => { +async function startCopy(mySource: string, options: CopyData): Promise { if (!options.filter(mySource, options.targetPath)) return; - const stats = await lstat(mySource); + const stats = await fsp.lstat(mySource); const target = mySource.replace(options.currentPath, replaceEsc(options.targetPath)); if (stats.isDirectory()) await copyDirectory(mySource, stats, target, options); else await copyOther(mySource, stats, target, options); -}; +} -const copyDirectory = async (mySource: string, stats: Stats, target: string, options: CopyData): Promise => { +async function copyDirectory(mySource: string, stats: Stats, target: string, options: CopyData): Promise { if (isSrcKid(mySource, target)) throw new Error('FS-NEXTRA: Copying a parent directory into a child will result in an infinite loop.'); if (await isWritable(target)) { - await mkdir(target, stats.mode); - await chmod(target, stats.mode); + await fsp.mkdir(target, stats.mode); + await fsp.chmod(target, stats.mode); } - const items = await readdir(mySource); + const items = await fsp.readdir(mySource); await Promise.all(items.map((item): Promise => startCopy(join(mySource, item), options))); -}; +} -const copyOther = async (mySource: string, stats: Stats, target: string, options: CopyData): Promise => { +async function copyOther(mySource: string, stats: Stats, target: string, options: CopyData): Promise { try { - const tstats = await stat(target); + const tstats = await fsp.stat(target); if (tstats && tstats.isDirectory()) target = join(target, basename(mySource)); } catch (err) { // noop @@ -107,6 +106,6 @@ const copyOther = async (mySource: string, stats: Stats, target: string, options await remove(target); } - if (stats.isSymbolicLink()) await symlink(await readlink(mySource), target); - else await copyFile(mySource, target); -}; + if (stats.isSymbolicLink()) await fsp.symlink(await fsp.readlink(mySource), target); + else await fsp.copyFile(mySource, target); +} diff --git a/src/nextra/copyFileAtomic.ts b/src/nextra/copyFileAtomic.ts index 68a1fc3e..601edafe 100644 --- a/src/nextra/copyFileAtomic.ts +++ b/src/nextra/copyFileAtomic.ts @@ -1,7 +1,7 @@ -import { tempFile } from '../utils/util'; -import { copyFile } from '../fs'; +import { promises as fsp } from 'fs'; -import move from './move'; +import { tempFile } from '../utils/util'; +import { move } from './move'; /** * @function copyFileAtomic @@ -10,8 +10,8 @@ import move from './move'; * @param destination The path to the file destination * @param options The write options or the encoding string. */ -export default async function copyFileAtomic(source: string, destination: string): Promise { +export async function copyFileAtomic(source: string, destination: string): Promise { const tempPath = tempFile(); - await copyFile(source, tempPath); + await fsp.copyFile(source, tempPath); await move(tempPath, destination, { overwrite: true }); } diff --git a/src/nextra/createFile.ts b/src/nextra/createFile.ts index d5e363a2..1b1bbe01 100644 --- a/src/nextra/createFile.ts +++ b/src/nextra/createFile.ts @@ -1,10 +1,9 @@ import { dirname } from 'path'; +import { promises as fsp } from 'fs'; -import { writeFile } from '../fs'; - -import writeFileAtomic from './writeFileAtomic'; -import mkdirs from './mkdirs'; -import pathExists from './pathExists'; +import { writeFileAtomic } from './writeFileAtomic'; +import { mkdirs } from './mkdirs'; +import { pathExists } from './pathExists'; /** * Creates an empty file, making all folders required to satisfy the given file path. @@ -20,11 +19,13 @@ import pathExists from './pathExists'; * @param file Path of the file you want to create * @param atomic Whether the operation should run atomically */ -export default async function createFile(file: string, atomic = false): Promise { +export async function createFile(file: string, atomic = false): Promise { if (await pathExists(file)) return; await mkdirs(dirname(file)); - const writeMethod = atomic ? writeFileAtomic : writeFile; + const writeMethod = atomic ? writeFileAtomic : fsp.writeFile; await writeMethod(file, ''); } + +export const ensureFile = createFile; diff --git a/src/nextra/createFileAtomic.ts b/src/nextra/createFileAtomic.ts index cad5b682..af38c25e 100644 --- a/src/nextra/createFileAtomic.ts +++ b/src/nextra/createFileAtomic.ts @@ -1,4 +1,4 @@ -import createFile from './createFile'; +import { createFile } from './createFile'; /** * Creates an file copy, making all folders required to satisfy the given file path atomically. @@ -12,6 +12,8 @@ import createFile from './createFile'; * @memberof fsn/nextra * @param file Path of the file you want to create */ -export default function createFileAtomic(file: string): Promise { +export function createFileAtomic(file: string): Promise { return createFile(file, true); } + +export const ensureFileAtomic = createFileAtomic; diff --git a/src/nextra/createFileCopy.ts b/src/nextra/createFileCopy.ts index 94b33a3d..b0f8e4d2 100644 --- a/src/nextra/createFileCopy.ts +++ b/src/nextra/createFileCopy.ts @@ -1,9 +1,9 @@ import { dirname, resolve } from 'path'; -import { access, copyFile } from '../fs'; +import { promises as fsp } from 'fs'; -import copyFileAtomic from './copyFileAtomic'; -import mkdirs from './mkdirs'; +import { copyFileAtomic } from './copyFileAtomic'; +import { mkdirs } from './mkdirs'; /** * Creates an file copy, making all folders required to satisfy the given file path. @@ -21,13 +21,15 @@ import mkdirs from './mkdirs'; * @param destination The path to the file destination * @param atomic Whether the operation should run atomically */ -export default async function createFileCopy(source: string, destination: string, atomic = false): Promise { +export async function createFileCopy(source: string, destination: string, atomic = false): Promise { if (resolve(source) === resolve(destination)) { - await access(source); + await fsp.access(source); } else { await mkdirs(dirname(destination)); - const copyMethod = atomic ? copyFileAtomic : copyFile; + const copyMethod = atomic ? copyFileAtomic : fsp.copyFile; await copyMethod(source, destination); } } + +export const ensureFileCopy = createFileCopy; diff --git a/src/nextra/createFileCopyAtomic.ts b/src/nextra/createFileCopyAtomic.ts index 176faaae..dd623ca1 100644 --- a/src/nextra/createFileCopyAtomic.ts +++ b/src/nextra/createFileCopyAtomic.ts @@ -1,4 +1,4 @@ -import createFileCopy from './createFileCopy'; +import { createFileCopy } from './createFileCopy'; /** * Creates a file copy atomically, making all folders required to satisfy the given file path. @@ -14,6 +14,8 @@ import createFileCopy from './createFileCopy'; * @param source The path to the file you want to copy * @param destination The path to the file destination */ -export default async function createFileCopyAtomic(source: string, destination: string): Promise { +export async function createFileCopyAtomic(source: string, destination: string): Promise { return createFileCopy(source, destination, true); } + +export const ensureFileCopyAtomic = createFileCopyAtomic; diff --git a/src/nextra/createLink.ts b/src/nextra/createLink.ts index d6194e11..eca03fc8 100644 --- a/src/nextra/createLink.ts +++ b/src/nextra/createLink.ts @@ -1,10 +1,10 @@ import { dirname } from 'path'; -import { lstat, link } from '../fs'; +import { promises as fsp } from 'fs'; -import linkAtomic from './linkAtomic'; -import mkdirs from './mkdirs'; -import pathExists from './pathExists'; +import { linkAtomic } from './linkAtomic'; +import { mkdirs } from './mkdirs'; +import { pathExists } from './pathExists'; /** * Creates a hard file link, making all folders required to satisfy the given file path. @@ -22,12 +22,14 @@ import pathExists from './pathExists'; * @param destination The destination path of the file * @param atomic Whether the operation should run atomically */ -export default async function createLink(source: string, destination: string, atomic = false): Promise { +export async function createLink(source: string, destination: string, atomic = false): Promise { if (await pathExists(destination)) return; - await lstat(source); + await fsp.lstat(source); await mkdirs(dirname(destination)); - const linkMethod = atomic ? linkAtomic : link; + const linkMethod = atomic ? linkAtomic : fsp.link; await linkMethod(source, destination); } + +export const ensureLink = createLink; diff --git a/src/nextra/createLinkAtomic.ts b/src/nextra/createLinkAtomic.ts index c323849d..7f52f24c 100644 --- a/src/nextra/createLinkAtomic.ts +++ b/src/nextra/createLinkAtomic.ts @@ -1,4 +1,4 @@ -import createLink from './createLink'; +import { createLink } from './createLink'; /** * Creates a hard file link, making all folders required to satisfy the given file path atomically. @@ -14,6 +14,8 @@ import createLink from './createLink'; * @param source The source path of the file * @param destination The destination path of the file */ -export default function createLinkAtomic(source: string, destination: string): Promise { +export function createLinkAtomic(source: string, destination: string): Promise { return createLink(source, destination, true); } + +export const ensureLinkAtomic = createLinkAtomic; diff --git a/src/nextra/createSymlink.ts b/src/nextra/createSymlink.ts index df1f6947..32413238 100644 --- a/src/nextra/createSymlink.ts +++ b/src/nextra/createSymlink.ts @@ -1,9 +1,9 @@ import { dirname, join, isAbsolute, relative, resolve } from 'path'; -import { symlink, lstat } from '../fs'; +import { promises as fsp } from 'fs'; -import pathExists from './pathExists'; -import mkdirs from './mkdirs'; -import symlinkAtomic from './symlinkAtomic'; +import { pathExists } from './pathExists'; +import { mkdirs } from './mkdirs'; +import { symlinkAtomic } from './symlinkAtomic'; /** @@ -39,33 +39,35 @@ interface SymLinkPaths { * @param type The type of symlink you are creating * @param atomic Whether the operation should run atomically */ -export default async function createSymlink(source: string, destination: string, atomic?: boolean): Promise; -export default async function createSymlink(source: string, destination: string, type?: SymLinkType, atomic?: boolean): Promise; -export default async function createSymlink(source: string, destination: string, type?: SymLinkType | boolean, atomic = false): Promise { +export async function createSymlink(source: string, destination: string, atomic?: boolean): Promise; +export async function createSymlink(source: string, destination: string, type?: SymLinkType, atomic?: boolean): Promise; +export async function createSymlink(source: string, destination: string, type?: SymLinkType | boolean, atomic = false): Promise { if (await pathExists(destination)) return; if (typeof type === 'boolean') [atomic, type] = [type, undefined]; await mkdirs(dirname(destination)); const relativePath = await symlinkPaths(source, destination); - const symlinkMethod = atomic ? symlinkAtomic : symlink; + const symlinkMethod = atomic ? symlinkAtomic : fsp.symlink; await symlinkMethod(relativePath.toDst, resolve(destination), type as SymLinkType || await symlinkType(relativePath.toCwd)); } -const symlinkPaths = async (srcpath: string, dstPath: string): Promise => { +async function symlinkPaths(srcpath: string, dstPath: string): Promise { if (isAbsolute(srcpath)) { - await lstat(srcpath); + await fsp.lstat(srcpath); return { toCwd: srcpath, toDst: srcpath }; } const dstDir = dirname(dstPath); const relativeToDst = join(dstDir, srcpath); /* istanbul ignore next: Doesn't get tested on all OSs */ if (await pathExists(relativeToDst)) return { toCwd: relativeToDst, toDst: srcpath }; - await lstat(srcpath); + await fsp.lstat(srcpath); return { toCwd: srcpath, toDst: relative(dstDir, srcpath) }; -}; +} -const symlinkType = async (srcpath: string): Promise => { - const stats = await lstat(srcpath); +async function symlinkType(srcpath: string): Promise { + const stats = await fsp.lstat(srcpath); return stats.isDirectory() ? 'dir' : 'file'; -}; +} + +export const ensureSymlink = createSymlink; diff --git a/src/nextra/createSymlinkAtomic.ts b/src/nextra/createSymlinkAtomic.ts index 07540e0d..69b41285 100644 --- a/src/nextra/createSymlinkAtomic.ts +++ b/src/nextra/createSymlinkAtomic.ts @@ -1,4 +1,4 @@ -import { default as createSymlink, SymLinkType } from './createSymlink'; +import { createSymlink, SymLinkType } from './createSymlink'; /** * Creates a soft file link, making all folders required to satisfy the given file path atomically. @@ -18,6 +18,8 @@ import { default as createSymlink, SymLinkType } from './createSymlink'; * @param {SymLinkType} type The type of symlink you are creating * @returns {Promise} */ -export default function createSymlinkAtomic(source: string, destination: string, type?: SymLinkType): Promise { +export function createSymlinkAtomic(source: string, destination: string, type?: SymLinkType): Promise { return createSymlink(source, destination, type, true); } + +export const ensureSymlinkAtomic = createSymlinkAtomic; diff --git a/src/nextra/emptyDir.ts b/src/nextra/emptyDir.ts index bc76f861..8ed0199e 100644 --- a/src/nextra/emptyDir.ts +++ b/src/nextra/emptyDir.ts @@ -1,9 +1,8 @@ import { join } from 'path'; +import { promises as fsp } from 'fs'; -import { readdir } from '../fs'; - -import mkdirs from './mkdirs'; -import remove from './remove'; +import { mkdirs } from './mkdirs'; +import { remove } from './remove'; /** * Deletes all directories and files within the provided directory. @@ -17,11 +16,13 @@ import remove from './remove'; * @memberof fsn/nextra * @param dir The directory you wish to empty */ -export default async function emptyDir(dir: string): Promise { +export async function emptyDir(dir: string): Promise { try { - const items = await readdir(dir); + const items = await fsp.readdir(dir); await Promise.all(items.map((item): Promise => remove(join(dir, item)))); } catch (err) { await mkdirs(dir); } } + +export const emptydir = emptyDir; diff --git a/src/nextra/gunzip.ts b/src/nextra/gunzip.ts index 8fb4692f..e90001e6 100644 --- a/src/nextra/gunzip.ts +++ b/src/nextra/gunzip.ts @@ -1,8 +1,8 @@ import { createGunzip } from 'zlib'; +import { createWriteStream, createReadStream } from 'fs'; -import { createWriteStream, createReadStream } from '../fs'; import { pipelinePromise } from '../utils/util'; -import gunzipAtomic from './gunzipAtomic'; +import { gunzipAtomic } from './gunzipAtomic'; /** * Un-Gzips a file @@ -12,7 +12,7 @@ import gunzipAtomic from './gunzipAtomic'; * @param inputFile The filepath of the archive * @param atomic If the unzip file should be created atomically */ -export default async function gzip(fileName: string, inputFile: string, atomic = false): Promise { +export async function gunzip(fileName: string, inputFile: string, atomic = false): Promise { if (atomic) return gunzipAtomic(fileName, inputFile); return pipelinePromise( diff --git a/src/nextra/gunzipAtomic.ts b/src/nextra/gunzipAtomic.ts index 7ce8a45f..59057918 100644 --- a/src/nextra/gunzipAtomic.ts +++ b/src/nextra/gunzipAtomic.ts @@ -1,5 +1,5 @@ -import gunzip from './gunzip'; -import move from './move'; +import { gunzip } from './gunzip'; +import { move } from './move'; import { tempFile } from '../utils/util'; /** @@ -9,7 +9,7 @@ import { tempFile } from '../utils/util'; * @param fileName The filename of the output file * @param inputFile The filepath of the archive */ -export default async function gzipAtomic(fileName: string, inputFile: string): Promise { +export async function gunzipAtomic(fileName: string, inputFile: string): Promise { const tempPath = tempFile(); await gunzip(tempPath, inputFile); return move(tempPath, fileName, { overwrite: true }); diff --git a/src/nextra/gzip.ts b/src/nextra/gzip.ts index 085d0c4e..9bea3e08 100644 --- a/src/nextra/gzip.ts +++ b/src/nextra/gzip.ts @@ -1,8 +1,8 @@ import { createGzip } from 'zlib'; +import { createWriteStream, createReadStream } from 'fs'; -import { createWriteStream, createReadStream } from '../fs'; import { pipelinePromise } from '../utils/util'; -import gzipAtomic from './gzipAtomic'; +import { gzipAtomic } from './gzipAtomic'; /** * Gzips a file @@ -12,7 +12,7 @@ import gzipAtomic from './gzipAtomic'; * @param inputFile The filepath of the input file * @param atomic If the gzip file should be created */ -export default async function gzip(fileName: string, inputFile: string, atomic = false): Promise { +export async function gzip(fileName: string, inputFile: string, atomic = false): Promise { if (atomic) return gzipAtomic(fileName, inputFile); return pipelinePromise( diff --git a/src/nextra/gzipAtomic.ts b/src/nextra/gzipAtomic.ts index 13be8fac..85f9b0b8 100644 --- a/src/nextra/gzipAtomic.ts +++ b/src/nextra/gzipAtomic.ts @@ -1,5 +1,5 @@ -import gzip from './gzip'; -import move from './move'; +import { gzip } from './gzip'; +import { move } from './move'; import { tempFile } from '../utils/util'; /** @@ -9,7 +9,7 @@ import { tempFile } from '../utils/util'; * @param fileName The filename of the archive * @param inputFile The filepath of the input file */ -export default async function gzipAtomic(fileName: string, inputFile: string): Promise { +export async function gzipAtomic(fileName: string, inputFile: string): Promise { const tempPath = tempFile(); await gzip(tempPath, inputFile); return move(tempPath, fileName, { overwrite: true }); diff --git a/src/nextra/linkAtomic.ts b/src/nextra/linkAtomic.ts index abee5fd3..b66b582c 100644 --- a/src/nextra/linkAtomic.ts +++ b/src/nextra/linkAtomic.ts @@ -1,7 +1,7 @@ -import { tempFile } from '../utils/util'; -import { link } from '../fs'; +import { promises as fsp } from 'fs'; -import move from './move'; +import { tempFile } from '../utils/util'; +import { move } from './move'; /** * Creates a hard file link atomically. @@ -10,8 +10,8 @@ import move from './move'; * @param source The source path of the file * @param destination The destination path of the file */ -export default async function linkAtomic(source: string, destination: string): Promise { +export async function linkAtomic(source: string, destination: string): Promise { const tempPath = tempFile(); - await link(source, tempPath); + await fsp.link(source, tempPath); await move(tempPath, destination, { overwrite: true }); } diff --git a/src/nextra/mkdirs.ts b/src/nextra/mkdirs.ts index 5c84c1e5..a2747f71 100644 --- a/src/nextra/mkdirs.ts +++ b/src/nextra/mkdirs.ts @@ -1,7 +1,7 @@ -import { resolve, dirname, normalize, sep } from 'path'; +import { resolve, dirname } from 'path'; +import { promises as fsp } from 'fs'; -import { isWindows } from '../utils/util'; -import { stat, mkdir } from '../fs'; +import { isWindows, invalidWin32Path } from '../utils/util'; /** * @typedef {Object} MkdirsOptions @@ -33,7 +33,7 @@ export interface MkdirsOptions { * @param path The path you wish to make * @param options Options for making the directories */ -export default async function mkdirs(path: string, options?: MkdirsOptions | number): Promise { +export async function mkdirs(path: string, options?: MkdirsOptions | number): Promise { const dirOptions = resolveOptions(options); if (isWindows && invalidWin32Path(path)) { @@ -47,25 +47,25 @@ export default async function mkdirs(path: string, options?: MkdirsOptions | num path = resolve(path); try { - await mkdir(path, dirOptions.mode); + await fsp.mkdir(path, dirOptions.mode); } catch (err) { if (err.code === 'ENOENT') { await mkdirs(dirname(path), dirOptions); await mkdirs(path, dirOptions); return; } - const myStat = await stat(path); + const myStat = await fsp.stat(path); if (myStat.isDirectory()) return; throw err; } } -const resolveOptions = (options: MkdirsOptions | number = {}): MkdirsOptions => ({ - // eslint-disable-next-line no-bitwise - mode: typeof options === 'number' ? options : options.mode || 0o0777 & ~process.umask() -}); +function resolveOptions(options: MkdirsOptions | number = {}): MkdirsOptions { + return { + // eslint-disable-next-line no-bitwise + mode: typeof options === 'number' ? options : options.mode || 0o0777 & ~process.umask() + }; +} -const invalidWin32Path = (myPath: string): boolean => { - const root = normalize(resolve(myPath)).split(sep); - return /[<>:"|?*]/.test(myPath.replace(root[0], '')); -}; +export const mkdirp = mkdirs; +export const ensureDir = mkdirs; diff --git a/src/nextra/move.ts b/src/nextra/move.ts index 65b1bcb0..493aedbc 100644 --- a/src/nextra/move.ts +++ b/src/nextra/move.ts @@ -1,12 +1,11 @@ import { resolve, dirname } from 'path'; +import { promises as fsp } from 'fs'; import { isSrcKid } from '../utils/util'; -import { access, rename, lstat } from '../fs'; - -import remove from './remove'; -import mkdirs from './mkdirs'; -import pathExists from './pathExists'; -import copy from './copy'; +import { remove } from './remove'; +import { mkdirs } from './mkdirs'; +import { pathExists } from './pathExists'; +import { copy } from './copy'; /** * @typedef {Object} MoveOptions @@ -24,11 +23,11 @@ export interface MoveOptions { * @param destination The destination path of the file * @param options The options for the move */ -export default async function move(source: string, destination: string, options: MoveOptions = {}): Promise { +export async function move(source: string, destination: string, options: MoveOptions = {}): Promise { const overwrite = options.overwrite || false; - if (resolve(source) === resolve(destination)) return access(source); + if (resolve(source) === resolve(destination)) return fsp.access(source); - const myStat = await lstat(source); + const myStat = await fsp.lstat(source); if (myStat.isDirectory() && isSrcKid(source, destination)) { throw new Error('FS-NEXTRA: Moving a parent directory into a child will result in an infinite loop.'); } @@ -42,7 +41,7 @@ export default async function move(source: string, destination: string, options: } try { - return await rename(source, destination); + return await fsp.rename(source, destination); } catch (err) { /* istanbul ignore next: Can't test via CI */ if (err.code === 'EXDEV') { diff --git a/src/nextra/outputFile.ts b/src/nextra/outputFile.ts index 395f0dab..b398a2ca 100644 --- a/src/nextra/outputFile.ts +++ b/src/nextra/outputFile.ts @@ -1,9 +1,8 @@ import { dirname } from 'path'; +import { promises as fsp } from 'fs'; -import { writeFile } from '../fs'; - -import { default as writeFileAtomic, WriteOptions } from './writeFileAtomic'; -import mkdirs from './mkdirs'; +import { writeFileAtomic, WriteOptions } from './writeFileAtomic'; +import { mkdirs } from './mkdirs'; /** * Writes a file to disk, creating all directories needed to meet the filepath provided. @@ -14,13 +13,13 @@ import mkdirs from './mkdirs'; * @param options The write options or the encoding string. * @param atomic {description} */ -export default async function outputFile(file: string, data: string | Buffer | Uint8Array, atomic?: boolean): Promise; -export default async function outputFile(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string, atomic?: boolean): Promise; -export default async function outputFile(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string | boolean, atomic = false): Promise { +export async function outputFile(file: string, data: string | Buffer | Uint8Array, atomic?: boolean): Promise; +export async function outputFile(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string, atomic?: boolean): Promise; +export async function outputFile(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string | boolean, atomic = false): Promise { if (typeof options === 'boolean') [atomic, options] = [options, {}]; await mkdirs(dirname(file)); - const writeMethod = atomic ? writeFileAtomic : writeFile; + const writeMethod = atomic ? writeFileAtomic : fsp.writeFile; await writeMethod(file, data, options); } diff --git a/src/nextra/outputFileAtomic.ts b/src/nextra/outputFileAtomic.ts index 036ac17b..698a366e 100644 --- a/src/nextra/outputFileAtomic.ts +++ b/src/nextra/outputFileAtomic.ts @@ -1,4 +1,4 @@ -import outputFile from './outputFile'; +import { outputFile } from './outputFile'; import { WriteOptions } from './writeFileAtomic'; /** @@ -10,6 +10,6 @@ import { WriteOptions } from './writeFileAtomic'; * @param options The write options or the encoding string. * @returns {Promise} */ -export default function outputFileAtomic(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string): Promise { +export function outputFileAtomic(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string): Promise { return outputFile(file, data, options, true); } diff --git a/src/nextra/outputJSON.ts b/src/nextra/outputJSON.ts index 2e6c78b1..31ddc665 100644 --- a/src/nextra/outputJSON.ts +++ b/src/nextra/outputJSON.ts @@ -1,7 +1,7 @@ import { dirname } from 'path'; -import { default as writeJSON, JsonOptions } from './writeJSON'; -import mkdirs from './mkdirs'; +import { writeJSON, JsonOptions } from './writeJSON'; +import { mkdirs } from './mkdirs'; /** @@ -22,12 +22,14 @@ import mkdirs from './mkdirs'; * @param options The write options or the encoding string. * @param atomic If the operation should be done atomically */ -export default async function outputJSON(file: string, data: any, atomic?: boolean): Promise; -export default async function outputJSON(file: string, data: any, options?: JsonOptions, atomic?: boolean): Promise; -export default async function outputJSON(file: string, data: any, options?: JsonOptions | boolean, atomic = false): Promise { +export async function outputJSON(file: string, data: any, atomic?: boolean): Promise; +export async function outputJSON(file: string, data: any, options?: JsonOptions, atomic?: boolean): Promise; +export async function outputJSON(file: string, data: any, options?: JsonOptions | boolean, atomic = false): Promise { if (typeof options === 'boolean') [atomic, options] = [options, {}]; await mkdirs(dirname(file)); return writeJSON(file, data, options, atomic); } + +export const outputJson = outputJSON; diff --git a/src/nextra/outputJSONAtomic.ts b/src/nextra/outputJSONAtomic.ts index 5d33b9ed..09f5efb6 100644 --- a/src/nextra/outputJSONAtomic.ts +++ b/src/nextra/outputJSONAtomic.ts @@ -1,4 +1,4 @@ -import outputJSON from './outputJSON'; +import { outputJSON } from './outputJSON'; import { JsonOptions } from './writeJSON'; /** @@ -17,6 +17,8 @@ import { JsonOptions } from './writeJSON'; * @param data The data to write to file * @param options The write options or the encoding string. */ -export default function outputJSONAtomic(file: string, data: any, options?: JsonOptions): Promise { +export function outputJSONAtomic(file: string, data: any, options?: JsonOptions): Promise { return outputJSON(file, data, options, true); } + +export const outputJsonAtomic = outputJSONAtomic; diff --git a/src/nextra/pathExists.ts b/src/nextra/pathExists.ts index 499515db..632facc2 100644 --- a/src/nextra/pathExists.ts +++ b/src/nextra/pathExists.ts @@ -1,4 +1,4 @@ -import { access } from '../fs'; +import { promises as fsp } from 'fs'; /** * Checks if a path exists. @@ -6,9 +6,9 @@ import { access } from '../fs'; * @memberof fsn/nextra * @param path The path to check */ -export default async function pathExists(path: string): Promise { +export async function pathExists(path: string): Promise { try { - await access(path); + await fsp.access(path); return true; } catch (err) { return false; diff --git a/src/nextra/readJSON.ts b/src/nextra/readJSON.ts index 78d7c21f..384f7637 100644 --- a/src/nextra/readJSON.ts +++ b/src/nextra/readJSON.ts @@ -1,4 +1,4 @@ -import { readFile } from '../fs'; +import { promises as fsp } from 'fs'; export type BufferEncoding = 'ascii' | 'utf8' | 'utf16le' | 'ucs2' | 'base64' | 'latin1' | 'binary' | 'hex'; @@ -30,13 +30,15 @@ export interface ReadJSONOptions { * @param {ReadJSONOptions|string} [options = {}] The options for reading json or the encoding string * @returns {Promise} */ -export default async function readJSON(file: string, options: ReadJSONOptions | BufferEncoding = { flag: 'r' }): Promise { +export async function readJSON(file: string, options: ReadJSONOptions | BufferEncoding = { flag: 'r' }): Promise { if (typeof options === 'string') options = { encoding: options, flag: 'r' }; - const content = await readFile(file, options); + const content = await fsp.readFile(file, options); return JSON.parse(stripBom(content), options.reviver); } -const stripBom = (content: string | Buffer): string => { +function stripBom(content: string | Buffer): string { if (Buffer.isBuffer(content)) content = content.toString('utf8'); return content.replace(/^\uFEFF/, ''); -}; +} + +export const readJson = readJSON; diff --git a/src/nextra/remove.ts b/src/nextra/remove.ts index f5be379a..0fa22cfc 100644 --- a/src/nextra/remove.ts +++ b/src/nextra/remove.ts @@ -1,7 +1,7 @@ import { join } from 'path'; +import { promises as fsp } from 'fs'; import { isWindows, setTimeoutPromise } from '../utils/util'; -import { lstat, unlink, rmdir, chmod, readdir } from '../fs'; /** * @typedef {Object} RemoveOptions @@ -19,7 +19,7 @@ export interface RemoveOptions { * @param path The path to remove * @param options The remove options */ -export default async function remove(path: string, options: RemoveOptions = {}): Promise { +export async function remove(path: string, options: RemoveOptions = {}): Promise { options.maxBusyTries = typeof options.maxBusyTries === 'undefined' ? 3 : options.maxBusyTries; for (let buysTries = 0; buysTries < options.maxBusyTries; buysTries++) { @@ -39,9 +39,9 @@ export default async function remove(path: string, options: RemoveOptions = {}): } } -const rimraf = async (myPath: string, options: RemoveOptions): Promise => { +async function rimraf(myPath: string, options: RemoveOptions): Promise { try { - const stats = await lstat(myPath); + const stats = await fsp.lstat(myPath); if (stats.isDirectory()) return removeDir(myPath, options); } catch (err) { /* istanbul ignore next: Windows */ @@ -50,7 +50,7 @@ const rimraf = async (myPath: string, options: RemoveOptions): Promise => } try { - return await unlink(myPath); + return await fsp.unlink(myPath); } catch (er) { /* istanbul ignore next: Windows */ if (er.code === 'EPERM') return isWindows ? fixWinEPERM(myPath, options) : removeDir(myPath, options, er); @@ -58,27 +58,27 @@ const rimraf = async (myPath: string, options: RemoveOptions): Promise => if (er.code === 'EISDIR') return removeDir(myPath, options, er); else throw er; } -}; +} /* istanbul ignore next: Windows */ -const fixWinEPERM = async (myPath: string, options: RemoveOptions): Promise => { - await chmod(myPath, 0o666); +async function fixWinEPERM(myPath: string, options: RemoveOptions): Promise { + await fsp.chmod(myPath, 0o666); return rimraf(myPath, options); -}; +} -const removeDir = async (myPath: string, options: RemoveOptions, originalEr = null): Promise => { +async function removeDir(myPath: string, options: RemoveOptions, originalEr = null): Promise { try { - return await rmdir(myPath); + return await fsp.rmdir(myPath); } catch (err) { /* istanbul ignore else: Difficult to reproduce */ if (['ENOTEMPTY', 'EEXIST', 'EPERM'].includes(err.code)) return rmkids(myPath, options); else if (err.code === 'ENOTDIR') throw originalEr; else throw err; } -}; +} -const rmkids = async (myPath: string, options: RemoveOptions): Promise => { - const files = await readdir(myPath); +async function rmkids(myPath: string, options: RemoveOptions): Promise { + const files = await fsp.readdir(myPath); await Promise.all(files.map((file): Promise => remove(join(myPath, file), options))); - return rmdir(myPath); -}; + return fsp.rmdir(myPath); +} diff --git a/src/nextra/scan.ts b/src/nextra/scan.ts index 0281e846..60368d9a 100644 --- a/src/nextra/scan.ts +++ b/src/nextra/scan.ts @@ -1,26 +1,17 @@ import { resolve, join } from 'path'; -import { lstat, readdir, Stats } from '../fs'; +import { promises as fsp, Dirent } from 'fs'; /** * @typedef {Object} ScanOptions * @memberof fsn/nextra - * @property {Function} [filter] A filter function receiving (stats, path) to determine if the returned map should include a given entry + * @property {Function} [filter] A filter function receiving (dirent, path) to determine if the returned map should include a given entry * @property {number} [depthLimit] How many directories deep the scan should go (0 is just the children of the passed root directory, no subdirectory files) */ export interface ScanOptions { - filter?: (stats: Stats, dir: string) => boolean; + filter?: (dirent: Dirent, path: string) => boolean; depthLimit?: number; } -const scanDeep = async (dir: string, results: Map, level: number, options: ScanOptions): Promise> => { - const stats = await lstat(dir); - if (!options.filter || options.filter(stats, dir)) results.set(dir, stats); - if (stats.isDirectory() && (typeof options.depthLimit === 'undefined' || ++level <= options.depthLimit)) { - await Promise.all((await readdir(dir)).map((part): Promise> => scanDeep(join(dir, part), results, level, options))); - } - return results; -}; - /** * Recursively scans a directory, returning a map of stats keyed on the full path to the item. * @function scan @@ -28,6 +19,19 @@ const scanDeep = async (dir: string, results: Map, level: number, * @param root The path to scan * @param options The options for the scan */ -export default function scan(root: string, options: ScanOptions = {}): Promise> { +export function scan(root: string, options: ScanOptions = {}): Promise> { return scanDeep(resolve(root), new Map(), 0, options); } + +async function scanDeep(path: string, results: Map, level: number, options: ScanOptions): Promise> { + const dir = await fsp.opendir(path); + + for await (const dirent of dir) { + if (!options.filter || options.filter(dirent, path)) results.set(join(path, dirent.name), dirent); + if (dirent.isDirectory() && (typeof options.depthLimit === 'undefined' || level < options.depthLimit)) { + await scanDeep(join(path, dirent.name), results, level + 1, options); + } + } + + return results; +} diff --git a/src/nextra/symlinkAtomic.ts b/src/nextra/symlinkAtomic.ts index 1212e7d6..a708561f 100644 --- a/src/nextra/symlinkAtomic.ts +++ b/src/nextra/symlinkAtomic.ts @@ -1,8 +1,8 @@ +import { promises as fsp } from 'fs'; + import { tempFile } from '../utils/util'; -import { symlink } from '../fs'; import { SymLinkType } from './createSymlink'; - -import move from './move'; +import { move } from './move'; /** * Creates a soft file link atomically. @@ -12,8 +12,8 @@ import move from './move'; * @param destination The destination path of the file * @param type The type of symlink you are creating */ -export default async function symlinkAtomic(source: string, destination: string, type?: SymLinkType): Promise { +export async function symlinkAtomic(source: string, destination: string, type?: SymLinkType): Promise { const tempPath = tempFile(); - await symlink(source, tempPath, type); + await fsp.symlink(source, tempPath, type); await move(tempPath, destination, { overwrite: false }); } diff --git a/src/nextra/targz.ts b/src/nextra/targz.ts index fa370f07..c0116718 100644 --- a/src/nextra/targz.ts +++ b/src/nextra/targz.ts @@ -1,11 +1,11 @@ import { createGzip } from 'zlib'; +import { createWriteStream, promises as fsp } from 'fs'; +import { dirname } from 'path'; -import { createWriteStream } from '../fs'; -import Tar from '../utils/Tar'; +import { Tar } from '../utils/Tar'; import { pipelinePromise } from '../utils/util'; -import { dirname } from 'path'; -import scan from './scan'; -import targzAtomic from './targzAtomic'; +import { scan } from './scan'; +import { targzAtomic } from './targzAtomic'; /** @@ -16,15 +16,20 @@ import targzAtomic from './targzAtomic'; * @param inputFiles The directory or array of filepaths to .tar.gz * @param options The options for this .tar.gz */ -export default async function targz(fileName: string, inputFiles: string | string[], atomic = false): Promise { +export async function targz(fileName: string, inputFiles: string | string[], atomic = false): Promise { if (atomic) return targzAtomic(fileName, inputFiles); if (!Array.isArray(inputFiles)) inputFiles = [inputFiles]; const tar = new Tar(dirname(inputFiles[0])); for (const input of inputFiles) { - const files = await scan(input, { filter: (stats): boolean => stats.isFile() }); - for (const [file, stats] of files) tar.append(file, stats); + const stats = await fsp.lstat(input); + if (stats.isDirectory()) { + const files = await scan(input, { filter: (dirent): boolean => dirent.isFile() }); + for (const file of files.keys()) tar.append(file, await fsp.lstat(file)); + } else { + tar.append(input, stats); + } } return pipelinePromise( diff --git a/src/nextra/targzAtomic.ts b/src/nextra/targzAtomic.ts index 4af834b4..1e0b0563 100644 --- a/src/nextra/targzAtomic.ts +++ b/src/nextra/targzAtomic.ts @@ -1,5 +1,5 @@ -import targz from './targz'; -import move from './move'; +import { targz } from './targz'; +import { move } from './move'; import { tempFile } from '../utils/util'; /** @@ -9,7 +9,7 @@ import { tempFile } from '../utils/util'; * @param fileName The filename of the archive * @param inputFiles The directory or array of filepaths to .tar.gz */ -export default async function targzAtomic(fileName: string, inputFiles: string | string[]): Promise { +export async function targzAtomic(fileName: string, inputFiles: string | string[]): Promise { const tempPath = tempFile(); await targz(tempPath, inputFiles); return move(tempPath, fileName, { overwrite: true }); diff --git a/src/nextra/unTargz.ts b/src/nextra/unTargz.ts index 7323792b..efbea326 100644 --- a/src/nextra/unTargz.ts +++ b/src/nextra/unTargz.ts @@ -1,10 +1,10 @@ import { createGunzip } from 'zlib'; import { resolve } from 'path'; +import { createReadStream } from 'fs'; -import { createReadStream } from '../fs'; -import Untar from '../utils/Untar'; -import outputFile from './outputFile'; -import outputFileAtomic from './outputFileAtomic'; +import { Untar } from '../utils/Untar'; +import { outputFile } from './outputFile'; +import { outputFileAtomic } from './outputFileAtomic'; /** @@ -15,7 +15,7 @@ import outputFileAtomic from './outputFileAtomic'; * @param inputFile The archive file * @param atomic The if the writes should be atomic */ -export default async function unTargz(outputDirectory: string, inputFile: string, atomic = false): Promise { +export async function unTargz(outputDirectory: string, inputFile: string, atomic = false): Promise { const tar = createReadStream(inputFile).pipe(createGunzip()).pipe(new Untar()); const writeMethod = atomic ? outputFile : outputFileAtomic; diff --git a/src/nextra/unTargzAtomic.ts b/src/nextra/unTargzAtomic.ts index 4404a570..f6451b1f 100644 --- a/src/nextra/unTargzAtomic.ts +++ b/src/nextra/unTargzAtomic.ts @@ -1,5 +1,4 @@ -import unTargz from './unTargz'; - +import { unTargz } from './unTargz'; /** * Extracts files from .tar.gz archives and writes them atomically. @@ -9,6 +8,6 @@ import unTargz from './unTargz'; * @param inputFile The archive file * @param atomic The if the writes should be atomic */ -export default async function unTargzAtomic(outputDirectory: string, inputFile: string): Promise { +export async function unTargzAtomic(outputDirectory: string, inputFile: string): Promise { return unTargz(outputDirectory, inputFile, true); } diff --git a/src/nextra/writeFileAtomic.ts b/src/nextra/writeFileAtomic.ts index e304afa9..004ca9f6 100644 --- a/src/nextra/writeFileAtomic.ts +++ b/src/nextra/writeFileAtomic.ts @@ -1,7 +1,7 @@ -import { tempFile } from '../utils/util'; -import { writeFile } from '../fs'; +import { promises as fsp } from 'fs'; -import move from './move'; +import { tempFile } from '../utils/util'; +import { move } from './move'; /** * @typedef {Object} WriteOptions @@ -23,8 +23,8 @@ export interface WriteOptions { * @param data The data to write to file * @param options The write options or the encoding string. */ -export default async function writeFileAtomic(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string): Promise { +export async function writeFileAtomic(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | string): Promise { const tempPath = tempFile(); - await writeFile(tempPath, data, options); + await fsp.writeFile(tempPath, data, options); await move(tempPath, file, { overwrite: true }); } diff --git a/src/nextra/writeJSON.ts b/src/nextra/writeJSON.ts index 185fb883..84b39fd6 100644 --- a/src/nextra/writeJSON.ts +++ b/src/nextra/writeJSON.ts @@ -1,6 +1,6 @@ -import { writeFile } from '../fs'; +import { promises as fsp } from 'fs'; -import writeFileAtomic from './writeFileAtomic'; +import { writeFileAtomic } from './writeFileAtomic'; /** * @typedef {Object} JsonOptions @@ -39,11 +39,13 @@ export interface JsonOptions { * @param {boolean} [atomic = false] Whether the operation should run atomically * @returns {Promise} */ -export default async function writeJSON(file: string, object: any, atomic?: boolean): Promise; -export default async function writeJSON(file: string, object: any, options?: JsonOptions, atomic?: boolean): Promise; -export default async function writeJSON(file: string, object: any, options: JsonOptions | boolean = {}, atomic = false): Promise { +export async function writeJSON(file: string, object: any, atomic?: boolean): Promise; +export async function writeJSON(file: string, object: any, options?: JsonOptions, atomic?: boolean): Promise; +export async function writeJSON(file: string, object: any, options: JsonOptions | boolean = {}, atomic = false): Promise { if (typeof options === 'boolean') [atomic, options] = [options, {}]; - const writeMethod = atomic ? writeFileAtomic : writeFile; + const writeMethod = atomic ? writeFileAtomic : fsp.writeFile; await writeMethod(file, `${JSON.stringify(object, options.replacer, options.spaces)}\n`, options); } + +export const writeJson = writeJSON; diff --git a/src/nextra/writeJSONAtomic.ts b/src/nextra/writeJSONAtomic.ts index f10806bb..e4eacb8f 100644 --- a/src/nextra/writeJSONAtomic.ts +++ b/src/nextra/writeJSONAtomic.ts @@ -1,4 +1,4 @@ -import { default as writeJSON, JsonOptions } from './writeJSON'; +import { writeJSON, JsonOptions } from './writeJSON'; /** * Writes a Javascript Object to file as JSON atomically. @@ -16,6 +16,8 @@ import { default as writeJSON, JsonOptions } from './writeJSON'; * @param object The javascript object you would like to write to file * @param options The options to pass JSON.stringify and writeFile */ -export default async function writeJSONAtomic(file: string, object: any, options: JsonOptions = {}): Promise { +export async function writeJSONAtomic(file: string, object: any, options: JsonOptions = {}): Promise { return writeJSON(file, object, options, true); } + +export const writeJsonAtomic = writeJSONAtomic; diff --git a/src/utils/Header.ts b/src/utils/Header.ts index f05af9f2..49a694d4 100644 --- a/src/utils/Header.ts +++ b/src/utils/Header.ts @@ -17,7 +17,7 @@ export interface HeaderFormat { padding?: any; } -export default class Header { +export class Header { public filename: string; public mode: number; diff --git a/src/utils/Tar.ts b/src/utils/Tar.ts index c64651f4..eef6fa9b 100644 --- a/src/utils/Tar.ts +++ b/src/utils/Tar.ts @@ -1,10 +1,10 @@ -import Header from './Header'; - +import { createReadStream, Stats } from 'fs'; import { relative } from 'path'; import { Readable } from 'stream'; -import { createReadStream, Stats } from '../fs'; -export default class Tar extends Readable { +import { Header } from './Header'; + +export class Tar extends Readable { private base: string; private written = 0; diff --git a/src/utils/Untar.ts b/src/utils/Untar.ts index 130bfed5..8968d3c6 100644 --- a/src/utils/Untar.ts +++ b/src/utils/Untar.ts @@ -1,12 +1,12 @@ -import Header from './Header'; - import { Writable } from 'stream'; +import { Header } from './Header'; + function breakSync(next: Function): void { setImmediate((): void => next()); } -export default class Untar extends Writable { +export class Untar extends Writable { private header: Header | null = null; private file: Buffer = Buffer.alloc(0); diff --git a/src/utils/util.ts b/src/utils/util.ts index 35d4ad72..f3845f67 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -1,4 +1,4 @@ -import { sep, resolve, join } from 'path'; +import { sep, resolve, join, normalize } from 'path'; import { promisify } from 'util'; import { randomBytes } from 'crypto'; import { tmpdir } from 'os'; @@ -6,6 +6,11 @@ import { pipeline } from 'stream'; export const isWindows: boolean = process.platform === 'win32'; +export const invalidWin32Path = (myPath: string): boolean => { + const root = normalize(resolve(myPath)).split(sep); + return /[<>:"|?*]/.test(myPath.replace(root[0], '')); +}; + export const setTimeoutPromise: typeof setTimeout.__promisify__ = promisify(setTimeout); export const pipelinePromise: typeof pipeline.__promisify__ = promisify(pipeline); @@ -24,4 +29,3 @@ export const uuid = (): string => { }; export const tempFile = (ext?: string): string => join(tmpdir(), uuid() + (ext || '')); - diff --git a/test/gunzip.ts b/test/gunzip.ts index e361d4b0..0275730b 100644 --- a/test/gunzip.ts +++ b/test/gunzip.ts @@ -7,7 +7,7 @@ ava('File', async (test): Promise => { test.plan(3); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.gz`; await nextra.gzip(fileName, file); const output = tempFileLoc(); @@ -16,14 +16,14 @@ ava('File', async (test): Promise => { test.is(retVal, undefined); test.true(stats.isFile()); - test.is(await nextra.readFile(output, 'utf8'), 'test'); + test.is(await fs.readFile(output, 'utf8'), 'test'); }); ava('File (Atomic Shortcut)', async (test): Promise => { test.plan(3); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.gz`; await nextra.gzip(fileName, file); const output = tempFileLoc(); @@ -32,5 +32,5 @@ ava('File (Atomic Shortcut)', async (test): Promise => { test.is(retVal, undefined); test.true(stats.isFile()); - test.is(await nextra.readFile(output, 'utf8'), 'test'); + test.is(await fs.readFile(output, 'utf8'), 'test'); }); diff --git a/test/gunzipAtomic.ts b/test/gunzipAtomic.ts index 4e864567..45b31c91 100644 --- a/test/gunzipAtomic.ts +++ b/test/gunzipAtomic.ts @@ -7,7 +7,7 @@ ava('File', async (test): Promise => { test.plan(3); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.gz`; await nextra.gzip(fileName, file); const output = tempFileLoc(); @@ -16,5 +16,5 @@ ava('File', async (test): Promise => { test.is(retVal, undefined); test.true(stats.isFile()); - test.is(await nextra.readFile(output, 'utf8'), 'test'); + test.is(await fs.readFile(output, 'utf8'), 'test'); }); diff --git a/test/gzip.ts b/test/gzip.ts index 70527b3d..951218c2 100644 --- a/test/gzip.ts +++ b/test/gzip.ts @@ -7,7 +7,7 @@ ava('File', async (test): Promise => { test.plan(2); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.gz`; const retVal = await nextra.gzip(fileName, file); const stats = await fs.stat(fileName); @@ -20,7 +20,7 @@ ava('File (Atomic Shortcut)', async (test): Promise => { test.plan(2); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.gz`; const retVal = await nextra.gzip(fileName, file, true); const stats = await fs.stat(fileName); diff --git a/test/gzipAtomic.ts b/test/gzipAtomic.ts index a74243ca..b42e61d0 100644 --- a/test/gzipAtomic.ts +++ b/test/gzipAtomic.ts @@ -7,7 +7,7 @@ ava('File', async (test): Promise => { test.plan(2); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.gzipAtomic(fileName, file); const stats = await fs.stat(fileName); diff --git a/test/scan.ts b/test/scan.ts index 34f0674f..d80804b5 100644 --- a/test/scan.ts +++ b/test/scan.ts @@ -2,27 +2,11 @@ import ava from 'ava'; import { tempFile, tempFileLoc, tempDir, tempDirLoc } from './lib'; import * as nextra from '../dist'; -ava('File', async (test): Promise => { - test.plan(2); - - const file = tempFile(); - const map = await nextra.scan(file); - const stats = map.get(file); - - test.is(map.size, 1); - test.true(stats && stats.isFile()); -}); - - ava('Empty Directory', async (test): Promise => { - test.plan(2); - const dir = tempDir(); const map = await nextra.scan(dir); - const stats = map.get(dir); - test.is(map.size, 1); - test.true(stats && stats.isDirectory()); + test.is(map.size, 0); }); ava('Full Directory', async (test): Promise => { @@ -30,7 +14,7 @@ ava('Full Directory', async (test): Promise => { const dir = tempDir(); const file = tempFile(dir); - const map = await nextra.scan(dir, { filter: (stats): boolean => stats.isFile() }); + const map = await nextra.scan(dir, { filter: (dirent): boolean => dirent.isFile() }); test.is(map.size, 1); test.true(map.has(file)); @@ -41,7 +25,7 @@ ava('Deep Directory', async (test): Promise => { const dir = tempDir(); const file = tempFile(tempDir(dir)); - const map = await nextra.scan(dir, { filter: (stats): boolean => stats.isFile() }); + const map = await nextra.scan(dir, { filter: (dirent): boolean => dirent.isFile() }); test.is(map.size, 1); test.true(map.has(file)); @@ -53,7 +37,7 @@ ava('Multi Deep Directory', async (test): Promise => { const dir = tempDir(); const file1 = tempFile(tempDir(dir)); const file2 = tempFile(tempDir(dir)); - const map = await nextra.scan(dir, { filter: (stats): boolean => stats.isFile() }); + const map = await nextra.scan(dir, { filter: (dirent): boolean => dirent.isFile() }); test.is(map.size, 2); test.true(map.has(file1)); @@ -65,7 +49,7 @@ ava('Deep Directory w/ Limit', async (test): Promise => { const dir = tempDir(); const file = tempFile(tempDir(dir)); - const map = await nextra.scan(dir, { filter: (stats): boolean => stats.isFile(), depthLimit: 0 }); + const map = await nextra.scan(dir, { filter: (dirent): boolean => dirent.isFile(), depthLimit: 0 }); test.is(map.size, 0); test.false(map.has(file)); @@ -78,7 +62,7 @@ ava('Multi Deep Directory w/ Limit', async (test): Promise => { const file1 = tempFile(tempDir(dir)); const file2 = tempFile(tempDir(dir)); const file3 = tempFile(tempDir(tempDir(dir))); - const map = await nextra.scan(dir, { filter: (stats): boolean => stats.isFile(), depthLimit: 2 }); + const map = await nextra.scan(dir, { filter: (dirent): boolean => dirent.isFile(), depthLimit: 1 }); test.is(map.size, 2); test.true(map.has(file1)); @@ -86,6 +70,10 @@ ava('Multi Deep Directory w/ Limit', async (test): Promise => { test.false(map.has(file3)); }); +ava('File', async (test): Promise => { + await test.throwsAsync(nextra.scan(tempFile())); +}); + ava('Non-Existent File', async (test): Promise => { await test.throwsAsync(nextra.scan(tempFileLoc())); }); diff --git a/test/targz.ts b/test/targz.ts index 6b1ffdc8..5893e0d4 100644 --- a/test/targz.ts +++ b/test/targz.ts @@ -7,7 +7,7 @@ ava('File', async (test): Promise => { test.plan(2); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targz(fileName, file); const stats = await fs.stat(fileName); @@ -20,9 +20,9 @@ ava('Files', async (test): Promise => { test.plan(2); const file1 = tempFileLoc(); - await nextra.writeFile(file1, 'test1', 'utf8'); + await fs.writeFile(file1, 'test1', 'utf8'); const file2 = tempFileLoc(); - await nextra.writeFile(file2, 'test2', 'utf8'); + await fs.writeFile(file2, 'test2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targz(fileName, [file1, file2]); const stats = await fs.stat(fileName); @@ -35,8 +35,8 @@ ava('Directory', async (test): Promise => { test.plan(2); const dir = tempDir(); - await nextra.writeFile(tempFileLoc(dir), 'file1', 'utf8'); - await nextra.writeFile(tempFileLoc(dir), 'file2', 'utf8'); + await fs.writeFile(tempFileLoc(dir), 'file1', 'utf8'); + await fs.writeFile(tempFileLoc(dir), 'file2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targz(fileName, dir); const stats = await fs.stat(fileName); @@ -49,7 +49,7 @@ ava('File (Atomic Shortcut)', async (test): Promise => { test.plan(2); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targz(fileName, file, true); const stats = await fs.stat(fileName); @@ -62,9 +62,9 @@ ava('Files (Atomic Shortcut)', async (test): Promise => { test.plan(2); const file1 = tempFileLoc(); - await nextra.writeFile(file1, 'test1', 'utf8'); + await fs.writeFile(file1, 'test1', 'utf8'); const file2 = tempFileLoc(); - await nextra.writeFile(file2, 'test2', 'utf8'); + await fs.writeFile(file2, 'test2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targz(fileName, [file1, file2], true); const stats = await fs.stat(fileName); @@ -77,8 +77,8 @@ ava('Directory (Atomic Shortcut)', async (test): Promise => { test.plan(2); const dir = tempDir(); - await nextra.writeFile(tempFileLoc(dir), 'file1', 'utf8'); - await nextra.writeFile(tempFileLoc(dir), 'file2', 'utf8'); + await fs.writeFile(tempFileLoc(dir), 'file1', 'utf8'); + await fs.writeFile(tempFileLoc(dir), 'file2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targz(fileName, dir, true); const stats = await fs.stat(fileName); diff --git a/test/targzAtomic.ts b/test/targzAtomic.ts index 50ea0763..099ab491 100644 --- a/test/targzAtomic.ts +++ b/test/targzAtomic.ts @@ -7,7 +7,7 @@ ava('File', async (test): Promise => { test.plan(2); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targzAtomic(fileName, file); const stats = await fs.stat(fileName); @@ -20,9 +20,9 @@ ava('Files', async (test): Promise => { test.plan(2); const file1 = tempFileLoc(); - await nextra.writeFile(file1, 'test1', 'utf8'); + await fs.writeFile(file1, 'test1', 'utf8'); const file2 = tempFileLoc(); - await nextra.writeFile(file2, 'test2', 'utf8'); + await fs.writeFile(file2, 'test2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targzAtomic(fileName, [file1, file2]); const stats = await fs.stat(fileName); @@ -35,8 +35,8 @@ ava('Directory', async (test): Promise => { test.plan(2); const dir = tempDir(); - await nextra.writeFile(tempFileLoc(dir), 'file1', 'utf8'); - await nextra.writeFile(tempFileLoc(dir), 'file2', 'utf8'); + await fs.writeFile(tempFileLoc(dir), 'file1', 'utf8'); + await fs.writeFile(tempFileLoc(dir), 'file2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; const retVal = await nextra.targzAtomic(fileName, dir); const stats = await fs.stat(fileName); diff --git a/test/unTargz.ts b/test/unTargz.ts index 92d37283..5dc96bf5 100644 --- a/test/unTargz.ts +++ b/test/unTargz.ts @@ -8,7 +8,7 @@ ava('File', async (test): Promise => { test.plan(3); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, file); const outputDirectory = tempDir(); @@ -27,7 +27,7 @@ ava('Big File', async (test): Promise => { const content = `${'big'.repeat(1000000)}file!`; const file = tempFileLoc(); - await nextra.writeFile(file, content, 'utf8'); + await fs.writeFile(file, content, 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, file); const outputDirectory = tempDir(); @@ -44,9 +44,9 @@ ava('Files', async (test): Promise => { test.plan(5); const file1 = tempFileLoc(); - await nextra.writeFile(file1, 'test1', 'utf8'); + await fs.writeFile(file1, 'test1', 'utf8'); const file2 = tempFileLoc(); - await nextra.writeFile(file2, 'test2', 'utf8'); + await fs.writeFile(file2, 'test2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, [file1, file2]); const outputDirectory = tempDir(); @@ -68,8 +68,8 @@ ava('Directory', async (test): Promise => { const directory = tempDir(); const file1 = tempFileLoc(directory); const file2 = tempFileLoc(directory); - await nextra.writeFile(file1, 'file1', 'utf8'); - await nextra.writeFile(file2, 'file2', 'utf8'); + await fs.writeFile(file1, 'file1', 'utf8'); + await fs.writeFile(file2, 'file2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, directory); const outputDirectory = tempDir(); @@ -89,7 +89,7 @@ ava('File (Atomic Shortcut)', async (test): Promise => { test.plan(3); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, file); const outputDirectory = tempDir(); @@ -106,9 +106,9 @@ ava('Files (Atomic Shortcut)', async (test): Promise => { test.plan(5); const file1 = tempFileLoc(); - await nextra.writeFile(file1, 'test1', 'utf8'); + await fs.writeFile(file1, 'test1', 'utf8'); const file2 = tempFileLoc(); - await nextra.writeFile(file2, 'test2', 'utf8'); + await fs.writeFile(file2, 'test2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, [file1, file2]); const outputDirectory = tempDir(); @@ -130,8 +130,8 @@ ava('Directory (Atomic Shortcut)', async (test): Promise => { const directory = tempDir(); const file1 = tempFileLoc(directory); const file2 = tempFileLoc(directory); - await nextra.writeFile(file1, 'file1', 'utf8'); - await nextra.writeFile(file2, 'file2', 'utf8'); + await fs.writeFile(file1, 'file1', 'utf8'); + await fs.writeFile(file2, 'file2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, directory); const outputDirectory = tempDir(); diff --git a/test/unTargzAtomic.ts b/test/unTargzAtomic.ts index 9fd916d5..e53c26e5 100644 --- a/test/unTargzAtomic.ts +++ b/test/unTargzAtomic.ts @@ -8,7 +8,7 @@ ava('File', async (test): Promise => { test.plan(3); const file = tempFileLoc(); - await nextra.writeFile(file, 'test', 'utf8'); + await fs.writeFile(file, 'test', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, file); const outputDirectory = tempDir(); @@ -25,9 +25,9 @@ ava('Files', async (test): Promise => { test.plan(5); const file1 = tempFileLoc(); - await nextra.writeFile(file1, 'test1', 'utf8'); + await fs.writeFile(file1, 'test1', 'utf8'); const file2 = tempFileLoc(); - await nextra.writeFile(file2, 'test2', 'utf8'); + await fs.writeFile(file2, 'test2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, [file1, file2]); const outputDirectory = tempDir(); @@ -49,8 +49,8 @@ ava('Directory', async (test): Promise => { const directory = tempDir(); const file1 = tempFileLoc(directory); const file2 = tempFileLoc(directory); - await nextra.writeFile(file1, 'file1', 'utf8'); - await nextra.writeFile(file2, 'file2', 'utf8'); + await fs.writeFile(file1, 'file1', 'utf8'); + await fs.writeFile(file2, 'file2', 'utf8'); const fileName = `${tempFileLoc()}.tar.gz`; await nextra.targz(fileName, directory); const outputDirectory = tempDir();