remove-glob 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -27
- package/dist/cli.js +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -15
- package/dist/interfaces.d.ts +4 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +62 -0
- package/package.json +1 -1
- package/src/cli.ts +11 -5
- package/src/index.ts +4 -17
- package/src/interfaces.ts +5 -0
- package/src/utils.ts +67 -0
package/README.md
CHANGED
|
@@ -29,25 +29,46 @@ A `remove` binary is available, it takes an optional path argument (zero or mult
|
|
|
29
29
|
> The `paths` and `glob` arguments are both optionals, but you **must** provide at least 1 of them.
|
|
30
30
|
> However, please note that providing both of them simultaneously is not supported and will throw an error (choose the option that is best suited to your use case).
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
> When using the `--glob` option, dotfiles and dot-directories (e.g. `.env`, `.gitignore`, `.config/`) are included by default. If you want to exclude them, you can adjust your glob pattern (e.g. use `**/[!.]*.js` or add an `!**/.*` pattern).
|
|
32
|
+
When using the `--glob` option, dotfiles and dot-directories (e.g. `.env`, `.gitignore`, `.config/`) are included by default. If you want to exclude them, you can adjust your glob pattern (e.g. use `**/[!.]*.js` or add an `!**/.*` pattern).
|
|
34
33
|
|
|
35
34
|
```
|
|
36
35
|
Usage:
|
|
37
|
-
remove [paths..] [options]
|
|
36
|
+
remove [paths..] [options] → Remove all items recursively
|
|
38
37
|
|
|
39
38
|
Arguments:
|
|
40
|
-
paths
|
|
39
|
+
paths Directory or file paths to remove [string..]
|
|
41
40
|
|
|
42
41
|
Options:
|
|
43
|
-
--cwd Directory to resolve from (default ".")
|
|
44
|
-
-d, --
|
|
45
|
-
-g, --glob Glob pattern(s) to find which files/dirs to remove
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
42
|
+
--cwd Directory to resolve from (default ".") [string]
|
|
43
|
+
-d, --dry-run Show which files/dirs would be deleted but without actually removing them [boolean]
|
|
44
|
+
-g, --glob Glob pattern(s) to find which files/dirs to remove [array]
|
|
45
|
+
-a, --all Include dotfiles (files starting with a dot) when matching glob patterns [boolean]
|
|
46
|
+
-s, --stat Show the stats of the items being removed [boolean]
|
|
47
|
+
-V, --verbose If true, it will log each file or directory being removed [boolean]
|
|
48
|
+
-e, --exclude Glob pattern(s) to exclude from deletion (overrides the default patterns) [array]
|
|
49
|
+
-h, --help Show help [boolean]
|
|
50
|
+
-v, --version Show version number [boolean]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
When `exclude` glob pattern(s) are provided, it will override the default exclude of: [`"**/.git/**", "**/.git", "**/node_modules/**", "**/node_modules"`].
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
The `--all`/`-a` option includes dotfiles (files starting with a dot) in glob matches. By default, dotfiles are excluded unless explicitly matched or this option is used.
|
|
57
|
+
|
|
58
|
+
#### Negation Patterns
|
|
59
|
+
You can use negation patterns (starting with `!`) in glob arrays to exclude files from removal:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
$ npx remove --glob "src/**/*.js" --glob "!src/**/*.test.js"
|
|
63
|
+
# This will remove all .js files except those ending with .test.js
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Brace Expansion
|
|
67
|
+
Brace expansion is supported in glob patterns:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
$ npx remove --glob "src/*.{js,ts}"
|
|
71
|
+
# This will match both .js and .ts files in src/
|
|
51
72
|
```
|
|
52
73
|
|
|
53
74
|
Remove files or directories. Note: on Windows globs must be **double quoted**, everybody else can quote however they please.
|
|
@@ -66,16 +87,14 @@ $ remove foo bar
|
|
|
66
87
|
$ remove --glob \"dist/**/*.{js,map}\"
|
|
67
88
|
```
|
|
68
89
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
> $ npx remove --glob "**/*" --exclude "**/.git/**" --exclude "**/.git"
|
|
78
|
-
> ```
|
|
90
|
+
When using the `--glob` option, it will skip `.git/` and `node_modules/` directories by default (using the default `--exclude` patterns). If you want to allow deletion of these directories, you can override the default by providing your own `--exclude` option (including an empty array to disable exclusion):
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
# Remove everything, including .git and node_modules
|
|
94
|
+
$ npx remove --glob "**/*" --exclude ""
|
|
95
|
+
# Or exclude only .git, but allow node_modules to be deleted
|
|
96
|
+
$ npx remove --glob "**/*" --exclude "**/.git/**" --exclude "**/.git"
|
|
97
|
+
```
|
|
79
98
|
|
|
80
99
|
### Usage
|
|
81
100
|
|
|
@@ -108,17 +127,27 @@ The first argument is an object holding any of the options shown below. The last
|
|
|
108
127
|
```js
|
|
109
128
|
{
|
|
110
129
|
cwd: string; // directory to resolve your `filepath` from, defaults to `process.cwd()`
|
|
111
|
-
dryRun: boolean; // show what would be
|
|
130
|
+
dryRun: boolean; // show what would be removed, without actually removing anything
|
|
112
131
|
paths: string | string[]; // filepath(s) to remove – may be a file or a directory.
|
|
113
|
-
glob: string;
|
|
114
|
-
exclude: string[];
|
|
115
|
-
|
|
132
|
+
glob: string | string[]; // glob pattern(s) to find which files/directories to remove
|
|
133
|
+
exclude: string | string[]; // glob pattern(s) to exclude from deletion
|
|
134
|
+
all: boolean; // include dotfiles (files starting with a dot) in glob matches
|
|
135
|
+
stat: boolean; // show some statistics after execution (time + file count)
|
|
116
136
|
verbose: boolean; // print more information to console when executing the removal
|
|
117
137
|
}
|
|
118
138
|
```
|
|
119
139
|
|
|
140
|
+
|
|
120
141
|
> [!NOTE]
|
|
121
|
-
> The first argument is required and it **must** include either a `paths` or a `glob`, but it cannot include both options simultaneously.
|
|
142
|
+
> The first argument is required and it **must** include either a `paths` or a `glob`, but it cannot include both options simultaneously. A
|
|
143
|
+
|
|
144
|
+
When an `exclude` glob pattern is provided, it will override the default exclusion of: [`"**/.git/**", "**/.git", "**/node_modules/**", "**/node_modules"`].
|
|
145
|
+
|
|
146
|
+
#### Advanced glob usage
|
|
147
|
+
|
|
148
|
+
- **Negation**: Use `!pattern` in a glob array to exclude files from removal.
|
|
149
|
+
- **Brace expansion**: Use `{a,b}` to match multiple alternatives in a single pattern.
|
|
150
|
+
- **Dotfiles**: Use `--all`/`-a` to include dotfiles in glob matches.
|
|
122
151
|
|
|
123
152
|
### Used by
|
|
124
153
|
|
package/dist/cli.js
CHANGED
|
@@ -25,11 +25,11 @@ try {
|
|
|
25
25
|
name: 'remove',
|
|
26
26
|
describe: 'Remove all items recursively',
|
|
27
27
|
examples: [
|
|
28
|
-
{ cmd: '$0 foo bar', describe: '
|
|
29
|
-
{ cmd: '$0 --glob="dist/**/*.js"', describe: '
|
|
28
|
+
{ cmd: '$0 foo bar', describe: 'Remove "foo" and "bar" folders' },
|
|
29
|
+
{ cmd: '$0 --glob="dist/**/*.js"', describe: 'Remove all files from from "dist" folder with ".js" extension' },
|
|
30
30
|
{
|
|
31
31
|
cmd: '$0 --glob="dist/**/*.js" --glob="packages/*/tsconfig.tsbuildinfo"',
|
|
32
|
-
describe: '
|
|
32
|
+
describe: 'Remove all files from from "dist" folder with ".js" extension and "tsconfig.tsbuildinfo" file from every "packages" folders',
|
|
33
33
|
},
|
|
34
34
|
],
|
|
35
35
|
positionals: [
|
|
@@ -58,6 +58,12 @@ try {
|
|
|
58
58
|
type: 'array',
|
|
59
59
|
describe: 'Glob pattern(s) to find which files/dirs to remove',
|
|
60
60
|
},
|
|
61
|
+
all: {
|
|
62
|
+
alias: 'a',
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
default: false,
|
|
65
|
+
describe: 'Include dotfiles (files starting with a dot) when matching glob patterns',
|
|
66
|
+
},
|
|
61
67
|
stat: {
|
|
62
68
|
alias: 's',
|
|
63
69
|
default: false,
|
|
@@ -71,8 +77,9 @@ try {
|
|
|
71
77
|
describe: 'If true, it will log each file or directory being removed',
|
|
72
78
|
},
|
|
73
79
|
exclude: {
|
|
80
|
+
alias: 'e',
|
|
74
81
|
type: 'array',
|
|
75
|
-
describe: 'Glob pattern(s) to exclude from deletion (overrides the default
|
|
82
|
+
describe: 'Glob pattern(s) to exclude from deletion (overrides the default patterns)',
|
|
76
83
|
},
|
|
77
84
|
},
|
|
78
85
|
version: readPackage().version,
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,GAAE,aAAkB,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,qBAoElF"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync,
|
|
1
|
+
import { existsSync, rmSync, statSync, unlinkSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import { throwOrCallback } from './utils.js';
|
|
3
|
+
import { throwOrCallback, getMatchedFiles } from './utils.js';
|
|
4
4
|
/**
|
|
5
5
|
* Remove the files or directories, the item(s) can be provided via positional arguments or via a `--glob` pattern.
|
|
6
6
|
* @param {RemoveOptions} options - CLI options
|
|
@@ -31,18 +31,7 @@ export function removeSync(opts = {}, callback) {
|
|
|
31
31
|
// paths is always an array now
|
|
32
32
|
const requiresCwdChange = !!(paths.length && opts.cwd);
|
|
33
33
|
if (!paths.length && opts.glob) {
|
|
34
|
-
|
|
35
|
-
const defaultExclude = ['**/.git/**', '**/.git', '**/node_modules/**', '**/node_modules'];
|
|
36
|
-
const globOptions = { cwd: opts.cwd, withFileTypes: false };
|
|
37
|
-
globOptions.exclude = Array.isArray(opts.exclude) ? opts.exclude : defaultExclude;
|
|
38
|
-
const globResult = globSync(opts.glob, globOptions);
|
|
39
|
-
// We reassign 'paths' here to hold the final list of files matched by glob,
|
|
40
|
-
// after filtering for strings and resolving to absolute paths if needed.
|
|
41
|
-
paths =
|
|
42
|
-
Array.isArray(globResult) && globResult.length > 0 ? globResult.filter((v) => typeof v === 'string') : [];
|
|
43
|
-
if (opts.cwd) {
|
|
44
|
-
paths = paths.map(p => resolve(opts.cwd, p));
|
|
45
|
-
}
|
|
34
|
+
paths = getMatchedFiles(opts.glob, { cwd: opts.cwd, exclude: opts.exclude, all: opts.all });
|
|
46
35
|
}
|
|
47
36
|
if (opts.stat || opts.verbose) {
|
|
48
37
|
console.time('Duration');
|
|
@@ -56,7 +45,7 @@ export function removeSync(opts = {}, callback) {
|
|
|
56
45
|
}
|
|
57
46
|
if (existsSync(path)) {
|
|
58
47
|
const isDir = statSync(path).isDirectory();
|
|
59
|
-
const pathLog = `${isDir ? 'directory' : 'file'}: ${path}`;
|
|
48
|
+
const pathLog = `${isDir ? 'directory recursively' : 'file'}: ${path}`;
|
|
60
49
|
if (opts.dryRun) {
|
|
61
50
|
console.log(`would remove ${pathLog}`);
|
|
62
51
|
}
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -26,5 +26,9 @@ export interface RemoveOptions {
|
|
|
26
26
|
* To disable exclusion and allow deleting everything, pass an empty array ([]).
|
|
27
27
|
*/
|
|
28
28
|
exclude?: string | string[];
|
|
29
|
+
/**
|
|
30
|
+
* If true, include dotfiles (files starting with a dot) when matching glob patterns.
|
|
31
|
+
*/
|
|
32
|
+
all?: boolean;
|
|
29
33
|
}
|
|
30
34
|
//# sourceMappingURL=interfaces.d.ts.map
|
package/dist/interfaces.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAE/B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEzB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAE/B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEzB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE5B;;OAEG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;CACf"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to get all matched files from glob patterns, supporting dotfile logic via opts.all
|
|
3
|
+
*/
|
|
4
|
+
export declare function getMatchedFiles(glob: string | string[], opts: {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
exclude?: string | string[];
|
|
7
|
+
all?: boolean;
|
|
8
|
+
}): string[];
|
|
1
9
|
/** Helper to throw or callback with error */
|
|
2
10
|
export declare function throwOrCallback(err?: Error, cb?: (e?: Error) => void): void;
|
|
3
11
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CA0DrI;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,QAMpE"}
|
package/dist/utils.js
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
+
import { globSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Helper to get all matched files from glob patterns, supporting dotfile logic via opts.all
|
|
5
|
+
*/
|
|
6
|
+
export function getMatchedFiles(glob, opts) {
|
|
7
|
+
const defaultExclude = ['**/.git/**', '**/.git', '**/node_modules/**', '**/node_modules'];
|
|
8
|
+
const globOptions = { cwd: opts.cwd, withFileTypes: false, exclude: defaultExclude };
|
|
9
|
+
if (Array.isArray(opts.exclude)) {
|
|
10
|
+
globOptions.exclude = opts.exclude;
|
|
11
|
+
}
|
|
12
|
+
else if (typeof opts.exclude === 'string') {
|
|
13
|
+
globOptions.exclude = [opts.exclude];
|
|
14
|
+
}
|
|
15
|
+
// Separate positive and negated patterns
|
|
16
|
+
const patterns = Array.isArray(glob) ? glob : [glob];
|
|
17
|
+
const positivePatterns = [];
|
|
18
|
+
const negatedPatterns = [];
|
|
19
|
+
for (const pat of patterns) {
|
|
20
|
+
if (typeof pat === 'string' && pat.startsWith('!')) {
|
|
21
|
+
negatedPatterns.push(pat.slice(1));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
positivePatterns.push(pat);
|
|
25
|
+
// Dotfile logic for positive patterns
|
|
26
|
+
if (opts.all && typeof pat === 'string' && pat.includes('*') && !pat.startsWith('.')) {
|
|
27
|
+
const dotPattern = pat.replace(/(\*)/g, '.*');
|
|
28
|
+
if (dotPattern !== pat) {
|
|
29
|
+
positivePatterns.push(dotPattern);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Collect all files matching positive patterns
|
|
35
|
+
const matchedSet = new Set();
|
|
36
|
+
for (const pattern of positivePatterns) {
|
|
37
|
+
const globResult = globSync(pattern, globOptions);
|
|
38
|
+
if (Array.isArray(globResult) && globResult.length > 0) {
|
|
39
|
+
for (const v of globResult) {
|
|
40
|
+
if (typeof v === 'string') {
|
|
41
|
+
matchedSet.add(v);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Remove files matching any negated pattern
|
|
47
|
+
for (const pattern of negatedPatterns) {
|
|
48
|
+
const globResult = globSync(pattern, globOptions);
|
|
49
|
+
if (Array.isArray(globResult) && globResult.length > 0) {
|
|
50
|
+
for (const v of globResult) {
|
|
51
|
+
if (typeof v === 'string') {
|
|
52
|
+
matchedSet.delete(v);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let paths = Array.from(matchedSet);
|
|
58
|
+
if (opts.cwd) {
|
|
59
|
+
paths = paths.map(p => resolve(opts.cwd, p));
|
|
60
|
+
}
|
|
61
|
+
return paths;
|
|
62
|
+
}
|
|
1
63
|
/** Helper to throw or callback with error */
|
|
2
64
|
export function throwOrCallback(err, cb) {
|
|
3
65
|
if (typeof cb === 'function') {
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -29,12 +29,12 @@ try {
|
|
|
29
29
|
name: 'remove',
|
|
30
30
|
describe: 'Remove all items recursively',
|
|
31
31
|
examples: [
|
|
32
|
-
{ cmd: '$0 foo bar', describe: '
|
|
33
|
-
{ cmd: '$0 --glob="dist/**/*.js"', describe: '
|
|
32
|
+
{ cmd: '$0 foo bar', describe: 'Remove "foo" and "bar" folders' },
|
|
33
|
+
{ cmd: '$0 --glob="dist/**/*.js"', describe: 'Remove all files from from "dist" folder with ".js" extension' },
|
|
34
34
|
{
|
|
35
35
|
cmd: '$0 --glob="dist/**/*.js" --glob="packages/*/tsconfig.tsbuildinfo"',
|
|
36
36
|
describe:
|
|
37
|
-
'
|
|
37
|
+
'Remove all files from from "dist" folder with ".js" extension and "tsconfig.tsbuildinfo" file from every "packages" folders',
|
|
38
38
|
},
|
|
39
39
|
],
|
|
40
40
|
positionals: [
|
|
@@ -63,6 +63,12 @@ try {
|
|
|
63
63
|
type: 'array',
|
|
64
64
|
describe: 'Glob pattern(s) to find which files/dirs to remove',
|
|
65
65
|
},
|
|
66
|
+
all: {
|
|
67
|
+
alias: 'a',
|
|
68
|
+
type: 'boolean',
|
|
69
|
+
default: false,
|
|
70
|
+
describe: 'Include dotfiles (files starting with a dot) when matching glob patterns',
|
|
71
|
+
},
|
|
66
72
|
stat: {
|
|
67
73
|
alias: 's',
|
|
68
74
|
default: false,
|
|
@@ -76,9 +82,9 @@ try {
|
|
|
76
82
|
describe: 'If true, it will log each file or directory being removed',
|
|
77
83
|
},
|
|
78
84
|
exclude: {
|
|
85
|
+
alias: 'e',
|
|
79
86
|
type: 'array',
|
|
80
|
-
describe:
|
|
81
|
-
'Glob pattern(s) to exclude from deletion (overrides the default: ["**/.git/**", "**/.git", "**/node_modules/**", "**/node_modules"])',
|
|
87
|
+
describe: 'Glob pattern(s) to exclude from deletion (overrides the default patterns)',
|
|
82
88
|
},
|
|
83
89
|
},
|
|
84
90
|
version: readPackage().version,
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { existsSync, globSync, rmSync, statSync, unlinkSync } from 'node:fs';
|
|
1
|
+
import { existsSync, rmSync, statSync, unlinkSync } from 'node:fs';
|
|
3
2
|
import { resolve } from 'node:path';
|
|
4
3
|
import type { RemoveOptions } from './interfaces.js';
|
|
5
|
-
import { throwOrCallback } from './utils.js';
|
|
4
|
+
import { throwOrCallback, getMatchedFiles } from './utils.js';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Remove the files or directories, the item(s) can be provided via positional arguments or via a `--glob` pattern.
|
|
@@ -35,19 +34,7 @@ export function removeSync(opts: RemoveOptions = {}, callback?: (e?: Error) => v
|
|
|
35
34
|
// paths is always an array now
|
|
36
35
|
const requiresCwdChange = !!(paths.length && opts.cwd);
|
|
37
36
|
if (!paths.length && opts.glob) {
|
|
38
|
-
|
|
39
|
-
const defaultExclude = ['**/.git/**', '**/.git', '**/node_modules/**', '**/node_modules'];
|
|
40
|
-
const globOptions: GlobOptions = { cwd: opts.cwd, withFileTypes: false };
|
|
41
|
-
globOptions.exclude = Array.isArray(opts.exclude) ? opts.exclude : defaultExclude;
|
|
42
|
-
|
|
43
|
-
const globResult = globSync(opts.glob, globOptions);
|
|
44
|
-
// We reassign 'paths' here to hold the final list of files matched by glob,
|
|
45
|
-
// after filtering for strings and resolving to absolute paths if needed.
|
|
46
|
-
paths =
|
|
47
|
-
Array.isArray(globResult) && globResult.length > 0 ? (globResult as unknown[]).filter((v): v is string => typeof v === 'string') : [];
|
|
48
|
-
if (opts.cwd) {
|
|
49
|
-
paths = paths.map(p => resolve(opts.cwd as string, p));
|
|
50
|
-
}
|
|
37
|
+
paths = getMatchedFiles(opts.glob, { cwd: opts.cwd, exclude: opts.exclude, all: opts.all });
|
|
51
38
|
}
|
|
52
39
|
|
|
53
40
|
if (opts.stat || opts.verbose) {
|
|
@@ -64,7 +51,7 @@ export function removeSync(opts: RemoveOptions = {}, callback?: (e?: Error) => v
|
|
|
64
51
|
|
|
65
52
|
if (existsSync(path)) {
|
|
66
53
|
const isDir = statSync(path).isDirectory();
|
|
67
|
-
const pathLog = `${isDir ? 'directory' : 'file'}: ${path}`;
|
|
54
|
+
const pathLog = `${isDir ? 'directory recursively' : 'file'}: ${path}`;
|
|
68
55
|
|
|
69
56
|
if (opts.dryRun) {
|
|
70
57
|
console.log(`would remove ${pathLog}`);
|
package/src/interfaces.ts
CHANGED
|
@@ -33,4 +33,9 @@ export interface RemoveOptions {
|
|
|
33
33
|
* To disable exclusion and allow deleting everything, pass an empty array ([]).
|
|
34
34
|
*/
|
|
35
35
|
exclude?: string | string[];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* If true, include dotfiles (files starting with a dot) when matching glob patterns.
|
|
39
|
+
*/
|
|
40
|
+
all?: boolean;
|
|
36
41
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,70 @@
|
|
|
1
|
+
import type { GlobOptions } from 'node:fs';
|
|
2
|
+
import { globSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Helper to get all matched files from glob patterns, supporting dotfile logic via opts.all
|
|
7
|
+
*/
|
|
8
|
+
export function getMatchedFiles(glob: string | string[], opts: { cwd?: string; exclude?: string | string[]; all?: boolean }): string[] {
|
|
9
|
+
const defaultExclude = ['**/.git/**', '**/.git', '**/node_modules/**', '**/node_modules'];
|
|
10
|
+
const globOptions: GlobOptions = { cwd: opts.cwd, withFileTypes: false, exclude: defaultExclude };
|
|
11
|
+
if (Array.isArray(opts.exclude)) {
|
|
12
|
+
globOptions.exclude = opts.exclude;
|
|
13
|
+
} else if (typeof opts.exclude === 'string') {
|
|
14
|
+
globOptions.exclude = [opts.exclude];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Separate positive and negated patterns
|
|
18
|
+
const patterns = Array.isArray(glob) ? glob : [glob];
|
|
19
|
+
const positivePatterns: string[] = [];
|
|
20
|
+
const negatedPatterns: string[] = [];
|
|
21
|
+
for (const pat of patterns) {
|
|
22
|
+
if (typeof pat === 'string' && pat.startsWith('!')) {
|
|
23
|
+
negatedPatterns.push(pat.slice(1));
|
|
24
|
+
} else {
|
|
25
|
+
positivePatterns.push(pat);
|
|
26
|
+
// Dotfile logic for positive patterns
|
|
27
|
+
if (opts.all && typeof pat === 'string' && pat.includes('*') && !pat.startsWith('.')) {
|
|
28
|
+
const dotPattern = pat.replace(/(\*)/g, '.*');
|
|
29
|
+
if (dotPattern !== pat) {
|
|
30
|
+
positivePatterns.push(dotPattern);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Collect all files matching positive patterns
|
|
37
|
+
const matchedSet = new Set<string>();
|
|
38
|
+
for (const pattern of positivePatterns) {
|
|
39
|
+
const globResult = globSync(pattern, globOptions);
|
|
40
|
+
if (Array.isArray(globResult) && globResult.length > 0) {
|
|
41
|
+
for (const v of globResult) {
|
|
42
|
+
if (typeof v === 'string') {
|
|
43
|
+
matchedSet.add(v);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Remove files matching any negated pattern
|
|
50
|
+
for (const pattern of negatedPatterns) {
|
|
51
|
+
const globResult = globSync(pattern, globOptions);
|
|
52
|
+
if (Array.isArray(globResult) && globResult.length > 0) {
|
|
53
|
+
for (const v of globResult) {
|
|
54
|
+
if (typeof v === 'string') {
|
|
55
|
+
matchedSet.delete(v);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let paths = Array.from(matchedSet);
|
|
62
|
+
if (opts.cwd) {
|
|
63
|
+
paths = paths.map(p => resolve(opts.cwd as string, p));
|
|
64
|
+
}
|
|
65
|
+
return paths;
|
|
66
|
+
}
|
|
67
|
+
|
|
1
68
|
/** Helper to throw or callback with error */
|
|
2
69
|
export function throwOrCallback(err?: Error, cb?: (e?: Error) => void) {
|
|
3
70
|
if (typeof cb === 'function') {
|