From f2b332123cfe7d9cd924577894fa4dd277ef6b4a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 12 Jul 2021 15:15:03 +0200 Subject: [PATCH] Move to ESM --- .github/funding.yml | 3 - .github/workflows/main.yml | 3 +- cpy-error.js | 7 +- glob-pattern.js | 29 ++-- index.d.ts | 323 ++++++++++++++++++------------------- index.js | 151 +++++++++-------- index.test-d.ts | 27 ++-- license | 2 +- package.json | 21 ++- readme.md | 80 +++++---- test.js | 109 ++++++------- 11 files changed, 363 insertions(+), 392 deletions(-) delete mode 100644 .github/funding.yml 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 aafa751..495ba52 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,6 +10,7 @@ jobs: fail-fast: false matrix: node-version: + - 16 - 14 - 12 os: @@ -18,7 +19,7 @@ jobs: - windows-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/cpy-error.js b/cpy-error.js index 4a0fcac..f5a1f40 100644 --- a/cpy-error.js +++ b/cpy-error.js @@ -1,12 +1,9 @@ -'use strict'; -const NestedError = require('nested-error-stacks'); +import NestedError from 'nested-error-stacks'; -class CpyError extends NestedError { +export default class CpyError extends NestedError { constructor(message, nested) { super(message, nested); Object.assign(this, nested); this.name = 'CpyError'; } } - -module.exports = CpyError; diff --git a/glob-pattern.js b/glob-pattern.js index 7fd3445..8b5f9de 100644 --- a/glob-pattern.js +++ b/glob-pattern.js @@ -1,15 +1,14 @@ -'use strict'; -const glob = require('globby'); -const junk = require('junk'); -const path = require('path'); -const fs = require('fs'); +import path from 'node:path'; +import fs from 'node:fs'; +import glob from 'globby'; +import junk from 'junk'; -class GlobPattern { +export default class GlobPattern { /** - * @param {string} pattern - * @param {string} destination - * @param {import('.').Options} options - */ + @param {string} pattern + @param {string} destination + @param {import('.').Options} options + */ constructor(pattern, destination, options) { this.path = pattern; this.originalPath = pattern; @@ -17,9 +16,9 @@ class GlobPattern { this.options = options; if ( - !glob.hasMagic(pattern) && - fs.existsSync(pattern) && - fs.lstatSync(pattern).isDirectory() + !glob.hasMagic(pattern) + && fs.existsSync(pattern) + && fs.lstatSync(pattern).isDirectory() ) { this.path = [pattern, '**'].join('/'); } @@ -50,7 +49,7 @@ class GlobPattern { ...this.options, dot: true, absolute: true, - onlyFiles: true + onlyFiles: true, }); if (this.options.ignoreJunk) { @@ -60,5 +59,3 @@ class GlobPattern { return matches; } } - -module.exports = GlobPattern; diff --git a/index.d.ts b/index.d.ts index 66f02e3..1b8f812 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,185 +1,176 @@ import {GlobbyOptions as GlobOptions} from 'globby'; import {Options as CpFileOptions} from 'cp-file'; -declare namespace cpy { - interface Entry { - /** - Resolved path to the file. - - @example '/tmp/dir/foo.js' - */ - readonly path: string; - - /** - Relative path to the file from cwd. - - @example 'dir/foo.js' - */ - readonly relativePath: string; - - /** - Filename with extension. - - @example 'foo.js' - */ - readonly name: string; - - /** - Filename without extension. - - @example 'foo' - */ - readonly nameWithoutExtension: string; - - /** - File extension. - - @example 'js' - */ - readonly extension: string; - } - - interface Options extends Readonly, CpFileOptions { - /** - Working directory to find source files. - - @default process.cwd() - */ - readonly cwd?: string; - - /** - Flatten directory tree. - - @default false - */ - readonly flat?: boolean; - - /** - Filename or function returning a filename used to rename every file in `source`. - - @example - ``` - import cpy = require('cpy'); - - (async () => { - await cpy('foo.js', 'destination', { - rename: basename => `prefix-${basename}` - }); - await cpy('foo.js', 'destination', { - rename: 'new-name' - }); - })(); - ``` - */ - readonly rename?: string | ((basename: string) => string); - - /** - Number of files being copied concurrently. - - @default (os.cpus().length || 1) * 2 - */ - readonly concurrency?: number; - - /** - Ignore junk files. - - @default true - */ - readonly ignoreJunk?: boolean; - - /** - Function to filter files to copy. - - Receives a source file object as the first argument. - - Return true to include, false to exclude. You can also return a Promise that resolves to true or false. - - @example - ``` - import cpy = require('cpy'); - - (async () => { - await cpy('foo', 'destination', { - filter: file => file.extension !== 'nocopy' - }); - })(); - ``` - */ - readonly filter?: (file: Entry) => boolean | Promise; - } - - interface ProgressData { - /** - Copied file count. - */ - completedFiles: number; - - /** - Overall file count. - */ - totalFiles: number; - - /** - Completed size in bytes. - */ - completedSize: number; - - /** - Completed percentage. A value between `0` and `1`. - */ - percent: number; - } - - interface ProgressEmitter { - on( - event: 'progress', - handler: (progress: ProgressData) => void - ): Promise; - } - - interface CopyStatus { - written: number; - percent: number; - } +export interface Entry { + /** + Resolved path to the file. + + @example '/tmp/dir/foo.js' + */ + readonly path: string; + + /** + Relative path to the file from cwd. + + @example 'dir/foo.js' + */ + readonly relativePath: string; + + /** + Filename with extension. + + @example 'foo.js' + */ + readonly name: string; + + /** + Filename without extension. + + @example 'foo' + */ + readonly nameWithoutExtension: string; + + /** + File extension. + + @example 'js' + */ + readonly extension: string; } -/** - Copy files. +export interface Options extends Readonly, CpFileOptions { + /** + Working directory to find source files. - @param source - Files to copy. If any of the files do not exist, an error will be thrown (does not apply to globs). - @param destination - Destination directory. - @param options - In addition to the options defined here, options are passed to [globby](https://github.com/sindresorhus/globby#options). + @default process.cwd() + */ + readonly cwd?: string; + + /** + Flatten directory tree. + + @default false + */ + readonly flat?: boolean; + + /** + Filename or function returning a filename used to rename every file in `source`. @example ``` - const cpy = require('cpy'); + import cpy from 'cpy'; + + await cpy('foo.js', 'destination', { + rename: basename => `prefix-${basename}` + }); + + await cpy('foo.js', 'destination', { + rename: 'new-name' + }); + ``` + */ + readonly rename?: string | ((basename: string) => string); + + /** + Number of files being copied concurrently. + + @default (os.cpus().length || 1) * 2 + */ + readonly concurrency?: number; - (async () => { - await cpy([ - 'source/*.png', // Copy all .png files - '!source/goat.png', // Ignore goat.png - ], 'destination'); + /** + Ignore junk files. - // Copy node_modules to destination/node_modules - await cpy('node_modules', 'destination'); + @default true + */ + readonly ignoreJunk?: boolean; - // Copy node_modules content to destination - await cpy('node_modules/**', 'destination'); + /** + Function to filter files to copy. - // Copy node_modules structure but skip all files except any .json files - await cpy('node_modules/**\/*.json', 'destination'); + Receives a source file object as the first argument. - // Copy all png files into destination without keeping directory structure - await cpy('**\/*.png', 'destination', {flat: true}); + Return true to include, false to exclude. You can also return a Promise that resolves to true or false. - console.log('Files copied!'); - })(); + @example ``` + import cpy from 'cpy'; + + await cpy('foo', 'destination', { + filter: file => file.extension !== 'nocopy' + }); + ``` + */ + readonly filter?: (file: Entry) => boolean | Promise; +} + +export interface ProgressData { + /** + Copied file count. + */ + completedFiles: number; + + /** + Overall file count. + */ + totalFiles: number; + + /** + Completed size in bytes. + */ + completedSize: number; + + /** + Completed percentage. A value between `0` and `1`. + */ + percent: number; +} + +export interface ProgressEmitter { + on( + event: 'progress', + handler: (progress: ProgressData) => void + ): Promise; +} + +export interface CopyStatus { + written: number; + percent: number; +} + +/** +Copy files. + +@param source - Files to copy. If any of the files do not exist, an error will be thrown (does not apply to globs). +@param destination - Destination directory. +@param options - In addition to the options defined here, options are passed to [globby](https://github.com/sindresorhus/globby#options). + +@example +``` +import cpy from 'cpy'; + +await cpy([ + 'source/*.png', // Copy all .png files + '!source/goat.png', // Ignore goat.png +], 'destination'); + +// Copy node_modules to destination/node_modules +await cpy('node_modules', 'destination'); + +// Copy node_modules content to destination +await cpy('node_modules/**', 'destination'); + +// Copy node_modules structure but skip all files except any .json files +await cpy('node_modules/**\/*.json', 'destination'); + +// Copy all png files into destination without keeping directory structure +await cpy('**\/*.png', 'destination', {flat: true}); + +console.log('Files copied!'); +``` */ -declare function cpy( +export default function cpy( source: string | readonly string[], destination: string, - options?: cpy.Options -): Promise & cpy.ProgressEmitter; - -export = cpy; + options?: Options +): Promise & ProgressEmitter; diff --git a/index.js b/index.js index dd085f5..84b43ba 100644 --- a/index.js +++ b/index.js @@ -1,41 +1,40 @@ -'use strict'; -const EventEmitter = require('events'); -const path = require('path'); -const os = require('os'); -const pMap = require('p-map'); -const arrify = require('arrify'); -const cpFile = require('cp-file'); -const pFilter = require('p-filter'); -const CpyError = require('./cpy-error'); -const GlobPattern = require('./glob-pattern'); -const glob = require('globby'); - -const defaultConcurrency = (os.cpus().length || 1) * 2; +import EventEmitter from 'node:events'; +import path from 'node:path'; +import os from 'node:os'; +import pMap from 'p-map'; +import arrify from 'arrify'; +import cpFile from 'cp-file'; +import pFilter from 'p-filter'; +import glob from 'globby'; +import CpyError from './cpy-error.js'; +import GlobPattern from './glob-pattern.js'; + +const defaultConcurrency = (os.cpus().length || 1) * 2; // eslint-disable-line unicorn/explicit-length-check /** - * @type {import('./index').Options} - */ +@type {import('./index').Options} +*/ const defaultOptions = { ignoreJunk: true, flat: false, - cwd: process.cwd() + cwd: process.cwd(), }; class Entry { /** - * @param {string} source - * @param {string} relativePath - * @param {GlobPattern} pattern - */ + @param {string} source + @param {string} relativePath + @param {GlobPattern} pattern + */ constructor(source, relativePath, pattern) { /** - * @type {string} - */ + @type {string} + */ this.path = source.split('/').join(path.sep); /** - * @type {string} - */ + @type {string} + */ this.relativePath = relativePath.split('/').join(path.sep); this.pattern = pattern; @@ -57,12 +56,12 @@ class Entry { } /** - * @param {object} props - * @param {Entry} props.entry - * @param {import('./index').Options} - * @param {string} props.destination - * @returns {string} - */ +@param {object} props +@param {Entry} props.entry +@param {import('./index').Options} +@param {string} props.destination +@returns {string} +*/ const preprocessDestinationPath = ({entry, destination, options}) => { if (entry.pattern.hasMagic()) { if (options.flat) { @@ -75,7 +74,7 @@ const preprocessDestinationPath = ({entry, destination, options}) => { return path.join( destination, - path.relative(entry.pattern.normalizedPath, entry.path) + path.relative(entry.pattern.normalizedPath, entry.path), ); } @@ -87,9 +86,9 @@ const preprocessDestinationPath = ({entry, destination, options}) => { }; /** - * @param {string} source - * @param {string|Function} rename - */ +@param {string} source +@param {string|Function} rename +*/ const renameFile = (source, rename) => { const filename = path.basename(source, path.extname(source)); const ext = path.extname(source); @@ -106,40 +105,40 @@ const renameFile = (source, rename) => { }; /** - * @param {string|string[]} source - * @param {string} destination - * @param {import('./index').Options} options - */ -const cpy = ( +@param {string|string[]} source +@param {string} destination +@param {import('./index').Options} options +*/ +export default function cpy( source, destination, - {concurrency = defaultConcurrency, ...options} = {} -) => { + {concurrency = defaultConcurrency, ...options} = {}, +) { /** - * @type {Map} - */ + @type {Map} + */ const copyStatus = new Map(); /** - * @type {import('events').EventEmitter} - */ + @type {import('events').EventEmitter} + */ const progressEmitter = new EventEmitter(); options = { ...defaultOptions, - ...options + ...options, }; const promise = (async () => { /** - * @type {Entry[]} - */ + @type {Entry[]} + */ let entries = []; let completedFiles = 0; let completedSize = 0; /** - * @type {GlobPattern[]} - */ + @type {GlobPattern[]} + */ let patterns = arrify(source).map(string => string.replace(/\\/g, '/')); if (patterns.length === 0 || !destination) { @@ -150,8 +149,8 @@ const cpy = ( for (const pattern of patterns) { /** - * @type {string[]} - */ + @type {string[]} + */ let matches = []; try { @@ -159,19 +158,19 @@ const cpy = ( } catch (error) { throw new CpyError( `Cannot glob \`${pattern.originalPath}\`: ${error.message}`, - error + error, ); } if (matches.length === 0 && !glob.hasMagic(pattern.originalPath)) { throw new CpyError( - `Cannot copy \`${pattern.originalPath}\`: the file doesn't exist` + `Cannot copy \`${pattern.originalPath}\`: the file doesn't exist`, ); } entries = [ ...entries, - ...matches.map(sourcePath => new Entry(sourcePath, path.relative(options.cwd, sourcePath), pattern)) + ...matches.map(sourcePath => new Entry(sourcePath, path.relative(options.cwd, sourcePath), pattern)), ]; } @@ -184,40 +183,40 @@ const cpy = ( totalFiles: 0, percent: 1, completedFiles: 0, - completedSize: 0 + completedSize: 0, }); } /** - * @param {import('cp-file').ProgressData} event - */ + @param {import('cp-file').ProgressData} event + */ const fileProgressHandler = event => { - const fileStatus = copyStatus.get(event.src) || { - written: 0, - percent: 0 + const fileStatus = copyStatus.get(event.sourcePath) || { + writtenBytes: 0, + percent: 0, }; if ( - fileStatus.written !== event.written || - fileStatus.percent !== event.percent + fileStatus.writtenBytes !== event.writtenBytes + || fileStatus.percent !== event.percent ) { - completedSize -= fileStatus.written; - completedSize += event.written; + completedSize -= fileStatus.writtenBytes; + completedSize += event.writtenBytes; if (event.percent === 1 && fileStatus.percent !== 1) { completedFiles++; } - copyStatus.set(event.src, { - written: event.written, - percent: event.percent + copyStatus.set(event.sourcePath, { + writtenBytes: event.writtenBytes, + percent: event.percent, }); progressEmitter.emit('progress', { totalFiles: entries.length, percent: completedFiles / entries.length, completedFiles, - completedSize + completedSize, }); } }; @@ -229,26 +228,26 @@ const cpy = ( preprocessDestinationPath({ entry, destination, - options + options, }), - options.rename + options.rename, ); try { await cpFile(entry.path, to, options).on( 'progress', - fileProgressHandler + fileProgressHandler, ); } catch (error) { throw new CpyError( `Cannot copy from \`${entry.relativePath}\` to \`${to}\`: ${error.message}`, - error + error, ); } return to; }, - {concurrency} + {concurrency}, ); })(); @@ -258,6 +257,4 @@ const cpy = ( }; return promise; -}; - -module.exports = cpy; +} diff --git a/index.test-d.ts b/index.test-d.ts index dc782c5..2871cdc 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,33 +1,32 @@ import {expectType} from 'tsd'; -import cpy = require('.'); -import {ProgressEmitter, ProgressData} from '.'; +import cpy, {ProgressEmitter, ProgressData, Entry} from './index.js'; expectType & ProgressEmitter>( - cpy(['source/*.png', '!source/goat.png'], 'destination') + cpy(['source/*.png', '!source/goat.png'], 'destination'), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {rename: 'foobar'}) + cpy('foo.js', 'destination', {rename: 'foobar'}), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {rename: basename => `prefix-${basename}`}) + cpy('foo.js', 'destination', {rename: basename => `prefix-${basename}`}), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {cwd: '/'}) + cpy('foo.js', 'destination', {cwd: '/'}), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {flat: true}) + cpy('foo.js', 'destination', {flat: true}), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {overwrite: false}) + cpy('foo.js', 'destination', {overwrite: false}), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {concurrency: 2}) + cpy('foo.js', 'destination', {concurrency: 2}), ); expectType & ProgressEmitter>( cpy('foo.js', 'destination', { filter: file => { - expectType(file); + expectType(file); expectType(file.path); expectType(file.relativePath); @@ -35,11 +34,11 @@ expectType & ProgressEmitter>( expectType(file.nameWithoutExtension); expectType(file.extension); return true; - } - }) + }, + }), ); expectType & ProgressEmitter>( - cpy('foo.js', 'destination', {filter: async (file: cpy.Entry) => true}) + cpy('foo.js', 'destination', {filter: async (_file: Entry) => true}), ); expectType>( @@ -50,5 +49,5 @@ expectType>( expectType(progress.totalFiles); expectType(progress.completedSize); expectType(progress.percent); - }) + }), ); diff --git a/license b/license index e7af2f7..fa7ceba 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/package.json b/package.json index feb3050..66bffa1 100644 --- a/package.json +++ b/package.json @@ -8,18 +8,16 @@ "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" + "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=12" + "node": ">=12.20" }, "scripts": { "test": "xo && ava && tsd" }, - "prettier": { - "bracketSpacing": false, - "singleQuote": true - }, "files": [ "cpy-error.js", "index.js", @@ -47,20 +45,21 @@ "directories" ], "dependencies": { - "arrify": "^2.0.1", - "cp-file": "^7.0.0", + "arrify": "^3.0.0", + "cp-file": "^9.1.0", "globby": "^11.0.4", "junk": "^3.1.0", "nested-error-stacks": "^2.1.0", "p-filter": "^2.1.0", - "p-map": "^3.0.0" + "p-map": "^5.0.0" }, "devDependencies": { "ava": "^3.15.0", "proxyquire": "^2.1.3", - "rimraf": "^3.0.0", + "rimraf": "^3.0.2", "tempy": "^1.0.1", "tsd": "^0.17.0", - "xo": "^0.25.4" + "typescript": "^4.3.5", + "xo": "^0.41.0" } } diff --git a/readme.md b/readme.md index cc73d9d..4ea84d2 100644 --- a/readme.md +++ b/readme.md @@ -19,28 +19,26 @@ $ npm install cpy ## Usage ```js -const cpy = require('cpy'); +import cpy from 'cpy'; -(async () => { - await cpy([ - 'source/*.png', // Copy all .png files - '!source/goat.png', // Ignore goat.png - ], 'destination'); +await cpy([ + 'source/*.png', // Copy all .png files + '!source/goat.png', // Ignore goat.png +], 'destination'); - // Copy node_modules to destination/node_modules - await cpy('node_modules', 'destination'); +// Copy node_modules to destination/node_modules +await cpy('node_modules', 'destination'); - // Copy node_modules content to destination - await cpy('node_modules/**', 'destination'); +// Copy node_modules content to destination +await cpy('node_modules/**', 'destination'); - // Copy node_modules structure but skip all files except package.json files - await cpy('node_modules/**/*.json', 'destination'); +// Copy node_modules structure but skip all files except package.json files +await cpy('node_modules/**/*.json', 'destination'); - // Copy all png files into destination without keeping directory structure - await cpy('**/*.png', 'destination', {flat: true}); +// Copy all png files into destination without keeping directory structure +await cpy('**/*.png', 'destination', {flat: true}); - console.log('Files copied!'); -})(); +console.log('Files copied!'); ``` ## API @@ -92,15 +90,12 @@ Default: `false` Flatten directory structure. All copied files will be put in the same directory. - ```js -const cpy = require('cpy'); +import cpy from 'cpy'; -(async () => { - await cpy('src/**/*.js', 'destination', { - flat: true - }); -})(); +await cpy('src/**/*.js', 'destination', { + flat: true +}); ``` ##### rename @@ -110,16 +105,15 @@ Type: `string | Function` Filename or function returning a filename used to rename every file in `source`. ```js -const cpy = require('cpy'); - -(async () => { - await cpy('foo.js', 'destination', { - rename: basename => `prefix-${basename}` - }); - await cpy('foo.js', 'destination', { - rename: 'new-name' - }); -})(); +import cpy from 'cpy'; + +await cpy('foo.js', 'destination', { + rename: basename => `prefix-${basename}` +}); + +await cpy('foo.js', 'destination', { + rename: 'new-name' +}); ``` ##### concurrency @@ -147,13 +141,11 @@ Receives a source file object as the first argument. Return true to include, false to exclude. You can also return a Promise that resolves to true or false. ```js -const cpy = require('cpy'); +import cpy from 'cpy'; -(async () => { - await cpy('foo', 'destination', { - filter: file => file.extension !== 'nocopy' - }); -})(); +await cpy('foo', 'destination', { + filter: file => file.extension !== 'nocopy' +}); ``` ##### Source file object @@ -218,11 +210,11 @@ Type: `Function` Note that the `.on()` method is available only right after the initial `cpy` call, so make sure you add a `handler` before awaiting the promise: ```js -(async () => { - await cpy(source, destination).on('progress', progress => { - // … - }); -})(); +import cpy from 'cpy'; + +await cpy(source, destination).on('progress', progress => { + // … +}); ``` ## Related diff --git a/test.js b/test.js index f9ea210..2745b7d 100644 --- a/test.js +++ b/test.js @@ -1,21 +1,20 @@ -const path = require('path'); -const fs = require('fs'); -const crypto = require('crypto'); -const rimraf = require('rimraf'); -const test = require('ava'); -const tempy = require('tempy'); -const proxyquire = require('proxyquire'); -const CpyError = require('./cpy-error'); -const cpy = require('.'); +import path from 'node:path'; +import fs from 'node:fs'; +import crypto from 'node:crypto'; +import rimraf from 'rimraf'; +import test from 'ava'; +import tempy from 'tempy'; +import proxyquire from 'proxyquire'; +import CpyError from './cpy-error.js'; +import cpy from './index.js'; const read = (...args) => fs.readFileSync(path.join(...args), 'utf8'); -const cpyMockedError = module => { - return proxyquire('.', { - [module]() { - throw new Error(`${module}:\tERROR`); - } - }); -}; + +const cpyMockedError = module => proxyquire('.', { + [module]() { + throw new Error(`${module}:\tERROR`); + }, +}); test.beforeEach(t => { t.context.tmp = tempy.file(); @@ -54,10 +53,10 @@ test('copy array of files', async t => { test('throws on invalid concurrency value', async t => { await t.throwsAsync( - cpy(['license', 'package.json'], t.context.tmp, {concurrency: -2}) + cpy(['license', 'package.json'], t.context.tmp, {concurrency: -2}), ); await t.throwsAsync( - cpy(['license', 'package.json'], t.context.tmp, {concurrency: 'foo'}) + cpy(['license', 'package.json'], t.context.tmp, {concurrency: 'foo'}), ); }); @@ -77,7 +76,7 @@ test('copy array of files with filter', async t => { } return !file.path.endsWith('license'); - } + }, }); t.false(fs.existsSync(path.join(t.context.tmp, 'license'))); @@ -100,7 +99,7 @@ test('copy array of files with async filter', async t => { } return !file.path.endsWith(`${path.sep}license`); - } + }, }); t.false(fs.existsSync(path.join(t.context.tmp, 'license'))); @@ -112,16 +111,16 @@ test('cwd', async t => { fs.mkdirSync(path.join(t.context.tmp, 'cwd')); fs.writeFileSync( path.join(t.context.tmp, 'cwd/hello.js'), - 'console.log("hello");' + 'console.log("hello");', ); await cpy(['hello.js'], 'destination', { - cwd: path.join(t.context.tmp, 'cwd') + cwd: path.join(t.context.tmp, 'cwd'), }); t.is( read(t.context.tmp, 'cwd/hello.js'), - read(t.context.tmp, 'cwd/destination/hello.js') + read(t.context.tmp, 'cwd/destination/hello.js'), ); }); @@ -129,7 +128,7 @@ test('do not overwrite', async t => { fs.mkdirSync(t.context.tmp); fs.writeFileSync(path.join(t.context.tmp, 'license'), ''); - await cpy(['license'], t.context.tmp, {overwrite: false}); + await t.throwsAsync(cpy(['license'], t.context.tmp, {overwrite: false})); t.is(read(t.context.tmp, 'license'), ''); }); @@ -139,7 +138,7 @@ test('do not keep path structure', async t => { fs.mkdirSync(path.join(t.context.tmp, 'cwd')); fs.writeFileSync( path.join(t.context.tmp, 'cwd/hello.js'), - 'console.log("hello");' + 'console.log("hello");', ); await cpy([path.join(t.context.tmp, 'cwd/hello.js')], t.context.tmp); @@ -153,14 +152,14 @@ test('path structure', async t => { fs.mkdirSync(path.join(t.context.tmp, 'out')); fs.writeFileSync( path.join(t.context.tmp, 'cwd/hello.js'), - 'console.log("hello");' + 'console.log("hello");', ); await cpy([path.join(t.context.tmp, '**')], path.join(t.context.tmp, 'out')); t.is( read(t.context.tmp, 'cwd/hello.js'), - read(t.context.tmp, 'out', 'cwd/hello.js') + read(t.context.tmp, 'out', 'cwd/hello.js'), ); }); @@ -169,25 +168,25 @@ test('rename filenames but not filepaths', async t => { fs.mkdirSync(path.join(t.context.tmp, 'source')); fs.writeFileSync( path.join(t.context.tmp, 'hello.js'), - 'console.log("hello");' + 'console.log("hello");', ); fs.writeFileSync( path.join(t.context.tmp, 'source/hello.js'), - 'console.log("hello");' + 'console.log("hello");', ); await cpy(['hello.js', 'source/hello.js'], 'destination/subdir', { cwd: t.context.tmp, - rename: 'hi.js' + rename: 'hi.js', }); t.is( read(t.context.tmp, 'hello.js'), - read(t.context.tmp, 'destination/subdir/hi.js') + read(t.context.tmp, 'destination/subdir/hi.js'), ); t.is( read(t.context.tmp, 'source/hello.js'), - read(t.context.tmp, 'destination/subdir/source/hi.js') + read(t.context.tmp, 'destination/subdir/source/hi.js'), ); }); @@ -197,21 +196,21 @@ test('rename filenames using a function', async t => { fs.writeFileSync(path.join(t.context.tmp, 'foo.js'), 'console.log("foo");'); fs.writeFileSync( path.join(t.context.tmp, 'source/bar.js'), - 'console.log("bar");' + 'console.log("bar");', ); await cpy(['foo.js', 'source/bar.js'], 'destination/subdir', { cwd: t.context.tmp, - rename: basename => `prefix-${basename}` + rename: basename => `prefix-${basename}`, }); t.is( read(t.context.tmp, 'foo.js'), - read(t.context.tmp, 'destination/subdir/prefix-foo.js') + read(t.context.tmp, 'destination/subdir/prefix-foo.js'), ); t.is( read(t.context.tmp, 'source/bar.js'), - read(t.context.tmp, 'destination/subdir/source/prefix-bar.js') + read(t.context.tmp, 'destination/subdir/source/prefix-bar.js'), ); }); @@ -222,32 +221,34 @@ test('flatten directory tree', async t => { fs.writeFileSync(path.join(t.context.tmp, 'foo.js'), 'console.log("foo");'); fs.writeFileSync( path.join(t.context.tmp, 'source/bar.js'), - 'console.log("bar");' + 'console.log("bar");', ); fs.writeFileSync( path.join(t.context.tmp, 'source/nested/baz.ts'), - 'console.log("baz");' + 'console.log("baz");', ); await cpy('**/*.js', 'destination/subdir', { cwd: t.context.tmp, - flat: true + flat: true, }); t.is( read(t.context.tmp, 'foo.js'), - read(t.context.tmp, 'destination/subdir/foo.js') + read(t.context.tmp, 'destination/subdir/foo.js'), ); t.is( read(t.context.tmp, 'source/bar.js'), - read(t.context.tmp, 'destination/subdir/bar.js') + read(t.context.tmp, 'destination/subdir/bar.js'), ); t.falsy( - fs.existsSync(path.join(t.context.tmp, 'destination/subdir/baz.ts')) + fs.existsSync(path.join(t.context.tmp, 'destination/subdir/baz.ts')), ); }); -test('cp-file errors are CpyErrors', async t => { +// TODO: Enable again when ESM supports mocking. +// eslint-disable-next-line ava/no-skip-test +test.skip('cp-file errors are CpyErrors', async t => { const cpy = cpyMockedError('cp-file'); await t.throwsAsync(cpy('license', t.context.dir), {message: /cp-file/, instanceOf: CpyError}); }); @@ -256,7 +257,7 @@ test('throws on non-existing file', async t => { fs.mkdirSync(t.context.tmp); await t.throwsAsync(cpy(['no-file'], t.context.tmp), { - instanceOf: CpyError + instanceOf: CpyError, }); }); @@ -264,7 +265,7 @@ test('throws on multiple non-existing files', async t => { fs.mkdirSync(t.context.tmp); await t.throwsAsync(cpy(['no-file1', 'no-file2'], t.context.tmp), { - instanceOf: CpyError + instanceOf: CpyError, }); }); @@ -284,7 +285,7 @@ test('junk files are ignored', async t => { await cpy('*', t.context.tmp, { cwd: path.join(t.context.tmp, 'cwd'), - ignoreJunk: true + ignoreJunk: true, }).on('progress', event => { report = event; }); @@ -306,7 +307,7 @@ test('junk files are copied', async t => { await cpy('*', t.context.tmp, { cwd: path.join(t.context.tmp, 'cwd'), - ignoreJunk: false + ignoreJunk: false, }).on('progress', event => { report = event; }); @@ -328,7 +329,7 @@ test('nested junk files are ignored', async t => { await cpy(['cwd/*'], t.context.tmp, { cwd: t.context.tmp, - ignoreJunk: true + ignoreJunk: true, }).on('progress', event => { report = event; }); @@ -348,7 +349,7 @@ test('reports copy progress of single file', async t => { let report; await cpy(['foo'], t.context.tmp, { - cwd: path.join(t.context.tmp, 'cwd') + cwd: path.join(t.context.tmp, 'cwd'), }).on('progress', event => { report = event; }); @@ -369,7 +370,7 @@ test('reports copy progress of multiple files', async t => { let report; await cpy(['foo', 'bar'], t.context.tmp, { - cwd: path.join(t.context.tmp, 'cwd') + cwd: path.join(t.context.tmp, 'cwd'), }).on('progress', event => { report = event; }); @@ -393,7 +394,7 @@ test('reports correct completedSize', async t => { let chunkCount = 0; await cpy(['fatfile'], t.context.tmp, { - cwd: path.join(t.context.tmp, 'cwd') + cwd: path.join(t.context.tmp, 'cwd'), }).on('progress', event => { chunkCount++; report = event; @@ -410,7 +411,7 @@ test('reports correct completedSize', async t => { test('returns the event emitter on early rejection', t => { const rejectedPromise = cpy(null, null); t.is(typeof rejectedPromise.on, 'function'); - rejectedPromise.catch(() => {}); + rejectedPromise.catch(() => {}); // eslint-disable-line promise/prefer-await-to-then }); test('returns destination path', async t => { @@ -420,11 +421,11 @@ test('returns destination path', async t => { fs.writeFileSync(path.join(t.context.tmp, 'cwd/bar'), 'dolor sit amet'); const to = await cpy(['foo', 'bar'], t.context.tmp, { - cwd: path.join(t.context.tmp, 'cwd') + cwd: path.join(t.context.tmp, 'cwd'), }); t.deepEqual(to, [ path.join(t.context.tmp, 'foo'), - path.join(t.context.tmp, 'bar') + path.join(t.context.tmp, 'bar'), ]); });