Comparing version 9.1.0 to 10.0.0
67
fs.js
@@ -1,17 +0,16 @@ | ||
'use strict'; | ||
const {promisify} = require('util'); | ||
const fs = require('graceful-fs'); | ||
const makeDir = require('make-dir'); | ||
const pEvent = require('p-event'); | ||
const CpFileError = require('./cp-file-error'); | ||
import {promisify} from 'node:util'; | ||
import fs from 'graceful-fs'; | ||
import {pEvent} from 'p-event'; | ||
import CopyFileError from './copy-file-error.js'; | ||
const stat = promisify(fs.stat); | ||
const lstat = promisify(fs.lstat); | ||
const utimes = promisify(fs.utimes); | ||
const chmod = promisify(fs.chmod); | ||
const statP = promisify(fs.stat); | ||
const lstatP = promisify(fs.lstat); | ||
const utimesP = promisify(fs.utimes); | ||
const chmodP = promisify(fs.chmod); | ||
const makeDirectoryP = promisify(fs.mkdir); | ||
exports.closeSync = fs.closeSync.bind(fs); | ||
exports.createWriteStream = fs.createWriteStream.bind(fs); | ||
export const closeSync = fs.closeSync.bind(fs); | ||
export const createWriteStream = fs.createWriteStream.bind(fs); | ||
exports.createReadStream = async (path, options) => { | ||
export async function createReadStream(path, options) { | ||
const read = fs.createReadStream(path, options); | ||
@@ -22,58 +21,58 @@ | ||
} catch (error) { | ||
throw new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error); | ||
throw new CopyFileError(`Cannot read from \`${path}\`: ${error.message}`, error); | ||
} | ||
return read; | ||
}; | ||
} | ||
exports.stat = path => stat(path).catch(error => { | ||
throw new CpFileError(`Cannot stat path \`${path}\`: ${error.message}`, error); | ||
export const stat = path => statP(path).catch(error => { | ||
throw new CopyFileError(`Cannot stat path \`${path}\`: ${error.message}`, error); | ||
}); | ||
exports.lstat = path => lstat(path).catch(error => { | ||
throw new CpFileError(`lstat \`${path}\` failed: ${error.message}`, error); | ||
export const lstat = path => lstatP(path).catch(error => { | ||
throw new CopyFileError(`lstat \`${path}\` failed: ${error.message}`, error); | ||
}); | ||
exports.utimes = (path, atime, mtime) => utimes(path, atime, mtime).catch(error => { | ||
throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); | ||
export const utimes = (path, atime, mtime) => utimesP(path, atime, mtime).catch(error => { | ||
throw new CopyFileError(`utimes \`${path}\` failed: ${error.message}`, error); | ||
}); | ||
exports.chmod = (path, mode) => chmod(path, mode).catch(error => { | ||
throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); | ||
export const chmod = (path, mode) => chmodP(path, mode).catch(error => { | ||
throw new CopyFileError(`chmod \`${path}\` failed: ${error.message}`, error); | ||
}); | ||
exports.statSync = path => { | ||
export const statSync = path => { | ||
try { | ||
return fs.statSync(path); | ||
} catch (error) { | ||
throw new CpFileError(`stat \`${path}\` failed: ${error.message}`, error); | ||
throw new CopyFileError(`stat \`${path}\` failed: ${error.message}`, error); | ||
} | ||
}; | ||
exports.utimesSync = (path, atime, mtime) => { | ||
export const utimesSync = (path, atime, mtime) => { | ||
try { | ||
return fs.utimesSync(path, atime, mtime); | ||
} catch (error) { | ||
throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); | ||
throw new CopyFileError(`utimes \`${path}\` failed: ${error.message}`, error); | ||
} | ||
}; | ||
exports.makeDir = (path, options) => makeDir(path, {...options, fs}).catch(error => { | ||
throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); | ||
export const makeDirectory = (path, options) => makeDirectoryP(path, {...options, recursive: true}).catch(error => { | ||
throw new CopyFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); | ||
}); | ||
exports.makeDirSync = (path, options) => { | ||
export const makeDirectorySync = (path, options) => { | ||
try { | ||
makeDir.sync(path, {...options, fs}); | ||
fs.mkdirSync(path, {...options, recursive: true}); | ||
} catch (error) { | ||
throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); | ||
throw new CopyFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); | ||
} | ||
}; | ||
exports.copyFileSync = (source, destination, flags) => { | ||
export const copyFileSync = (source, destination, flags) => { | ||
try { | ||
fs.copyFileSync(source, destination, flags); | ||
} catch (error) { | ||
throw new CpFileError(`Cannot copy from \`${source}\` to \`${destination}\`: ${error.message}`, error); | ||
throw new CopyFileError(`Cannot copy from \`${source}\` to \`${destination}\`: ${error.message}`, error); | ||
} | ||
}; |
148
index.d.ts
@@ -1,91 +0,105 @@ | ||
declare namespace cpFile { | ||
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; | ||
interface ProgressData { | ||
/** | ||
Absolute path to source. | ||
*/ | ||
sourcePath: string; | ||
/** | ||
The working directory to find source files. | ||
/** | ||
Absolute path to destination. | ||
*/ | ||
destinationPath: string; | ||
The source and destination path are relative to this. | ||
/** | ||
File size in bytes. | ||
*/ | ||
size: number; | ||
/** | ||
Copied size in bytes. | ||
*/ | ||
writtenBytes: number; | ||
/** | ||
Copied percentage, a value between `0` and `1`. | ||
*/ | ||
percent: number; | ||
} | ||
interface ProgressEmitter { | ||
/** | ||
Note: For empty files, the `progress` event is emitted only once. | ||
*/ | ||
on(event: 'progress', handler: (data: ProgressData) => void): Promise<void>; | ||
} | ||
@default process.cwd() | ||
*/ | ||
readonly cwd?: string; | ||
} | ||
declare const cpFile: { | ||
export interface AsyncOptions { | ||
/** | ||
Copy a file. | ||
The given function is called whenever there is measurable progress. | ||
@param source - The file you want to copy. | ||
@param destination - Where you want the file copied. | ||
@returns A `Promise` that resolves when the file is copied. | ||
Note: For empty files, the `onProgress` event is emitted only once. | ||
@example | ||
``` | ||
import cpFile = require('cp-file'); | ||
import {copyFile} from 'cp-file'; | ||
(async () => { | ||
await cpFile('source/unicorn.png', 'destination/unicorn.png'); | ||
console.log('File copied'); | ||
})(); | ||
await copyFile('source/unicorn.png', 'destination/unicorn.png', { | ||
onProgress: progress => { | ||
// … | ||
} | ||
}); | ||
``` | ||
*/ | ||
(source: string, destination: string, options?: cpFile.Options): Promise<void> & cpFile.ProgressEmitter; | ||
readonly onProgress?: (progress: ProgressData) => void; | ||
} | ||
export interface ProgressData { | ||
/** | ||
Copy a file synchronously. | ||
Absolute path to source. | ||
*/ | ||
sourcePath: string; | ||
@param source - The file you want to copy. | ||
@param destination - Where you want the file copied. | ||
/** | ||
Absolute path to destination. | ||
*/ | ||
destinationPath: string; | ||
@example | ||
``` | ||
import cpFile = require('cp-file'); | ||
/** | ||
File size in bytes. | ||
*/ | ||
size: number; | ||
cpFile.sync('source/unicorn.png', 'destination/unicorn.png'); | ||
``` | ||
/** | ||
Copied size in bytes. | ||
*/ | ||
sync(source: string, destination: string, options?: cpFile.Options): void; | ||
}; | ||
writtenBytes: number; | ||
export = cpFile; | ||
/** | ||
Copied percentage, a value between `0` and `1`. | ||
*/ | ||
percent: number; | ||
} | ||
/** | ||
Copy a file. | ||
@param source - The file you want to copy. | ||
@param destination - Where you want the file copied. | ||
@returns A `Promise` that resolves when the file is copied. | ||
@example | ||
``` | ||
import {copyFile} from 'cp-file'; | ||
await copyFile('source/unicorn.png', 'destination/unicorn.png'); | ||
console.log('File copied'); | ||
``` | ||
*/ | ||
export function copyFile(source: string, destination: string, options?: Options & AsyncOptions): Promise<void>; | ||
/** | ||
Copy a file synchronously. | ||
@param source - The file you want to copy. | ||
@param destination - Where you want the file copied. | ||
@example | ||
``` | ||
import {copyFileSync} from 'cp-file'; | ||
copyFileSync('source/unicorn.png', 'destination/unicorn.png'); | ||
``` | ||
*/ | ||
export function copyFileSync(source: string, destination: string, options?: Options): void; |
106
index.js
@@ -1,25 +0,35 @@ | ||
'use strict'; | ||
const path = require('path'); | ||
const {constants: fsConstants} = require('fs'); | ||
const pEvent = require('p-event'); | ||
const CpFileError = require('./cp-file-error'); | ||
const fs = require('./fs'); | ||
const ProgressEmitter = require('./progress-emitter'); | ||
import path from 'node:path'; | ||
import {constants as fsConstants} from 'node:fs'; | ||
import {pEvent} from 'p-event'; | ||
import CopyFileError from './copy-file-error.js'; | ||
import * as fs from './fs.js'; | ||
const cpFileAsync = async (source, destination, options, progressEmitter) => { | ||
const copyFileAsync = async (source, destination, options) => { | ||
let readError; | ||
const stat = await fs.stat(source); | ||
progressEmitter.size = stat.size; | ||
const {size} = await fs.stat(source); | ||
const readStream = await fs.createReadStream(source); | ||
await fs.makeDir(path.dirname(destination), {mode: options.directoryMode}); | ||
await fs.makeDirectory(path.dirname(destination), {mode: options.directoryMode}); | ||
const writeStream = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'}); | ||
const emitProgress = writtenBytes => { | ||
if (typeof options.onProgress !== 'function') { | ||
return; | ||
} | ||
options.onProgress({ | ||
sourcePath: path.resolve(source), | ||
destinationPath: path.resolve(destination), | ||
size, | ||
writtenBytes, | ||
percent: writtenBytes === size ? 1 : writtenBytes / size, | ||
}); | ||
}; | ||
readStream.on('data', () => { | ||
progressEmitter.writtenBytes = writeStream.bytesWritten; | ||
emitProgress(writeStream.bytesWritten); | ||
}); | ||
readStream.once('error', error => { | ||
readError = new CpFileError(`Cannot read from \`${source}\`: ${error.message}`, error); | ||
writeStream.end(); | ||
readError = new CopyFileError(`Cannot read from \`${source}\`: ${error.message}`, error); | ||
}); | ||
@@ -32,6 +42,6 @@ | ||
await writePromise; | ||
progressEmitter.writtenBytes = progressEmitter.size; | ||
emitProgress(size); | ||
shouldUpdateStats = true; | ||
} catch (error) { | ||
throw new CpFileError(`Cannot write to \`${destination}\`: ${error.message}`, error); | ||
throw new CopyFileError(`Cannot write to \`${destination}\`: ${error.message}`, error); | ||
} | ||
@@ -48,3 +58,3 @@ | ||
fs.utimes(destination, stats.atime, stats.mtime), | ||
fs.chmod(destination, stats.mode) | ||
fs.chmod(destination, stats.mode), | ||
]); | ||
@@ -54,31 +64,35 @@ } | ||
const cpFile = (sourcePath, destinationPath, options) => { | ||
const resolvePath = (cwd, sourcePath, destinationPath) => { | ||
sourcePath = path.resolve(cwd, sourcePath); | ||
destinationPath = path.resolve(cwd, destinationPath); | ||
return { | ||
sourcePath, | ||
destinationPath, | ||
}; | ||
}; | ||
export async function copyFile(sourcePath, destinationPath, options = {}) { | ||
if (!sourcePath || !destinationPath) { | ||
return Promise.reject(new CpFileError('`source` and `destination` required')); | ||
throw new CopyFileError('`source` and `destination` required'); | ||
} | ||
if (options.cwd) { | ||
({sourcePath, destinationPath} = resolvePath(options.cwd, sourcePath, destinationPath)); | ||
} | ||
options = { | ||
overwrite: true, | ||
...options | ||
...options, | ||
}; | ||
const progressEmitter = new ProgressEmitter(path.resolve(sourcePath), path.resolve(destinationPath)); | ||
const promise = cpFileAsync(sourcePath, destinationPath, options, progressEmitter); | ||
return copyFileAsync(sourcePath, destinationPath, options); | ||
} | ||
promise.on = (...arguments_) => { | ||
progressEmitter.on(...arguments_); | ||
return promise; | ||
}; | ||
return promise; | ||
}; | ||
module.exports = cpFile; | ||
const checkSourceIsFile = (stat, source) => { | ||
if (stat.isDirectory()) { | ||
throw Object.assign(new CpFileError(`EISDIR: illegal operation on a directory '${source}'`), { | ||
throw Object.assign(new CopyFileError(`EISDIR: illegal operation on a directory '${source}'`), { | ||
errno: -21, | ||
code: 'EISDIR', | ||
source | ||
source, | ||
}); | ||
@@ -88,19 +102,23 @@ } | ||
module.exports.sync = (source, destination, options) => { | ||
if (!source || !destination) { | ||
throw new CpFileError('`source` and `destination` required'); | ||
export function copyFileSync(sourcePath, destinationPath, options = {}) { | ||
if (!sourcePath || !destinationPath) { | ||
throw new CopyFileError('`source` and `destination` required'); | ||
} | ||
if (options.cwd) { | ||
({sourcePath, destinationPath} = resolvePath(options.cwd, sourcePath, destinationPath)); | ||
} | ||
options = { | ||
overwrite: true, | ||
...options | ||
...options, | ||
}; | ||
const stat = fs.statSync(source); | ||
checkSourceIsFile(stat, source); | ||
fs.makeDirSync(path.dirname(destination), {mode: options.directoryMode}); | ||
const stat = fs.statSync(sourcePath); | ||
checkSourceIsFile(stat, sourcePath); | ||
fs.makeDirectorySync(path.dirname(destinationPath), {mode: options.directoryMode}); | ||
const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL; | ||
try { | ||
fs.copyFileSync(source, destination, flags); | ||
fs.copyFileSync(sourcePath, destinationPath, flags); | ||
} catch (error) { | ||
@@ -114,3 +132,3 @@ if (!options.overwrite && error.code === 'EEXIST') { | ||
fs.utimesSync(destination, stat.atime, stat.mtime); | ||
}; | ||
fs.utimesSync(destinationPath, stat.atime, stat.mtime); | ||
} |
{ | ||
"name": "cp-file", | ||
"version": "9.1.0", | ||
"version": "10.0.0", | ||
"description": "Copy a file", | ||
@@ -13,4 +13,7 @@ "license": "MIT", | ||
}, | ||
"type": "module", | ||
"exports": "./index.js", | ||
"types": "./index.d.ts", | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=14.16" | ||
}, | ||
@@ -21,7 +24,6 @@ "scripts": { | ||
"files": [ | ||
"cp-file-error.js", | ||
"fs.js", | ||
"index.js", | ||
"index.d.ts", | ||
"progress-emitter.js" | ||
"copy-file-error.js", | ||
"fs.js" | ||
], | ||
@@ -44,24 +46,26 @@ "keywords": [ | ||
"dependencies": { | ||
"graceful-fs": "^4.1.2", | ||
"make-dir": "^3.0.0", | ||
"nested-error-stacks": "^2.0.0", | ||
"p-event": "^4.1.0" | ||
"graceful-fs": "^4.2.10", | ||
"nested-error-stacks": "^2.1.1", | ||
"p-event": "^5.0.1" | ||
}, | ||
"devDependencies": { | ||
"ava": "^2.1.0", | ||
"clear-module": "^3.1.0", | ||
"coveralls": "^3.0.4", | ||
"del": "^5.1.0", | ||
"import-fresh": "^3.0.0", | ||
"nyc": "^15.0.0", | ||
"sinon": "^9.0.0", | ||
"tsd": "^0.11.0", | ||
"uuid": "^7.0.2", | ||
"xo": "^0.28.2" | ||
"ava": "^4.3.0", | ||
"clear-module": "^4.1.2", | ||
"coveralls": "^3.1.1", | ||
"del": "^6.1.1", | ||
"import-fresh": "^3.3.0", | ||
"nyc": "^15.1.0", | ||
"sinon": "^14.0.0", | ||
"tsd": "^0.21.0", | ||
"xo": "^0.50.0" | ||
}, | ||
"xo": { | ||
"rules": { | ||
"unicorn/string-content": "off" | ||
"unicorn/string-content": "off", | ||
"ava/assertion-arguments": "off" | ||
} | ||
}, | ||
"ava": { | ||
"workerThreads": false | ||
} | ||
} |
@@ -16,5 +16,5 @@ # cp-file | ||
```sh | ||
npm install cp-file | ||
``` | ||
$ npm install cp-file | ||
``` | ||
@@ -24,8 +24,6 @@ ## Usage | ||
```js | ||
const cpFile = require('cp-file'); | ||
import {copyFile} from 'cp-file'; | ||
(async () => { | ||
await cpFile('source/unicorn.png', 'destination/unicorn.png'); | ||
console.log('File copied'); | ||
})(); | ||
await copyFile('source/unicorn.png', 'destination/unicorn.png'); | ||
console.log('File copied'); | ||
``` | ||
@@ -35,7 +33,7 @@ | ||
### cpFile(source, destination, options?) | ||
### copyFile(source, destination, options?) | ||
Returns a `Promise` that resolves when the file is copied. | ||
### cpFile.sync(source, destination, options?) | ||
### copyFileSync(source, destination, options?) | ||
@@ -65,2 +63,11 @@ #### source | ||
##### cwd | ||
Type: `string`\ | ||
Default: `process.cwd()` | ||
The working directory to find source files. | ||
The source and destination path are relative to this. | ||
##### directoryMode | ||
@@ -75,11 +82,11 @@ | ||
### cpFile.on('progress', handler) | ||
##### onProgress | ||
Progress reporting. Only available when using the async method. | ||
Type: `(progress: ProgressData) => void` | ||
#### handler(data) | ||
The given function is called whenever there is measurable progress. | ||
Type: `Function` | ||
Only available when using the async method. | ||
##### data | ||
###### `ProgressData` | ||
@@ -96,3 +103,3 @@ ```js | ||
- `source` and `destination` are absolute paths. | ||
- `sourcePath` and `destinationPath` are absolute paths. | ||
- `size` and `writtenBytes` are in bytes. | ||
@@ -103,14 +110,12 @@ - `percent` is a value between `0` and `1`. | ||
- For empty files, the `progress` event is emitted only once. | ||
- The `.on()` method is available only right after the initial `cpFile()` call. So make sure | ||
you add a `handler` before `.then()`: | ||
- For empty files, the `onProgress` callback function is emitted only once. | ||
```js | ||
const cpFile = require('cp-file'); | ||
import {copyFile} from 'cp-file'; | ||
(async () => { | ||
await cpFile(source, destination).on('progress', data => { | ||
await copyFile(source, destination, { | ||
onProgress: progress => { | ||
// … | ||
}); | ||
})(); | ||
} | ||
}); | ||
``` | ||
@@ -117,0 +122,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
12807
3
9
122
1
Yes
7
258
1
+ Addedp-event@5.0.1(transitive)
+ Addedp-timeout@5.1.0(transitive)
- Removedmake-dir@^3.0.0
- Removedmake-dir@3.1.0(transitive)
- Removedp-event@4.2.0(transitive)
- Removedp-finally@1.0.0(transitive)
- Removedp-timeout@3.2.0(transitive)
- Removedsemver@6.3.1(transitive)
Updatedgraceful-fs@^4.2.10
Updatednested-error-stacks@^2.1.1
Updatedp-event@^5.0.1