Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement recursive and flat copy #77

Merged
merged 32 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7965268
feat: implement recursive and flat copy
Idered Aug 30, 2020
eac62d7
chore: simplify path transformation
Idered Aug 30, 2020
addfc13
chore: simplify output path
Idered Aug 30, 2020
336212f
chore: run tests on windows and on latest node
Idered Aug 30, 2020
8d0bafd
chore: add rename option and clean up
Idered Dec 30, 2020
a7244b3
chore: remove test-simple script
Idered Dec 30, 2020
9508e48
chore: add flat test
Idered Dec 30, 2020
f9a1dc8
chore: fix code style
Idered Jun 11, 2021
3c826ec
docs: update and add flat option
Idered Jun 11, 2021
15c42f2
docs: add more examples
Idered Jun 11, 2021
5c8fb8a
fix: bring back relativePath
Idered Jun 11, 2021
42a3c0a
chore: update tests
Idered Jun 11, 2021
43df1f7
Merge branch 'main' into feat/recursive-copy
Idered Jun 11, 2021
debe4c5
fix: tests and cleanup package.json
Idered Jun 12, 2021
6a9b07f
chore: remove redundant tests
Idered Jun 12, 2021
130cf8c
chore: drop node.js 8 support
Idered Jun 12, 2021
15635b1
chore: use yarn in github workflow
Idered Jun 12, 2021
03e5bc5
chore: revert npm to yarn
Idered Jun 12, 2021
efbcbb7
chore: optimize running multiple glob operations
Idered Jun 12, 2021
939a1fb
chore: switch back from node-glob to globby
Idered Jun 13, 2021
2fc581a
chore: drop node.js 10
Idered Jun 13, 2021
2722b28
chore: remove unused dependencies
Idered Jun 13, 2021
3b7fa26
fix: flattening for patterns without magic
Idered Jun 13, 2021
01e3a83
fix: compatibility with globby
Idered Jun 13, 2021
b62ffd2
docs: update glob link
Idered Jun 13, 2021
3238cb3
chore: apply code review fixes
Idered Jul 4, 2021
d243925
style: remove comma
Idered Jul 4, 2021
d2f2691
fix: invalid path usage
Idered Jul 4, 2021
d1cc20c
fix: glob options types
Idered Jul 4, 2021
40a7d5d
chore: update deps
Idered Jul 5, 2021
cddbedc
chore: downgrade xo back to 0.25
Idered Jul 5, 2021
056861e
docs: update "rename" example
Idered Jul 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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