* Recursively copies the contents of one directory to another. * @param {string} src The source directory to copy. * @param {string} dst The directory to copy into. * @param {(RegExp|function(string): boolean)=} opt_exclude An exclusion filter * as either a regex or predicate function. All f
(src, dst, opt_exclude)
| 92 | * directory's path once all files have been copied. |
| 93 | */ |
| 94 | function copyDir(src, dst, opt_exclude) { |
| 95 | let predicate = opt_exclude |
| 96 | if (opt_exclude && typeof opt_exclude !== 'function') { |
| 97 | predicate = function (p) { |
| 98 | return !opt_exclude.test(p) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | if (!fs.existsSync(dst)) { |
| 103 | fs.mkdirSync(dst) |
| 104 | } |
| 105 | |
| 106 | let files = fs.readdirSync(src) |
| 107 | files = files.map(function (file) { |
| 108 | return path.join(src, file) |
| 109 | }) |
| 110 | |
| 111 | if (predicate) { |
| 112 | files = files.filter(/** @type {function(string): boolean} */ (predicate)) |
| 113 | } |
| 114 | |
| 115 | const results = [] |
| 116 | files.forEach(function (file) { |
| 117 | const stats = fs.statSync(file) |
| 118 | const target = path.join(dst, path.basename(file)) |
| 119 | |
| 120 | if (stats.isDirectory()) { |
| 121 | if (!fs.existsSync(target)) { |
| 122 | fs.mkdirSync(target, stats.mode) |
| 123 | } |
| 124 | results.push(copyDir(file, target, predicate)) |
| 125 | } else { |
| 126 | results.push(copy(file, target)) |
| 127 | } |
| 128 | }) |
| 129 | |
| 130 | return Promise.all(results).then(() => dst) |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Tests if a file path exists. |