summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/recursive-copy
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/@11ty/recursive-copy')
-rw-r--r--node_modules/@11ty/recursive-copy/README.md201
-rw-r--r--node_modules/@11ty/recursive-copy/index.d.ts117
-rw-r--r--node_modules/@11ty/recursive-copy/index.js3
-rw-r--r--node_modules/@11ty/recursive-copy/lib/copy.js436
-rw-r--r--node_modules/@11ty/recursive-copy/package.json72
5 files changed, 829 insertions, 0 deletions
diff --git a/node_modules/@11ty/recursive-copy/README.md b/node_modules/@11ty/recursive-copy/README.md
new file mode 100644
index 0000000..d053022
--- /dev/null
+++ b/node_modules/@11ty/recursive-copy/README.md
@@ -0,0 +1,201 @@
+# `@11ty/recursive-copy`
+
+A temporary fork of [`timkendrick/recursive-copy`](https://github.com/timkendrick/recursive-copy) to satisfy https://github.com/11ty/eleventy/issues/3299 as Eleventy slowly [moves to use Node native API `fs.cp`](https://github.com/11ty/eleventy/issues/3360).
+
+- v4.x requires Node 18+
+- v3.x requires Node 0.10+
+- v2.x requires Node 0.10+
+
+> Simple, flexible file copy utility
+
+## Features
+
+- Recursively copy whole directory hierarchies
+- Choose which files are copied by passing a filter function, regular expression or glob
+- Rename files dynamically, including changing the output path
+- Transform file contents using streams
+- Choose whether to overwrite existing files
+- Choose whether to copy system files
+- Filters out [junk](https://www.npmjs.com/package/junk) files by default
+- Emits start, finish and error events for each file that is processed
+- Optional promise-based interface
+
+## Examples
+
+#### Node-style callback interface
+
+```javascript
+var copy = require('@11ty/recursive-copy');
+
+copy('src', 'dest', function(error, results) {
+ if (error) {
+ console.error('Copy failed: ' + error);
+ } else {
+ console.info('Copied ' + results.length + ' files');
+ }
+});
+```
+
+#### Promise interface
+
+```javascript
+var copy = require('@11ty/recursive-copy');
+
+copy('src', 'dest')
+ .then(function(results) {
+ console.info('Copied ' + results.length + ' files');
+ })
+ .catch(function(error) {
+ console.error('Copy failed: ' + error);
+ });
+```
+
+#### ES2015+ usage
+
+```javascript
+import copy from '@11ty/recursive-copy';
+
+try {
+ const results = await copy('src', 'dest');
+ console.info('Copied ' + results.length + ' files');
+} catch (error) {
+ console.error('Copy failed: ' + error);
+}
+```
+
+#### Advanced options
+
+```javascript
+var copy = require('@11ty/recursive-copy');
+
+var path = require('path');
+var through = require('through2');
+
+var options = {
+ overwrite: true,
+ expand: true,
+ dot: true,
+ junk: true,
+ filter: [
+ '**/*',
+ '!.htpasswd'
+ ],
+ rename: function(filePath) {
+ return filePath + '.orig';
+ },
+ transform: function(src, dest, stats) {
+ if (path.extname(src) !== '.txt') { return null; }
+ return through(function(chunk, enc, done) {
+ var output = chunk.toString().toUpperCase();
+ done(null, output);
+ });
+ }
+};
+
+copy('src', 'dest', options)
+ .on(copy.events.COPY_FILE_START, function(copyOperation) {
+ console.info('Copying file ' + copyOperation.src + '...');
+ })
+ .on(copy.events.COPY_FILE_COMPLETE, function(copyOperation) {
+ console.info('Copied to ' + copyOperation.dest);
+ })
+ .on(copy.events.ERROR, function(error, copyOperation) {
+ console.error('Unable to copy ' + copyOperation.dest);
+ })
+ .then(function(results) {
+ console.info(results.length + ' file(s) copied');
+ })
+ .catch(function(error) {
+ return console.error('Copy failed: ' + error);
+ });
+```
+
+
+## Usage
+
+### `copy(src, dest, [options], [callback])`
+
+Recursively copy files and folders from `src` to `dest`
+
+#### Arguments:
+
+| Name | Type | Required | Default | Description |
+| ---- | ---- | -------- | ------- | ----------- |
+| `src` | `string` | Yes | N/A | Source file/folder path |
+| `dest` | `string` | Yes | N/A | Destination file/folder path |
+| `options.overwrite` | `boolean` | No | `false` | Whether to overwrite destination files |
+| `options.expand` | `boolean` | No | `false` | Whether to expand symbolic links |
+| `options.dot` | `boolean` | No | `false` | Whether to copy files beginning with a `.` |
+| `options.junk` | `boolean` | No | `false` | Whether to copy OS junk files (e.g. `.DS_Store`, `Thumbs.db`) |
+| `options.filter` | `function`, `RegExp`, `string`, `array` | No | `null` | Filter function / regular expression / glob that determines which files to copy (uses [maximatch](https://www.npmjs.com/package/maximatch)) |
+| `options.rename` | `function` | No | `null` | Function that maps source paths to destination paths |
+| `options.transform` | `function` | No | `null` | Function that returns a transform stream used to modify file contents |
+| `options.results` | `boolean` | No | `true` | Whether to return an array of copy results |
+| `options.concurrency` | `number` | No | `255` | Maximum number of simultaneous copy operations |
+| `options.debug` | `boolean` | No | `false` | Whether to log debug information |
+| `callback` | `function` | No | `null` | Callback, invoked on success/failure |
+
+
+#### Returns:
+
+`Promise<Array>` Promise, fulfilled with array of copy results:
+
+```json
+[
+ {
+ "src": "/path/to/src",
+ "dest": "/path/to/dest",
+ "stats": <Stats>
+ },
+ {
+ "src": "/path/to/src/file.txt",
+ "dest": "/path/to/dest/file.txt",
+ "stats": <Stats>
+ },
+ {
+ "src": "/path/to/src/subfolder",
+ "dest": "/path/to/dest/subfolder",
+ "stats": <Stats>
+ },
+ {
+ "src": "/path/to/src/subfolder/nested.txt",
+ "dest": "/path/to/dest/subfolder/nested.txt",
+ "stats": <Stats>
+ }
+]
+```
+
+## Events
+
+The value returned by the `copy` function implements the `EventEmitter` interface, and emits the following events:
+
+| Event | Handler signature |
+| ----- | ----------------- |
+| `copy.events.ERROR` | `function(error, ErrorInfo)` |
+| `copy.events.COMPLETE` | `function(Array<CopyOperation>)` |
+| `copy.events.CREATE_DIRECTORY_START` | `function(CopyOperation)` |
+| `copy.events.CREATE_DIRECTORY_ERROR` | `function(error, CopyOperation)` |
+| `copy.events.CREATE_DIRECTORY_COMPLETE` | `function(CopyOperation)` |
+| `copy.events.CREATE_SYMLINK_START` | `function(CopyOperation)` |
+| `copy.events.CREATE_SYMLINK_ERROR` | `function(error, CopyOperation)` |
+| `copy.events.CREATE_SYMLINK_COMPLETE` | `function(CopyOperation)` |
+| `copy.events.COPY_FILE_START` | `function(CopyOperation)` |
+| `copy.events.COPY_FILE_ERROR` | `function(error, CopyOperation)` |
+| `copy.events.COPY_FILE_COMPLETE` | `function(CopyOperation)` |
+
+...where the types referred to in the handler signature are as follows:
+
+### `ErrorInfo`
+
+| Property | Type | Description |
+| -------- | ---- | ----------- |
+| `src` | `string` | Source path of the file/folder/symlink that failed to copy |
+| `dest` | `string` | Destination path of the file/folder/symlink that failed to copy |
+
+### `CopyOperation`
+
+| Property | Type | Description |
+| -------- | ---- | ----------- |
+| `src` | `string` | Source path of the relevant file/folder/symlink |
+| `dest` | `string` | Destination path of the relevant file/folder/symlink |
+| `stats ` | `fs.Stats` | Stats for the relevant file/folder/symlink |
diff --git a/node_modules/@11ty/recursive-copy/index.d.ts b/node_modules/@11ty/recursive-copy/index.d.ts
new file mode 100644
index 0000000..9a8770e
--- /dev/null
+++ b/node_modules/@11ty/recursive-copy/index.d.ts
@@ -0,0 +1,117 @@
+import { Stats } from 'fs';
+import { Stream } from 'stream';
+
+interface Options {
+ /**
+ * Whether to overwrite destination files.
+ */
+ overwrite?: boolean;
+ /**
+ * Whether to expand symbolic links.
+ */
+ expand?: boolean;
+ /**
+ * Whether to copy files beginning with a `.`
+ */
+ dot?: boolean;
+ /**
+ * Whether to copy OS junk files (e.g. `.DS_Store`, `Thumbs.db`).
+ */
+ junk?: boolean;
+ /**
+ * Filter function / regular expression / glob that determines which files to copy (uses maximatch).
+ */
+ filter?: string | string[] | RegExp | ((path: string) => boolean);
+ /**
+ * Function that maps source paths to destination paths.
+ */
+ rename?: (path: string) => string;
+ /**
+ * Function that returns a transform stream used to modify file contents.
+ */
+ transform?: (src: string, dest: string, stats: Stats) => Stream | null | undefined;
+ /**
+ * Whether to return an array of copy results.
+ *
+ * Defaults to true.
+ */
+ results?: boolean;
+ /**
+ * Maximum number of simultaneous copy operations.
+ *
+ * Defaults to 255.
+ */
+ concurrency?: number;
+ /**
+ * Whether to log debug information.
+ */
+ debug?: boolean;
+}
+
+interface CopyFn {
+ (
+ source: string,
+ dest: string,
+ options?: Options,
+ ): WithCopyEvents<Promise<Array<CopyOperation>>>;
+ (
+ source: string,
+ dest: string,
+ callback: (error: Error | null, results?: Array<CopyOperation>) => void,
+ ): WithCopyEvents<{}>;
+ events: {
+ ERROR: CopyEventType.ERROR;
+ COMPLETE: CopyEventType.COMPLETE;
+ CREATE_DIRECTORY_START: CopyEventType.CREATE_DIRECTORY_START;
+ CREATE_DIRECTORY_ERROR: CopyEventType.CREATE_DIRECTORY_ERROR;
+ CREATE_DIRECTORY_COMPLETE: CopyEventType.CREATE_DIRECTORY_COMPLETE;
+ CREATE_SYMLINK_START: CopyEventType.CREATE_SYMLINK_START;
+ CREATE_SYMLINK_ERROR: CopyEventType.CREATE_SYMLINK_ERROR;
+ CREATE_SYMLINK_COMPLETE: CopyEventType.CREATE_SYMLINK_COMPLETE;
+ COPY_FILE_START: CopyEventType.COPY_FILE_START;
+ COPY_FILE_ERROR: CopyEventType.COPY_FILE_ERROR;
+ COPY_FILE_COMPLETE: CopyEventType.COPY_FILE_COMPLETE;
+ };
+}
+
+declare const copy: CopyFn;
+export default copy;
+
+export interface CopyErrorInfo {
+ src: string;
+ dest: string;
+}
+
+export interface CopyOperation {
+ src: string;
+ dest: string;
+ stats: Stats;
+}
+
+type WithCopyEvents<T> = T & {
+ on(event: CopyEventType.ERROR, callback: (error: Error, info: CopyErrorInfo) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.COMPLETE, callback: (info: Array<CopyOperation>) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.CREATE_DIRECTORY_START, callback: (info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.CREATE_DIRECTORY_ERROR, callback: (error: Error, info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.CREATE_DIRECTORY_COMPLETE, callback: (info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.CREATE_SYMLINK_START, callback: (info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.CREATE_SYMLINK_ERROR, callback: (error: Error, info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.CREATE_SYMLINK_COMPLETE, callback: (info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.COPY_FILE_START, callback: (info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.COPY_FILE_ERROR, callback: (error: Error, info: CopyOperation) => void): WithCopyEvents<T>;
+ on(event: CopyEventType.COPY_FILE_COMPLETE, callback: (info: CopyOperation) => void): WithCopyEvents<T>;
+}
+
+export enum CopyEventType {
+ ERROR = 'error',
+ COMPLETE = 'complete',
+ CREATE_DIRECTORY_START = 'createDirectoryStart',
+ CREATE_DIRECTORY_ERROR = 'createDirectoryError',
+ CREATE_DIRECTORY_COMPLETE = 'createDirectoryComplete',
+ CREATE_SYMLINK_START = 'createSymlinkStart',
+ CREATE_SYMLINK_ERROR = 'createSymlinkError',
+ CREATE_SYMLINK_COMPLETE = 'createSymlinkComplete',
+ COPY_FILE_START = 'copyFileStart',
+ COPY_FILE_ERROR = 'copyFileError',
+ COPY_FILE_COMPLETE = 'copyFileComplete',
+}
diff --git a/node_modules/@11ty/recursive-copy/index.js b/node_modules/@11ty/recursive-copy/index.js
new file mode 100644
index 0000000..ea56967
--- /dev/null
+++ b/node_modules/@11ty/recursive-copy/index.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./lib/copy');
diff --git a/node_modules/@11ty/recursive-copy/lib/copy.js b/node_modules/@11ty/recursive-copy/lib/copy.js
new file mode 100644
index 0000000..8e0b12e
--- /dev/null
+++ b/node_modules/@11ty/recursive-copy/lib/copy.js
@@ -0,0 +1,436 @@
+'use strict';
+
+var Promise = global.Promise;
+var path = require('node:path');
+var EventEmitter = require('node:events').EventEmitter;
+var fs = require('fs');
+var junk = require('junk');
+var errno = require('errno');
+var maximatch = require('maximatch');
+var slash = require('slash');
+
+var CopyError = errno.custom.createError('CopyError');
+
+var EVENT_ERROR = 'error';
+var EVENT_COMPLETE = 'complete';
+var EVENT_CREATE_DIRECTORY_START = 'createDirectoryStart';
+var EVENT_CREATE_DIRECTORY_ERROR = 'createDirectoryError';
+var EVENT_CREATE_DIRECTORY_COMPLETE = 'createDirectoryComplete';
+var EVENT_CREATE_SYMLINK_START = 'createSymlinkStart';
+var EVENT_CREATE_SYMLINK_ERROR = 'createSymlinkError';
+var EVENT_CREATE_SYMLINK_COMPLETE = 'createSymlinkComplete';
+var EVENT_COPY_FILE_START = 'copyFileStart';
+var EVENT_COPY_FILE_ERROR = 'copyFileError';
+var EVENT_COPY_FILE_COMPLETE = 'copyFileComplete';
+
+var mkdirp = fs.promises.mkdir;
+var mkdir = mkdirp;
+var stat = fs.promises.stat;
+var lstat = fs.promises.lstat;
+var readlink = fs.promises.readlink
+var symlink = fs.promises.symlink;
+var readdir = fs.promises.readdir;
+
+module.exports = function(src, dest, options, callback) {
+ if ((arguments.length === 3) && (typeof options === 'function')) {
+ callback = options;
+ options = undefined;
+ }
+ options = options || {};
+
+ var parentDirectory = path.dirname(dest);
+ var shouldExpandSymlinks = Boolean(options.expand);
+
+ var emitter;
+ var hasFinished = false;
+ if (options.debug) { log('Ensuring output directory exists…'); }
+ var promise = ensureDirectoryExists(parentDirectory)
+ .then(function() {
+ if (options.debug) { log('Fetching source paths…'); }
+ return getFilePaths(src, shouldExpandSymlinks)
+ })
+ .then(function(filePaths) {
+ if (options.debug) { log('Filtering source paths…'); }
+ // must filter out explicit copy attempts for dot files (not post-relative path)
+ filePaths = getFilteredPaths(filePaths, undefined, {
+ dot: options.dot,
+ junk: options.junk
+ });
+ var relativePaths = filePaths.map(function(filePath) {
+ return path.relative(src, filePath);
+ });
+ var filteredPaths = getFilteredPaths(relativePaths, options.filter, {
+ dot: options.dot,
+ junk: options.junk
+ });
+ return filteredPaths.map(function(relativePath) {
+ var inputPath = relativePath;
+ var outputPath = options.rename ? options.rename(inputPath) : inputPath;
+ return {
+ src: path.join(src, inputPath),
+ dest: path.join(dest, outputPath)
+ };
+ })
+ })
+ .then(function(operations) {
+ if (options.debug) { log('Copying files…'); }
+ var hasFinishedGetter = function() { return hasFinished; };
+ var emitEvent = function() { emitter.emit.apply(emitter, arguments); };
+ return batch(operations, function(operation) {
+ return copy(operation.src, operation.dest, hasFinishedGetter, emitEvent, options);
+ }, {
+ results: options.results !== false,
+ concurrency: options.concurrency || 255
+ });
+ })
+ .catch(function(error) {
+ if (options.debug) { log('Copy failed'); }
+ if (error instanceof CopyError) {
+ emitter.emit(EVENT_ERROR, error.error, error.data);
+ throw error.error;
+ } else {
+ throw error;
+ }
+ })
+ .then(function(results) {
+ if (options.debug) { log('Copy complete'); }
+ emitter.emit(EVENT_COMPLETE, results);
+ return results;
+ })
+ .then(function(results) {
+ hasFinished = true;
+ return results;
+ })
+ .catch(function(error) {
+ hasFinished = true;
+ throw error;
+ });
+
+ if (typeof callback === 'function') {
+ promise.then(function(results) {
+ callback(null, results);
+ })
+ .catch(function(error) {
+ callback(error);
+ });
+ emitter = new EventEmitter();
+ } else {
+ emitter = withEventEmitter(promise);
+ }
+
+ return emitter;
+};
+
+function batch(inputs, iteratee, options) {
+ var results = options.results ? [] : undefined;
+ if (inputs.length === 0) { return Promise.resolve(results); }
+ return new Promise(function(resolve, reject) {
+ var currentIndex = -1;
+ var activeWorkers = 0;
+ while (currentIndex < Math.min(inputs.length, options.concurrency) - 1) {
+ startWorker(inputs[++currentIndex]);
+ }
+
+ function startWorker(input) {
+ ++activeWorkers;
+ iteratee(input).then(function(result) {
+ --activeWorkers;
+ if (results) { results.push(result); }
+ if (currentIndex < inputs.length - 1) {
+ startWorker(inputs[++currentIndex]);
+ } else if (activeWorkers === 0) {
+ resolve(results);
+ }
+ }).catch(reject);
+ }
+ });
+}
+
+function getFilePaths(src, shouldExpandSymlinks) {
+ return (shouldExpandSymlinks ? stat : lstat)(src)
+ .then(function(stats) {
+ if (stats.isDirectory()) {
+ return getFileListing(src, shouldExpandSymlinks)
+ .then(function(filenames) {
+ return [src].concat(filenames);
+ });
+ } else {
+ return [src];
+ }
+ });
+}
+
+function getFilteredPaths(paths, filter, options) {
+ var useDotFilter = !options.dot;
+ var useJunkFilter = !options.junk;
+ if (!filter && !useDotFilter && !useJunkFilter) { return paths; }
+ return paths.filter(function(path) {
+ if(!useDotFilter || dotFilter(path)) {
+ if(!useJunkFilter || junkFilter(path)) {
+ if(!filter) {
+ return true;
+ }
+ var p = slash(path);
+ // filter might be a string, array, function
+ var m = maximatch(p, filter, options);
+ if(m.length > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ });
+}
+
+function dotFilter(relativePath) {
+ var filename = path.basename(relativePath);
+ return filename.charAt(0) !== '.';
+}
+
+function junkFilter(relativePath) {
+ var filename = path.basename(relativePath);
+ return !junk.is(filename);
+}
+
+function ensureDirectoryExists(path) {
+ return mkdir(path, { recursive: true });
+}
+
+function getFileListing(srcPath, shouldExpandSymlinks) {
+ return readdir(srcPath)
+ .then(function(filenames) {
+ return Promise.all(
+ filenames.map(function(filename) {
+ var filePath = path.join(srcPath, filename);
+ return (shouldExpandSymlinks ? stat : lstat)(filePath)
+ .then(function(stats) {
+ if (stats.isDirectory()) {
+ return getFileListing(filePath, shouldExpandSymlinks)
+ .then(function(childPaths) {
+ return [filePath].concat(childPaths);
+ });
+ } else {
+ return [filePath];
+ }
+ });
+ })
+ )
+ .then(function mergeArrays(arrays) {
+ return Array.prototype.concat.apply([], arrays);
+ });
+ });
+}
+
+function copy(srcPath, destPath, hasFinished, emitEvent, options) {
+ if (options.debug) { log('Preparing to copy ' + srcPath + '…'); }
+ return prepareForCopy(srcPath, destPath, options)
+ .then(function(stats) {
+ if (options.debug) { log('Copying ' + srcPath + '…'); }
+ var copyFunction = getCopyFunction(stats, hasFinished, emitEvent);
+ return copyFunction(srcPath, destPath, stats, options);
+ })
+ .catch(function(error) {
+ if (error instanceof CopyError) {
+ throw error;
+ }
+ var copyError = new CopyError(error.message);
+ copyError.error = error;
+ copyError.data = {
+ src: srcPath,
+ dest: destPath
+ };
+ throw copyError;
+ })
+ .then(function(result) {
+ if (options.debug) { log('Copied ' + srcPath); }
+ return result;
+ });
+}
+
+function prepareForCopy(srcPath, destPath, options) {
+ var shouldExpandSymlinks = Boolean(options.expand);
+ var shouldOverwriteExistingFiles = Boolean(options.overwrite);
+ return (shouldExpandSymlinks ? stat : lstat)(srcPath)
+ .then(function(stats) {
+ return ensureDestinationIsWritable(destPath, stats, shouldOverwriteExistingFiles)
+ .then(function() {
+ return stats;
+ });
+ });
+}
+
+function ensureDestinationIsWritable(destPath, srcStats, shouldOverwriteExistingFiles) {
+ return lstat(destPath)
+ .catch(function(error) {
+ var shouldIgnoreError = error.code === 'ENOENT';
+ if (shouldIgnoreError) { return null; }
+ throw error;
+ })
+ .then(function(destStats) {
+ var destExists = Boolean(destStats);
+ if (!destExists) { return true; }
+
+ var isMergePossible = srcStats.isDirectory() && destStats.isDirectory();
+ if (isMergePossible) { return true; }
+
+ if (shouldOverwriteExistingFiles) {
+ return fs.promises.rm(destPath, { recursive: true, force: true }).then(function(paths) {
+ return true;
+ });
+ } else {
+ throw fsError('EEXIST', destPath);
+ }
+ });
+}
+
+function getCopyFunction(stats, hasFinished, emitEvent) {
+ if (stats.isDirectory()) {
+ return createCopyFunction(copyDirectory, stats, hasFinished, emitEvent, {
+ startEvent: EVENT_CREATE_DIRECTORY_START,
+ completeEvent: EVENT_CREATE_DIRECTORY_COMPLETE,
+ errorEvent: EVENT_CREATE_DIRECTORY_ERROR
+ });
+ } else if (stats.isSymbolicLink()) {
+ return createCopyFunction(copySymlink, stats, hasFinished, emitEvent, {
+ startEvent: EVENT_CREATE_SYMLINK_START,
+ completeEvent: EVENT_CREATE_SYMLINK_COMPLETE,
+ errorEvent: EVENT_CREATE_SYMLINK_ERROR
+ });
+ } else {
+ return createCopyFunction(copyFile, stats, hasFinished, emitEvent, {
+ startEvent: EVENT_COPY_FILE_START,
+ completeEvent: EVENT_COPY_FILE_COMPLETE,
+ errorEvent: EVENT_COPY_FILE_ERROR
+ });
+ }
+}
+
+function createCopyFunction(fn, stats, hasFinished, emitEvent, events) {
+ var startEvent = events.startEvent;
+ var completeEvent = events.completeEvent;
+ var errorEvent = events.errorEvent;
+ return function(srcPath, destPath, stats, options) {
+ // Multiple chains of promises are fired in parallel,
+ // so when one fails we need to prevent any future
+ // copy operations
+ if (hasFinished()) { return Promise.reject(); }
+ var metadata = {
+ src: srcPath,
+ dest: destPath,
+ stats: stats
+ };
+ emitEvent(startEvent, metadata);
+ var parentDirectory = path.dirname(destPath);
+ return ensureDirectoryExists(parentDirectory)
+ .then(function() {
+ return fn(srcPath, destPath, stats, options);
+ })
+ .then(function() {
+ if (!hasFinished()) { emitEvent(completeEvent, metadata); }
+ return metadata;
+ })
+ .catch(function(error) {
+ if (!hasFinished()) { emitEvent(errorEvent, error, metadata); }
+ throw error;
+ });
+ };
+}
+
+function copyFile(srcPath, destPath, stats, options) {
+ return new Promise(function(resolve, reject) {
+ var hasFinished = false;
+
+ var read = fs.createReadStream(srcPath);
+ read.on('error', handleCopyFailed);
+
+ var write = fs.createWriteStream(destPath, {
+ flags: 'w',
+ mode: stats.mode
+ });
+ write.on('error', handleCopyFailed);
+ write.on('finish', function() {
+ fs.utimes(destPath, stats.atime, stats.mtime, function() {
+ hasFinished = true;
+ resolve();
+ });
+ });
+
+ var transformStream = null;
+ if (options.transform) {
+ transformStream = options.transform(srcPath, destPath, stats);
+ if (transformStream) {
+ transformStream.on('error', handleCopyFailed);
+ read.pipe(transformStream).pipe(write);
+ } else {
+ read.pipe(write);
+ }
+ } else {
+ read.pipe(write);
+ }
+
+
+ function handleCopyFailed(error) {
+ if (hasFinished) { return; }
+ hasFinished = true;
+ if (typeof read.close === 'function') {
+ read.close();
+ }
+ if (typeof write.close === 'function') {
+ write.close();
+ }
+ return reject(error);
+ }
+ });
+}
+
+function copySymlink(srcPath, destPath, stats, options) {
+ return readlink(srcPath)
+ .then(function(link) {
+ return symlink(link, destPath);
+ });
+}
+
+function copyDirectory(srcPath, destPath, stats, options) {
+ return mkdir(destPath, { recusirve: true })
+ .catch(function(error) {
+ var shouldIgnoreError = error.code === 'EEXIST';
+ if (shouldIgnoreError) { return; }
+ throw error;
+ });
+}
+
+function fsError(code, path) {
+ var errorType = errno.code[code];
+ var message = errorType.code + ', ' + errorType.description + ' ' + path;
+ var error = new Error(message);
+ error.errno = errorType.errno;
+ error.code = errorType.code;
+ error.path = path;
+ return error;
+}
+
+function log(message) {
+ process.stdout.write(message + '\n');
+}
+
+function withEventEmitter(target) {
+ for (var key in EventEmitter.prototype) {
+ target[key] = EventEmitter.prototype[key];
+ }
+ EventEmitter.call(target);
+ return target;
+}
+
+module.exports.events = {
+ ERROR: EVENT_ERROR,
+ COMPLETE: EVENT_COMPLETE,
+ CREATE_DIRECTORY_START: EVENT_CREATE_DIRECTORY_START,
+ CREATE_DIRECTORY_ERROR: EVENT_CREATE_DIRECTORY_ERROR,
+ CREATE_DIRECTORY_COMPLETE: EVENT_CREATE_DIRECTORY_COMPLETE,
+ CREATE_SYMLINK_START: EVENT_CREATE_SYMLINK_START,
+ CREATE_SYMLINK_ERROR: EVENT_CREATE_SYMLINK_ERROR,
+ CREATE_SYMLINK_COMPLETE: EVENT_CREATE_SYMLINK_COMPLETE,
+ COPY_FILE_START: EVENT_COPY_FILE_START,
+ COPY_FILE_ERROR: EVENT_COPY_FILE_ERROR,
+ COPY_FILE_COMPLETE: EVENT_COPY_FILE_COMPLETE
+};
diff --git a/node_modules/@11ty/recursive-copy/package.json b/node_modules/@11ty/recursive-copy/package.json
new file mode 100644
index 0000000..0d7b959
--- /dev/null
+++ b/node_modules/@11ty/recursive-copy/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "@11ty/recursive-copy",
+ "version": "4.0.2",
+ "description": "A fork of `recursive-copy`: Simple, flexible file copy utility",
+ "engines": {
+ "node": ">=18"
+ },
+ "main": "index.js",
+ "types": "index.d.ts",
+ "directories": {
+ "lib": "lib",
+ "test": "test"
+ },
+ "files": [
+ "index.js",
+ "index.d.ts",
+ "lib"
+ ],
+ "scripts": {
+ "test": "npm run test:lint && npm run test:mocha && if-node-version '>=10' npm run test:typings",
+ "test:lint": "if-node-version '>=4' eslint index.js test",
+ "test:mocha": "mocha --reporter spec",
+ "test:typings": "tsd && echo 'TypeScript definitions are valid'",
+ "prepublishOnly": "npm run test"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/11ty/recursive-copy.git"
+ },
+ "keywords": [
+ "copy",
+ "recursive",
+ "file",
+ "directory",
+ "folder",
+ "symlink",
+ "fs",
+ "rename",
+ "filter",
+ "transform",
+ "glob",
+ "regex",
+ "regexp"
+ ],
+ "author": "Tim Kendrick <timkendrick@gmail.com>",
+ "contributors": [
+ "Zach Leatherman <zachleatherman@gmail.com> (https://zachleat.com/)"
+ ],
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/11ty/recursive-copy/issues"
+ },
+ "homepage": "https://github.com/11ty/recursive-copy",
+ "dependencies": {
+ "errno": "^1.0.0",
+ "junk": "^3.1.0",
+ "maximatch": "^0.1.0",
+ "slash": "^3.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^14.18.63",
+ "chai": "^3.5.0",
+ "chai-as-promised": "^5.3.0",
+ "eslint": "^2.13.1",
+ "if-node-version": "^1.1.1",
+ "mocha": "^2.5.3",
+ "read-dir-files": "^0.1.1",
+ "rewire": "^2.5.2",
+ "through2": "^2.0.5",
+ "tsd": "0.31.2"
+ }
+}