Skip to content

Commit

Permalink
Implement recursive and flat copy (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
Idered authored Jul 12, 2021
1 parent 94fff3a commit be263e1
Show file tree
Hide file tree
Showing 8 changed files with 467 additions and 163 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ jobs:
node-version:
- 14
- 12
- 10
- 8
os:
- ubuntu-latest
- macos-latest
Expand Down
64 changes: 64 additions & 0 deletions glob-pattern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict';
const glob = require('globby');
const junk = require('junk');
const path = require('path');
const fs = require('fs');

class GlobPattern {
/**
* @param {string} pattern
* @param {string} destination
* @param {import('.').Options} options
*/
constructor(pattern, destination, options) {
this.path = pattern;
this.originalPath = pattern;
this.destination = destination;
this.options = options;

if (
!glob.hasMagic(pattern) &&
fs.existsSync(pattern) &&
fs.lstatSync(pattern).isDirectory()
) {
this.path = [pattern, '**'].join('/');
}
}

get name() {
return path.basename(this.originalPath);
}

get normalizedPath() {
const segments = this.originalPath.split('/');
const magicIndex = segments.findIndex(item => item ? glob.hasMagic(item) : false);
const normalized = segments.slice(0, magicIndex).join('/');

if (normalized) {
return path.isAbsolute(normalized) ? normalized : path.join(this.options.cwd, normalized);
}

return this.destination;
}

hasMagic() {
return glob.hasMagic(this.options.flat ? this.path : this.originalPath);
}

getMatches() {
let matches = glob.sync(this.path, {
...this.options,
dot: true,
absolute: true,
onlyFiles: true
});

if (this.options.ignoreJunk) {
matches = matches.filter(file => junk.not(path.basename(file)));
}

return matches;
}
}

module.exports = GlobPattern;
66 changes: 45 additions & 21 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {GlobbyOptions} from 'globby';
import {GlobbyOptions as GlobOptions} from 'globby';
import {Options as CpFileOptions} from 'cp-file';

declare namespace cpy {
interface SourceFile {
interface Entry {
/**
Resolved path to the file.
Expand All @@ -11,9 +11,9 @@ declare namespace cpy {
readonly path: string;

/**
Relative path to the file from `cwd`.
Relative path to the file from cwd.
@example 'dir/foo.js' if `cwd` was '/tmp'
@example 'dir/foo.js'
*/
readonly relativePath: string;

Expand All @@ -39,7 +39,7 @@ declare namespace cpy {
readonly extension: string;
}

interface Options extends Readonly<GlobbyOptions>, CpFileOptions {
interface Options extends Readonly<GlobOptions>, CpFileOptions {
/**
Working directory to find source files.
Expand All @@ -48,11 +48,11 @@ declare namespace cpy {
readonly cwd?: string;

/**
Preserve path structure.
Flatten directory tree.
@default false
*/
readonly parents?: boolean;
readonly flat?: boolean;

/**
Filename or function returning a filename used to rename every file in `source`.
Expand All @@ -65,6 +65,9 @@ declare namespace cpy {
await cpy('foo.js', 'destination', {
rename: basename => `prefix-${basename}`
});
await cpy('foo.js', 'destination', {
rename: 'new-name'
});
})();
```
*/
Expand Down Expand Up @@ -102,7 +105,7 @@ declare namespace cpy {
})();
```
*/
readonly filter?: (file: SourceFile) => (boolean | Promise<boolean>);
readonly filter?: (file: Entry) => boolean | Promise<boolean>;
}

interface ProgressData {
Expand Down Expand Up @@ -133,27 +136,48 @@ declare namespace cpy {
handler: (progress: ProgressData) => void
): Promise<string[]>;
}

interface CopyStatus {
written: number;
percent: number;
}
}

/**
Copy files.
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
```
const cpy = require('cpy');
(async () => {
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');
@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).
// Copy node_modules structure but skip all files except any .json files
await cpy('node_modules/**\/*.json', 'destination');
@example
```
import cpy = require('cpy');
// Copy all png files into destination without keeping directory structure
await cpy('**\/*.png', 'destination', {flat: true});
(async () => {
await cpy(['source/*.png', '!source/goat.png'], 'destination');
console.log('Files copied!');
})();
```
console.log('Files copied!');
})();
```
*/
declare function cpy(
source: string | ReadonlyArray<string>,
source: string | readonly string[],
destination: string,
options?: cpy.Options
): Promise<string[]> & cpy.ProgressEmitter;
Expand Down
Loading

0 comments on commit be263e1

Please sign in to comment.