diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 1a630e9..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,3 +0,0 @@ -github: sindresorhus -open_collective: sindresorhus -custom: https://sindresorhus.com/donate diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5f76c17..3222d5d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,15 +10,13 @@ jobs: fail-fast: false matrix: node-version: - - 14 - - 12 - - 10 + - 16 os: - ubuntu-latest - macos-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/index.d.ts b/index.d.ts index 3a94af9..43903d1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,50 +1,50 @@ -declare namespace moveFile { - interface Options { - /** - Overwrite existing destination file. +export interface Options { + /** + Overwrite existing destination file. - @default true - */ - readonly overwrite?: boolean; + @default true + */ + readonly overwrite?: boolean; - /** - [Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories. + /** + [Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories. - It has no effect on Windows. + It has no effect on Windows. - @default 0o777 - */ - readonly directoryMode?: number; - } + @default 0o777 + */ + readonly directoryMode?: number; } -declare const moveFile: { - /** - Move a file. +/** +Move a file asynchronously. - @param source - File you want to move. - @param destination - Where you want the file moved. - @returns A `Promise` that resolves when the file has been moved. +@param sourcePath - The file you want to move. +@param destinationPath - Where you want the file moved. +@returns A `Promise` that resolves when the file has been moved. - @example - ``` - import moveFile = require('move-file'); +@example +``` +import {moveFile} from 'move-file'; - (async () => { - await moveFile('source/unicorn.png', 'destination/unicorn.png'); - console.log('The file has been moved'); - })(); - ``` - */ - (source: string, destination: string, options?: moveFile.Options): Promise; +await moveFile('source/unicorn.png', 'destination/unicorn.png'); +console.log('The file has been moved'); +``` +*/ +export function moveFile(sourcePath: string, destinationPath: string, options?: Options): Promise; - /** - Move a file synchronously. +/** +Move a file synchronously. - @param source - File you want to move. - @param destination - Where you want the file moved. - */ - sync(source: string, destination: string, options?: moveFile.Options): void; -}; +@param sourcePath - The file you want to move. +@param destinationPath - Where you want the file moved. + +@example +``` +import {moveFileSync} from 'move-file'; -export = moveFile; +moveFileSync('source/unicorn.png', 'destination/unicorn.png'); +console.log('The file has been moved'); +``` +*/ +export function moveFileSync(sourcePath: string, destinationPath: string, options?: Options): void; diff --git a/index.js b/index.js index 6a3794c..b88cb88 100644 --- a/index.js +++ b/index.js @@ -1,68 +1,55 @@ -'use strict'; -const path = require('path'); -const fs = require('fs'); -const pathExists = require('path-exists'); +import path from 'node:path'; +import fs, {promises as fsP} from 'node:fs'; +import {pathExists} from 'path-exists'; -const fsP = fs.promises; - -module.exports = async (source, destination, options) => { - if (!source || !destination) { - throw new TypeError('`source` and `destination` file required'); +export async function moveFile(sourcePath, destinationPath, {overwrite = true, directoryMode} = {}) { + if (!sourcePath || !destinationPath) { + throw new TypeError('`sourcePath` and `destinationPath` required'); } - options = { - overwrite: true, - ...options - }; - - if (!options.overwrite && await pathExists(destination)) { - throw new Error(`The destination file exists: ${destination}`); + if (!overwrite && await pathExists(destinationPath)) { + throw new Error(`The destination file exists: ${destinationPath}`); } - await fsP.mkdir(path.dirname(destination), { + await fsP.mkdir(path.dirname(destinationPath), { recursive: true, - mode: options.directoryMode + mode: directoryMode, }); try { - await fsP.rename(source, destination); + await fsP.rename(sourcePath, destinationPath); } catch (error) { if (error.code === 'EXDEV') { - await fsP.copyFile(source, destination); - await fsP.unlink(source); + await fsP.copyFile(sourcePath, destinationPath); + await fsP.unlink(sourcePath); } else { throw error; } } -}; +} -module.exports.sync = (source, destination, options) => { - if (!source || !destination) { - throw new TypeError('`source` and `destination` file required'); +export function moveFileSync(sourcePath, destinationPath, {overwrite = true, directoryMode} = {}) { + if (!sourcePath || !destinationPath) { + throw new TypeError('`sourcePath` and `destinationPath` required'); } - options = { - overwrite: true, - ...options - }; - - if (!options.overwrite && fs.existsSync(destination)) { - throw new Error(`The destination file exists: ${destination}`); + if (!overwrite && fs.existsSync(destinationPath)) { + throw new Error(`The destination file exists: ${destinationPath}`); } - fs.mkdirSync(path.dirname(destination), { + fs.mkdirSync(path.dirname(destinationPath), { recursive: true, - mode: options.directoryMode + mode: directoryMode, }); try { - fs.renameSync(source, destination); + fs.renameSync(sourcePath, destinationPath); } catch (error) { if (error.code === 'EXDEV') { - fs.copyFileSync(source, destination); - fs.unlinkSync(source); + fs.copyFileSync(sourcePath, destinationPath); + fs.unlinkSync(sourcePath); } else { throw error; } } -}; +} diff --git a/index.test-d.ts b/index.test-d.ts index 4192ba3..c256e92 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,37 +1,37 @@ import {expectError, expectType} from 'tsd'; -import moveFile = require('.'); +import {moveFile, moveFileSync} from './index.js'; expectType>( - moveFile('source/unicorn.png', 'destination/unicorn.png') + moveFile('source/unicorn.png', 'destination/unicorn.png'), ); expectType>( - moveFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false}) + moveFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false}), ); expectType>( moveFile('source/unicorn.png', 'destination/unicorn.png', { - directoryMode: 0o700 - }) + directoryMode: 0o700, + }), ); expectError( await moveFile('source/unicorn.png', 'destination/unicorn.png', { - directoryMode: '700' - }) + directoryMode: '700', + }), ); expectType( - moveFile.sync('source/unicorn.png', 'destination/unicorn.png') + moveFileSync('source/unicorn.png', 'destination/unicorn.png'), ); expectType( - moveFile.sync('source/unicorn.png', 'destination/unicorn.png', { - overwrite: false - }) + moveFileSync('source/unicorn.png', 'destination/unicorn.png', { + overwrite: false, + }), ); expectType( - moveFile.sync('source/unicorn.png', 'destination/unicorn.png', { - directoryMode: 0o700 - }) + moveFileSync('source/unicorn.png', 'destination/unicorn.png', { + directoryMode: 0o700, + }), ); expectError( - moveFile.sync('source/unicorn.png', 'destination/unicorn.png', { - directoryMode: '700' - }) + moveFileSync('source/unicorn.png', 'destination/unicorn.png', { + directoryMode: '700', + }), ); diff --git a/package.json b/package.json index de07090..163083d 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=10.17" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "scripts": { "test": "xo && ava && tsd" @@ -37,14 +39,14 @@ "partitions" ], "dependencies": { - "path-exists": "^4.0.0" + "path-exists": "^5.0.0" }, "devDependencies": { - "ava": "^1.4.1", - "sinon": "^9.0.2", - "temp-write": "^4.0.0", - "tempy": "^0.5.0", - "tsd": "^0.11.0", - "xo": "^0.24.0" + "ava": "^3.15.0", + "sinon": "^11.1.2", + "temp-write": "^5.0.0", + "tempy": "^1.0.1", + "tsd": "^0.17.0", + "xo": "^0.44.0" } } diff --git a/readme.md b/readme.md index 7b91d5a..bda1126 100644 --- a/readme.md +++ b/readme.md @@ -20,29 +20,27 @@ $ npm install move-file ## Usage ```js -const moveFile = require('move-file'); +import {moveFile} from 'move-file'; -(async () => { - await moveFile('source/unicorn.png', 'destination/unicorn.png'); - console.log('The file has been moved'); -})(); +await moveFile('source/unicorn.png', 'destination/unicorn.png'); +console.log('The file has been moved'); ``` ## API -### moveFile(source, destination, options?) +### moveFile(sourcePath, destinationPath, options?) Returns a `Promise` that resolves when the file has been moved. -### moveFile.sync(source, destination, options?) +### moveFileSync(sourcePath, destinationPath, options?) -#### source +#### sourcePath Type: `string` -File you want to move. +The file you want to move. -#### destination +#### destinationPath Type: `string` diff --git a/test/async.js b/test/async.js index 69a1048..3ed9ab7 100644 --- a/test/async.js +++ b/test/async.js @@ -1,9 +1,9 @@ -import fs from 'fs'; +import fs from 'node:fs'; import test from 'ava'; import tempy from 'tempy'; import tempWrite from 'temp-write'; import sinon from 'sinon'; -import moveFile from '..'; +import {moveFile} from '../index.js'; const fixture = '🦄'; @@ -18,7 +18,7 @@ test('move a file', async t => { }); test.serial('move a file across devices', async t => { - const exdevError = new Error(); + const exdevError = new Error('exdevError'); exdevError.code = 'EXDEV'; fs.rename = sinon.stub(fs, 'rename').throws(exdevError); @@ -31,7 +31,9 @@ test.serial('move a file across devices', async t => { test('overwrite option', async t => { await t.throwsAsync( moveFile(tempWrite.sync('x'), tempWrite.sync('y'), {overwrite: false}), - /The destination file exists/ + { + message: /The destination file exists/, + }, ); }); diff --git a/test/sync.js b/test/sync.js index 5894e57..8101d5e 100644 --- a/test/sync.js +++ b/test/sync.js @@ -1,39 +1,41 @@ -import fs from 'fs'; +import fs from 'node:fs'; import test from 'ava'; import tempy from 'tempy'; import tempWrite from 'temp-write'; import sinon from 'sinon'; -import moveFile from '..'; +import {moveFileSync} from '../index.js'; const fixture = '🦄'; test('missing `source` or `destination` throws', t => { t.throws(() => { - moveFile.sync(); + moveFileSync(); }); }); test('move a file', t => { const destination = tempy.file(); - moveFile.sync(tempWrite.sync(fixture), destination); + moveFileSync(tempWrite.sync(fixture), destination); t.is(fs.readFileSync(destination, 'utf8'), fixture); }); test('move a file across devices', t => { - const exdevError = new Error(); + const exdevError = new Error('exdevError'); exdevError.code = 'EXDEV'; fs.renameSync = sinon.stub(fs, 'renameSync').throws(exdevError); const destination = tempy.file(); - moveFile.sync(tempWrite.sync(fixture), destination); + moveFileSync(tempWrite.sync(fixture), destination); t.is(fs.readFileSync(destination, 'utf8'), fixture); fs.renameSync.restore(); }); test('overwrite option', t => { t.throws(() => { - moveFile.sync(tempWrite.sync('x'), tempWrite.sync('y'), {overwrite: false}); - }, /The destination file exists/); + moveFileSync(tempWrite.sync('x'), tempWrite.sync('y'), {overwrite: false}); + }, { + message: /The destination file exists/, + }); }); test('directoryMode option', t => { @@ -41,7 +43,7 @@ test('directoryMode option', t => { const directory = `${root}/dir`; const destination = `${directory}/file`; const directoryMode = 0o700; - moveFile.sync(tempWrite.sync(fixture), destination, {directoryMode}); + moveFileSync(tempWrite.sync(fixture), destination, {directoryMode}); const stat = fs.statSync(directory); t.is(stat.mode & directoryMode, directoryMode); });