diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml index 15c63fc1..e359de18 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 12 + - name: Use Node.js 14 uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: ${{ runner.os }}-12-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-14-${{ 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 12 + - name: Use Node.js 14 uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: ${{ runner.os }}-12-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-14-${{ 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 12 + - name: Use Node.js 14 uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: ${{ runner.os }}-12-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-14-${{ hashFiles('**/yarn.lock') }} - name: Install Dependencies run: yarn - name: Test Docs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 14a9014b..5179a013 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node_version: [12, 14] + node_version: [14] os: [ubuntu-latest, windows-latest, macOS-latest] steps: @@ -47,42 +47,27 @@ jobs: steps: - name: Checkout Project uses: actions/checkout@v1 - - name: Use Node.js 12 + - name: Use Node.js 14 uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - name: Restore CI Cache uses: actions/cache@v1 with: path: node_modules - key: Windows-12-${{ hashFiles('**\yarn.lock') }} + key: Windows-14-${{ hashFiles('**\yarn.lock') }} - name: Install Dependencies run: yarn - - uses: actions/download-artifact@v1 - name: Download Windows-12 Coverage Data - with: - name: Windows-12 - path: .nyc_output - uses: actions/download-artifact@v1 name: Download Windows-14 Coverage Data with: name: Windows-14 path: .nyc_output - - uses: actions/download-artifact@v1 - name: Download macOS-12 Coverage Data - with: - name: macOS-12 - path: .nyc_output - uses: actions/download-artifact@v1 name: Download macOS-14 Coverage Data with: name: macOS-14 path: .nyc_output - - uses: actions/download-artifact@v1 - name: Download Linux-12 Coverage Data - with: - name: Linux-12 - path: .nyc_output - uses: actions/download-artifact@v1 name: Download Linux-14 Coverage Data with: diff --git a/package.json b/package.json index af98ef43..3e39c83f 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "author": "BDISTIN", "license": "MIT", "engines": { - "node": ">=12.12.0" + "node": ">=14.0.0" }, "devDependencies": { "@ava/typescript": "^1.1.1", diff --git a/src/nextra/copy.ts b/src/nextra/copy.ts index 82e9dcb7..2aeb500c 100644 --- a/src/nextra/copy.ts +++ b/src/nextra/copy.ts @@ -1,5 +1,7 @@ import { resolve, dirname, join, basename } from 'path'; -import { promises as fsp, Stats } from 'fs'; +import { access, mkdir, lstat, chmod, readdir, stat, symlink, readlink, copyFile } from 'fs/promises'; + +import type { Stats } from 'fs'; import { replaceEsc, isSrcKid } from '../utils/util'; import { mkdirs } from './mkdirs'; @@ -44,7 +46,7 @@ export async function copy(source: string, destination: string, options: CopyOpt if (resolve(source) === resolve(destination)) { if (copyOptions.errorOnExist) throw new Error('FS-NEXTRA: Source and destination must not be the same.'); - await fsp.access(source); + await access(source); } else { await mkdirs(dirname(destination)); await startCopy(source, copyOptions); @@ -66,7 +68,7 @@ function resolveCopyOptions(source: string, destination: string, options: CopyOp async function isWritable(myPath: string): Promise { try { - await fsp.lstat(myPath); + await lstat(myPath); return false; } catch (err) { return err.code === 'ENOENT'; @@ -75,7 +77,7 @@ async function isWritable(myPath: string): Promise { async function startCopy(mySource: string, options: CopyData): Promise { if (!options.filter(mySource, options.targetPath)) return; - const stats = await fsp.lstat(mySource); + const stats = await lstat(mySource); const target = mySource.replace(options.currentPath, replaceEsc(options.targetPath)); if (stats.isDirectory()) await copyDirectory(mySource, stats, target, options); @@ -85,16 +87,16 @@ async function startCopy(mySource: 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 fsp.mkdir(target, stats.mode); - await fsp.chmod(target, stats.mode); + await mkdir(target, stats.mode); + await chmod(target, stats.mode); } - const items = await fsp.readdir(mySource); + const items = await readdir(mySource); await Promise.all(items.map((item): Promise => startCopy(join(mySource, item), options))); } async function copyOther(mySource: string, stats: Stats, target: string, options: CopyData): Promise { try { - const tstats = await fsp.stat(target); + const tstats = await stat(target); if (tstats && tstats.isDirectory()) target = join(target, basename(mySource)); } catch (err) { // noop @@ -106,6 +108,6 @@ async function copyOther(mySource: string, stats: Stats, target: string, options await remove(target); } - if (stats.isSymbolicLink()) await fsp.symlink(await fsp.readlink(mySource), target); - else await fsp.copyFile(mySource, target); + if (stats.isSymbolicLink()) await symlink(await readlink(mySource), target); + else await copyFile(mySource, target); } diff --git a/src/nextra/copyFileAtomic.ts b/src/nextra/copyFileAtomic.ts index 601edafe..88aed899 100644 --- a/src/nextra/copyFileAtomic.ts +++ b/src/nextra/copyFileAtomic.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { copyFile } from 'fs/promises'; import { tempFile } from '../utils/util'; import { move } from './move'; @@ -12,6 +12,6 @@ import { move } from './move'; */ export async function copyFileAtomic(source: string, destination: string): Promise { const tempPath = tempFile(); - await fsp.copyFile(source, tempPath); + await copyFile(source, tempPath); await move(tempPath, destination, { overwrite: true }); } diff --git a/src/nextra/createFile.ts b/src/nextra/createFile.ts index 1b1bbe01..9d63c229 100644 --- a/src/nextra/createFile.ts +++ b/src/nextra/createFile.ts @@ -1,5 +1,5 @@ import { dirname } from 'path'; -import { promises as fsp } from 'fs'; +import { writeFile } from 'fs/promises'; import { writeFileAtomic } from './writeFileAtomic'; import { mkdirs } from './mkdirs'; @@ -24,7 +24,7 @@ export async function createFile(file: string, atomic = false): Promise { await mkdirs(dirname(file)); - const writeMethod = atomic ? writeFileAtomic : fsp.writeFile; + const writeMethod = atomic ? writeFileAtomic : writeFile; await writeMethod(file, ''); } diff --git a/src/nextra/createFileCopy.ts b/src/nextra/createFileCopy.ts index b0f8e4d2..576ede30 100644 --- a/src/nextra/createFileCopy.ts +++ b/src/nextra/createFileCopy.ts @@ -1,6 +1,5 @@ import { dirname, resolve } from 'path'; - -import { promises as fsp } from 'fs'; +import { access, copyFile } from 'fs/promises'; import { copyFileAtomic } from './copyFileAtomic'; import { mkdirs } from './mkdirs'; @@ -23,11 +22,11 @@ import { mkdirs } from './mkdirs'; */ export async function createFileCopy(source: string, destination: string, atomic = false): Promise { if (resolve(source) === resolve(destination)) { - await fsp.access(source); + await access(source); } else { await mkdirs(dirname(destination)); - const copyMethod = atomic ? copyFileAtomic : fsp.copyFile; + const copyMethod = atomic ? copyFileAtomic : copyFile; await copyMethod(source, destination); } } diff --git a/src/nextra/createLink.ts b/src/nextra/createLink.ts index eca03fc8..efb838bf 100644 --- a/src/nextra/createLink.ts +++ b/src/nextra/createLink.ts @@ -1,6 +1,5 @@ import { dirname } from 'path'; - -import { promises as fsp } from 'fs'; +import { lstat, link } from 'fs/promises'; import { linkAtomic } from './linkAtomic'; import { mkdirs } from './mkdirs'; @@ -24,11 +23,11 @@ import { pathExists } from './pathExists'; */ export async function createLink(source: string, destination: string, atomic = false): Promise { if (await pathExists(destination)) return; - await fsp.lstat(source); + await lstat(source); await mkdirs(dirname(destination)); - const linkMethod = atomic ? linkAtomic : fsp.link; + const linkMethod = atomic ? linkAtomic : link; await linkMethod(source, destination); } diff --git a/src/nextra/createSymlink.ts b/src/nextra/createSymlink.ts index 32413238..eb5156bb 100644 --- a/src/nextra/createSymlink.ts +++ b/src/nextra/createSymlink.ts @@ -1,5 +1,5 @@ import { dirname, join, isAbsolute, relative, resolve } from 'path'; -import { promises as fsp } from 'fs'; +import { symlink, lstat } from 'fs/promises'; import { pathExists } from './pathExists'; import { mkdirs } from './mkdirs'; @@ -48,25 +48,25 @@ export async function createSymlink(source: string, destination: string, type?: await mkdirs(dirname(destination)); const relativePath = await symlinkPaths(source, destination); - const symlinkMethod = atomic ? symlinkAtomic : fsp.symlink; + const symlinkMethod = atomic ? symlinkAtomic : symlink; await symlinkMethod(relativePath.toDst, resolve(destination), type as SymLinkType || await symlinkType(relativePath.toCwd)); } async function symlinkPaths(srcpath: string, dstPath: string): Promise { if (isAbsolute(srcpath)) { - await fsp.lstat(srcpath); + await 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 fsp.lstat(srcpath); + await lstat(srcpath); return { toCwd: srcpath, toDst: relative(dstDir, srcpath) }; } async function symlinkType(srcpath: string): Promise { - const stats = await fsp.lstat(srcpath); + const stats = await lstat(srcpath); return stats.isDirectory() ? 'dir' : 'file'; } diff --git a/src/nextra/emptyDir.ts b/src/nextra/emptyDir.ts index 8ed0199e..0cdba8e4 100644 --- a/src/nextra/emptyDir.ts +++ b/src/nextra/emptyDir.ts @@ -1,5 +1,5 @@ import { join } from 'path'; -import { promises as fsp } from 'fs'; +import { readdir } from 'fs/promises'; import { mkdirs } from './mkdirs'; import { remove } from './remove'; @@ -18,7 +18,7 @@ import { remove } from './remove'; */ export async function emptyDir(dir: string): Promise { try { - const items = await fsp.readdir(dir); + const items = await readdir(dir); await Promise.all(items.map((item): Promise => remove(join(dir, item)))); } catch (err) { await mkdirs(dir); diff --git a/src/nextra/linkAtomic.ts b/src/nextra/linkAtomic.ts index b66b582c..b322a512 100644 --- a/src/nextra/linkAtomic.ts +++ b/src/nextra/linkAtomic.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { link } from 'fs/promises'; import { tempFile } from '../utils/util'; import { move } from './move'; @@ -12,6 +12,6 @@ import { move } from './move'; */ export async function linkAtomic(source: string, destination: string): Promise { const tempPath = tempFile(); - await fsp.link(source, tempPath); + await link(source, tempPath); await move(tempPath, destination, { overwrite: true }); } diff --git a/src/nextra/mkdirs.ts b/src/nextra/mkdirs.ts index 83c0c5c2..ea45bcdd 100644 --- a/src/nextra/mkdirs.ts +++ b/src/nextra/mkdirs.ts @@ -1,5 +1,5 @@ import { resolve, dirname } from 'path'; -import { promises as fsp } from 'fs'; +import { mkdir, stat } from 'fs/promises'; import { isWindows, invalidWin32Path, umask } from '../utils/util'; @@ -47,14 +47,14 @@ export async function mkdirs(path: string, options?: MkdirsOptions | number): Pr path = resolve(path); try { - await fsp.mkdir(path, dirOptions.mode); + await mkdir(path, dirOptions.mode); } catch (err) { if (err.code === 'ENOENT') { await mkdirs(dirname(path), dirOptions); await mkdirs(path, dirOptions); return; } - const myStat = await fsp.stat(path); + const myStat = await stat(path); if (myStat.isDirectory()) return; throw err; } diff --git a/src/nextra/move.ts b/src/nextra/move.ts index 493aedbc..d59db2f4 100644 --- a/src/nextra/move.ts +++ b/src/nextra/move.ts @@ -1,5 +1,5 @@ import { resolve, dirname } from 'path'; -import { promises as fsp } from 'fs'; +import { access, lstat, rename } from 'fs/promises'; import { isSrcKid } from '../utils/util'; import { remove } from './remove'; @@ -25,9 +25,9 @@ export interface MoveOptions { */ export async function move(source: string, destination: string, options: MoveOptions = {}): Promise { const overwrite = options.overwrite || false; - if (resolve(source) === resolve(destination)) return fsp.access(source); + if (resolve(source) === resolve(destination)) return access(source); - const myStat = await fsp.lstat(source); + const myStat = await 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.'); } @@ -41,7 +41,7 @@ export async function move(source: string, destination: string, options: MoveOpt } try { - return await fsp.rename(source, destination); + return await 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 bc6f2492..77dfa29e 100644 --- a/src/nextra/outputFile.ts +++ b/src/nextra/outputFile.ts @@ -1,5 +1,5 @@ import { dirname } from 'path'; -import { promises as fsp } from 'fs'; +import { writeFile } from 'fs/promises'; import { writeFileAtomic, WriteOptions, BaseEncodingOptions } from './writeFileAtomic'; import { mkdirs } from './mkdirs'; @@ -20,6 +20,6 @@ export async function outputFile(file: string, data: string | Buffer | Uint8Arra await mkdirs(dirname(file)); - const writeMethod = atomic ? writeFileAtomic : fsp.writeFile; + const writeMethod = atomic ? writeFileAtomic : writeFile; await writeMethod(file, data, options); } diff --git a/src/nextra/pathExists.ts b/src/nextra/pathExists.ts index 632facc2..e6d3831f 100644 --- a/src/nextra/pathExists.ts +++ b/src/nextra/pathExists.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { access } from 'fs/promises'; /** * Checks if a path exists. @@ -8,7 +8,7 @@ import { promises as fsp } from 'fs'; */ export async function pathExists(path: string): Promise { try { - await fsp.access(path); + await access(path); return true; } catch (err) { return false; diff --git a/src/nextra/readJSON.ts b/src/nextra/readJSON.ts index 384f7637..1a291556 100644 --- a/src/nextra/readJSON.ts +++ b/src/nextra/readJSON.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { readFile } from 'fs/promises'; export type BufferEncoding = 'ascii' | 'utf8' | 'utf16le' | 'ucs2' | 'base64' | 'latin1' | 'binary' | 'hex'; @@ -32,7 +32,7 @@ export interface ReadJSONOptions { */ export async function readJSON(file: string, options: ReadJSONOptions | BufferEncoding = { flag: 'r' }): Promise { if (typeof options === 'string') options = { encoding: options, flag: 'r' }; - const content = await fsp.readFile(file, options); + const content = await readFile(file, options); return JSON.parse(stripBom(content), options.reviver); } diff --git a/src/nextra/remove.ts b/src/nextra/remove.ts index 0fa22cfc..f7fe22fa 100644 --- a/src/nextra/remove.ts +++ b/src/nextra/remove.ts @@ -1,5 +1,5 @@ import { join } from 'path'; -import { promises as fsp } from 'fs'; +import { lstat, unlink, chmod, rmdir, readdir } from 'fs/promises'; import { isWindows, setTimeoutPromise } from '../utils/util'; @@ -41,7 +41,7 @@ export async function remove(path: string, options: RemoveOptions = {}): Promise async function rimraf(myPath: string, options: RemoveOptions): Promise { try { - const stats = await fsp.lstat(myPath); + const stats = await lstat(myPath); if (stats.isDirectory()) return removeDir(myPath, options); } catch (err) { /* istanbul ignore next: Windows */ @@ -50,7 +50,7 @@ async function rimraf(myPath: string, options: RemoveOptions): Promise { } try { - return await fsp.unlink(myPath); + return await unlink(myPath); } catch (er) { /* istanbul ignore next: Windows */ if (er.code === 'EPERM') return isWindows ? fixWinEPERM(myPath, options) : removeDir(myPath, options, er); @@ -62,13 +62,13 @@ async function rimraf(myPath: string, options: RemoveOptions): Promise { /* istanbul ignore next: Windows */ async function fixWinEPERM(myPath: string, options: RemoveOptions): Promise { - await fsp.chmod(myPath, 0o666); + await chmod(myPath, 0o666); return rimraf(myPath, options); } async function removeDir(myPath: string, options: RemoveOptions, originalEr = null): Promise { try { - return await fsp.rmdir(myPath); + return await rmdir(myPath); } catch (err) { /* istanbul ignore else: Difficult to reproduce */ if (['ENOTEMPTY', 'EEXIST', 'EPERM'].includes(err.code)) return rmkids(myPath, options); @@ -78,7 +78,7 @@ async function removeDir(myPath: string, options: RemoveOptions, originalEr = nu } async function rmkids(myPath: string, options: RemoveOptions): Promise { - const files = await fsp.readdir(myPath); + const files = await readdir(myPath); await Promise.all(files.map((file): Promise => remove(join(myPath, file), options))); - return fsp.rmdir(myPath); + return rmdir(myPath); } diff --git a/src/nextra/scan.ts b/src/nextra/scan.ts index 64936101..2332f80b 100644 --- a/src/nextra/scan.ts +++ b/src/nextra/scan.ts @@ -1,5 +1,8 @@ import { resolve, join } from 'path'; -import { promises as fsp, Dirent } from 'fs'; +import { opendir } from 'fs/promises'; + +import type { Dirent } from 'fs'; + /** * @typedef {Object} ScanOptions @@ -24,7 +27,7 @@ export function scan(root: string, options: ScanOptions = {}): Promise, level: number, options: ScanOptions): Promise> { - const dir = await fsp.opendir(path); + const dir = await opendir(path); for await (const dirent of dir) { const fullPath = join(path, dirent.name); diff --git a/src/nextra/symlinkAtomic.ts b/src/nextra/symlinkAtomic.ts index 28e8cd6b..90860649 100644 --- a/src/nextra/symlinkAtomic.ts +++ b/src/nextra/symlinkAtomic.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { symlink } from 'fs/promises'; import { tempFile } from '../utils/util'; import { move } from './move'; @@ -15,6 +15,6 @@ import type { SymLinkType } from './createSymlink'; */ export async function symlinkAtomic(source: string, destination: string, type?: SymLinkType): Promise { const tempPath = tempFile(); - await fsp.symlink(source, tempPath, type); + await symlink(source, tempPath, type); await move(tempPath, destination, { overwrite: false }); } diff --git a/src/nextra/targz.ts b/src/nextra/targz.ts index c0116718..0ea7856f 100644 --- a/src/nextra/targz.ts +++ b/src/nextra/targz.ts @@ -1,5 +1,6 @@ import { createGzip } from 'zlib'; -import { createWriteStream, promises as fsp } from 'fs'; +import { createWriteStream } from 'fs'; +import { lstat } from 'fs/promises'; import { dirname } from 'path'; import { Tar } from '../utils/Tar'; @@ -23,10 +24,10 @@ export async function targz(fileName: string, inputFiles: string | string[], ato const tar = new Tar(dirname(inputFiles[0])); for (const input of inputFiles) { - const stats = await fsp.lstat(input); + const stats = await 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)); + for (const file of files.keys()) tar.append(file, await lstat(file)); } else { tar.append(input, stats); } diff --git a/src/nextra/writeFileAtomic.ts b/src/nextra/writeFileAtomic.ts index 14fc2307..ccbe5a5f 100644 --- a/src/nextra/writeFileAtomic.ts +++ b/src/nextra/writeFileAtomic.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { writeFile } from 'fs/promises'; import { tempFile } from '../utils/util'; import { move } from './move'; @@ -27,6 +27,6 @@ export interface WriteOptions { */ export async function writeFileAtomic(file: string, data: string | Buffer | Uint8Array, options?: WriteOptions | BaseEncodingOptions): Promise { const tempPath = tempFile(); - await fsp.writeFile(tempPath, data, options); + await writeFile(tempPath, data, options); await move(tempPath, file, { overwrite: true }); } diff --git a/src/nextra/writeJSON.ts b/src/nextra/writeJSON.ts index fa227a59..1d73520d 100644 --- a/src/nextra/writeJSON.ts +++ b/src/nextra/writeJSON.ts @@ -1,4 +1,4 @@ -import { promises as fsp } from 'fs'; +import { writeFile } from 'fs/promises'; import { writeFileAtomic, BaseEncodingOptions } from './writeFileAtomic'; @@ -44,7 +44,7 @@ export async function writeJSON(file: string, object: any, options?: JsonOptions 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 : fsp.writeFile; + const writeMethod = atomic ? writeFileAtomic : writeFile; await writeMethod(file, `${JSON.stringify(object, options.replacer, options.spaces)}\n`, options); }