Skip to content

Commit

Permalink
Require Node.js 12.20 and move to ESM
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Aug 12, 2021
1 parent 0f39a71 commit ef6798c
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 131 deletions.
3 changes: 0 additions & 3 deletions .github/funding.yml

This file was deleted.

6 changes: 2 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
76 changes: 38 additions & 38 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -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<void>;
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<void>;

/**
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;
63 changes: 25 additions & 38 deletions index.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
};
}
34 changes: 17 additions & 17 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
import {expectError, expectType} from 'tsd';
import moveFile = require('.');
import {moveFile, moveFileSync} from './index.js';

expectType<Promise<void>>(
moveFile('source/unicorn.png', 'destination/unicorn.png')
moveFile('source/unicorn.png', 'destination/unicorn.png'),
);
expectType<Promise<void>>(
moveFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false})
moveFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false}),
);
expectType<Promise<void>>(
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<void>(
moveFile.sync('source/unicorn.png', 'destination/unicorn.png')
moveFileSync('source/unicorn.png', 'destination/unicorn.png'),
);
expectType<void>(
moveFile.sync('source/unicorn.png', 'destination/unicorn.png', {
overwrite: false
})
moveFileSync('source/unicorn.png', 'destination/unicorn.png', {
overwrite: false,
}),
);
expectType<void>(
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',
}),
);
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
}
}
18 changes: 8 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
10 changes: 6 additions & 4 deletions test/async.js
Original file line number Diff line number Diff line change
@@ -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 = '🦄';

Expand All @@ -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);

Expand All @@ -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/,
},
);
});

Expand Down
Loading

0 comments on commit ef6798c

Please sign in to comment.