remove-glob 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2025-present, Ghislain B.
2
+ https://github.com/ghiscoding/remove-glob
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
2
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
3
+ [![Vitest](https://img.shields.io/badge/tested%20with-vitest-fcc72b.svg?logo=vitest)](https://vitest.dev/)
4
+ [![codecov](https://codecov.io/gh/ghiscoding/remove-glob/branch/main/graph/badge.svg)](https://codecov.io/gh/ghiscoding/remove-glob)
5
+ [![npm](https://img.shields.io/npm/v/remove-glob.svg)](https://www.npmjs.com/package/remove-glob)
6
+ [![npm](https://img.shields.io/npm/dy/remove-glob)](https://www.npmjs.com/package/remove-glob)
7
+ [![npm bundle size](https://img.shields.io/bundlephobia/minzip/remove-glob?color=success&label=gzip)](https://bundlephobia.com/result?p=remove-glob)
8
+
9
+ ## remove-glob
10
+
11
+ A tiny cross-platform utility to remove items or directories recursively, it also accepts an optional glob pattern. There's also a CLI for easy, cross-platform usage. It uses 2 small dependencies [tinyglobby](https://www.npmjs.com/package/tinyglobby) for glob support and [cli-nano](https://www.npmjs.com/package/cli-nano) for the CLI.
12
+
13
+ Inspired by [rimraf](https://www.npmjs.com/package/rimraf) and [premove](https://www.npmjs.com/package/premove) but also supports glob pattern to remove files or directories.
14
+
15
+ ### Install
16
+ ```sh
17
+ npm install remove-glob
18
+ ```
19
+
20
+ ### Command Line
21
+
22
+ A `remove` binary is available, it takes 1 or more file/directory paths to be removed or any other options shown below (you can use an optional `--glob` pattern instead of paths).
23
+
24
+ ```
25
+ Usage:
26
+ remove [paths..] [options] Remove all items recursively
27
+
28
+ Positionals:
29
+ paths directory or file paths to remove [string]
30
+
31
+ Options:
32
+ --cwd Directory to resolve from (default ".") [string]
33
+ --dryRun Show which files/dirs would be deleted but without actually re... [boolean]
34
+ --glob Glob pattern to find which files/dirs to remove [string]
35
+ --stat Show the stats of the items being removed [boolean]
36
+ --verbose If true, it will log each file or directory being removed [boolean]
37
+
38
+ Default options:
39
+ -h, --help Show help [boolean]
40
+ -v, --version Show version number [boolean]
41
+ ```
42
+
43
+ Remove files or directories. Note: on Windows globs must be **double quoted**, everybody else can quote however they please.
44
+
45
+ ```sh
46
+ # remove "foo" and "bar" via `npx`
47
+ $ npx remove foo bar
48
+
49
+ # or remove using glob pattern
50
+ $ npx remove --glob \"dist/**/*.js\"
51
+
52
+ # install globally, use whenever
53
+ $ npm install remove-glob -g
54
+ $ remove foo bar
55
+ $ remove --glob \"dist/**/*.{js,map}\"
56
+ ```
57
+
58
+ ### Usage
59
+
60
+ ```ts
61
+ import { resolve } from 'node:path';
62
+ import { removeSync } from 'remove-glob';
63
+
64
+ try {
65
+ // remove via paths
66
+ removeSync({ paths: './foobar' });
67
+ removeSync({ paths: ['./foo/file1.txt', './foo/file2.txt'] });
68
+
69
+ // or remove via glob pattern
70
+ removeSync({ glob: 'foo/**/*.txt' })
71
+ } catch (err) {
72
+ //
73
+ }
74
+
75
+ // Using `cwd` option
76
+ const dir = resolve('./foo/bar');
77
+ await removeSync({ paths: ['hello.txt'], cwd: dir });
78
+ ```
79
+
80
+ ### JavaScript API
81
+
82
+ ```js
83
+ import { removeSync } from 'remove-glob';
84
+
85
+ removeSync(opt, callback);
86
+ ```
87
+
88
+ The first argument is an object holding any of the options shown below. The last argument is an optional callback function which is executed (when defined) after all files are removed.
89
+
90
+ ```js
91
+ {
92
+ cwd: string, // directory to resolve your `filepath` from, defaults to `process.cwd()`
93
+ dryRun: bool, // show what would be copied, without actually copying anything
94
+ paths: string | string[], // filepath(s) to remove – may be a file or a directory.
95
+ glob: string, // glob pattern to find which files/directories to remove
96
+ stats: bool // show some statistics after execution (time + file count)
97
+ verbose: bool, // print more information to console when executing the removal
98
+ }
99
+ ```
100
+
101
+ > [!WARNING]
102
+ > The first argument is necessary and it **must** include a `paths` or a `glob` (but it cannot include both options together).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { parseArgs } from 'cli-nano';
6
+ import { removeSync } from './index.js';
7
+ function readPackage() {
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const pkgPath = resolve(__dirname, '../package.json');
10
+ const pkg = readFileSync(pkgPath, 'utf8');
11
+ return JSON.parse(pkg);
12
+ }
13
+ function handleError(err) {
14
+ if (err) {
15
+ console.error(err);
16
+ process.exit(1);
17
+ }
18
+ else {
19
+ process.exit(0);
20
+ }
21
+ }
22
+ try {
23
+ const results = parseArgs({
24
+ command: {
25
+ name: 'remove',
26
+ description: 'Remove all items recursively',
27
+ positionals: [
28
+ {
29
+ name: 'paths',
30
+ description: 'directory or file paths to remove',
31
+ type: 'string',
32
+ variadic: true,
33
+ required: false,
34
+ },
35
+ ],
36
+ },
37
+ options: {
38
+ cwd: {
39
+ type: 'string',
40
+ description: 'Directory to resolve from (default ".")',
41
+ },
42
+ dryRun: {
43
+ type: 'boolean',
44
+ default: false,
45
+ description: 'Show which files/dirs would be deleted but without actually removing them',
46
+ },
47
+ glob: {
48
+ type: 'string',
49
+ description: 'Glob pattern to find which files/dirs to remove',
50
+ },
51
+ stat: {
52
+ type: 'boolean',
53
+ default: false,
54
+ description: 'Show the stats of the items being removed',
55
+ },
56
+ verbose: {
57
+ type: 'boolean',
58
+ default: false,
59
+ description: 'If true, it will log each file or directory being removed',
60
+ },
61
+ },
62
+ version: readPackage().version,
63
+ });
64
+ // execute remove function
65
+ removeSync(results, err => handleError(err));
66
+ }
67
+ catch (err) {
68
+ handleError(err);
69
+ }
70
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,SAAS,WAAW;IAClB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,CAAC;IACH,MAAM,OAAO,GAAG,SAAS,CAAC;QACxB,OAAO,EAAE;YACP,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,8BAA8B;YAC3C,WAAW,EAAE;gBACX;oBACE,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,mCAAmC;oBAChD,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,IAAI;oBACd,QAAQ,EAAE,KAAK;iBAChB;aACF;SACF;QACD,OAAO,EAAE;YACP,GAAG,EAAE;gBACH,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,yCAAyC;aACvD;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK;gBACd,WAAW,EAAE,2EAA2E;aACzF;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,iDAAiD;aAC/D;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK;gBACd,WAAW,EAAE,2CAA2C;aACzD;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK;gBACd,WAAW,EAAE,2DAA2D;aACzE;SACF;QACD,OAAO,EAAE,WAAW,EAAE,CAAC,OAAO;KAC/B,CAAC,CAAC;IAEH,0BAA0B;IAC1B,UAAU,CAAC,OAAwB,EAAE,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,WAAW,CAAC,GAAY,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { RemoveOptions } from './interfaces.js';
2
+ /**
3
+ * Remove the files or directories, the item(s) can be provided via positional arguments or via a `--glob` pattern.
4
+ * @param {RemoveOptions} options - CLI options
5
+ * @param {(e?: Error) => void} callback - optional callback that will be executed after remove is finished or when an error occurs
6
+ */
7
+ export declare function removeSync(opts?: RemoveOptions, callback?: (e?: Error) => void): false | undefined;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWrD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,GAAE,aAAkB,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,qBAoElF"}
package/dist/index.js ADDED
@@ -0,0 +1,80 @@
1
+ import { existsSync, readdirSync, rmSync, statSync, unlinkSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { globSync } from 'tinyglobby';
4
+ /** Helper to throw or callback with error */
5
+ function throwOrCallback(err, cb) {
6
+ if (typeof cb === 'function') {
7
+ cb(err);
8
+ }
9
+ else {
10
+ throw err;
11
+ }
12
+ }
13
+ /**
14
+ * Remove the files or directories, the item(s) can be provided via positional arguments or via a `--glob` pattern.
15
+ * @param {RemoveOptions} options - CLI options
16
+ * @param {(e?: Error) => void} callback - optional callback that will be executed after remove is finished or when an error occurs
17
+ */
18
+ export function removeSync(opts = {}, callback) {
19
+ const cb = callback || opts.callback;
20
+ let paths = opts.paths || [];
21
+ if (!paths.length && !opts.glob) {
22
+ throwOrCallback(new Error('Please make sure to provide file paths via command arguments or via `--glob` pattern, i.e.: "remove dir" or "remove --glob dir/**/*.js"'), cb);
23
+ return;
24
+ }
25
+ if (paths.length && opts.glob) {
26
+ throwOrCallback(new Error('Providing both `--paths` and `--glob` pattern are not supported, you must provide only one of these options.'), cb);
27
+ return;
28
+ }
29
+ let pathExists = false;
30
+ if (!Array.isArray(paths)) {
31
+ paths = paths.length ? [paths] : [];
32
+ }
33
+ const requiresCwdChange = !!(paths.length && opts.cwd);
34
+ if (!paths.length) {
35
+ paths = globSync([opts.glob], { cwd: opts.cwd, dot: true, onlyFiles: false, absolute: true });
36
+ }
37
+ opts.stat && console.time('Duration');
38
+ opts.dryRun && console.log('=== dry-run ===');
39
+ paths.forEach(path => {
40
+ // do we need to resolve file/dir from a different cwd?
41
+ if (requiresCwdChange) {
42
+ path = resolve(opts.cwd || '.', path);
43
+ }
44
+ if (existsSync(path)) {
45
+ if (statSync(path).isDirectory()) {
46
+ // directories
47
+ if (opts.dryRun) {
48
+ console.log(`would remove directory: ${path}`);
49
+ }
50
+ else {
51
+ opts.verbose && console.log(`removing directory: ${path}`);
52
+ readdirSync(path).forEach(name => {
53
+ removeSync({ paths: join(path, name) }); // recursively remove content
54
+ });
55
+ rmSync(path, { recursive: true, force: true });
56
+ }
57
+ }
58
+ else {
59
+ // files
60
+ if (opts.dryRun) {
61
+ console.log(`would remove file: ${path}`);
62
+ }
63
+ else {
64
+ opts.verbose && console.log(`removing file: ${path}`);
65
+ unlinkSync(path);
66
+ }
67
+ }
68
+ pathExists = true;
69
+ }
70
+ });
71
+ if (opts.stat || opts.verbose) {
72
+ console.log(`Removed: ${paths.length} items`);
73
+ console.timeEnd('Duration');
74
+ }
75
+ opts.dryRun && console.log('=== dry-run ===');
76
+ if (typeof cb === 'function')
77
+ cb();
78
+ return pathExists;
79
+ }
80
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface RemoveOptions {
2
+ /** Callback to run when the execution finished or an error occured */
3
+ callback?: (e?: Error) => void;
4
+ /**
5
+ * The directory to resolve your `filepath` from.
6
+ * Defaults to the `process.cwd()` – aka, the directory that your command is run within.
7
+ */
8
+ cwd?: string;
9
+ /** Show which files would be deleted but without actually deleting them */
10
+ dryRun?: boolean;
11
+ /** Glob pattern to find which files/directories to remove */
12
+ glob?: string;
13
+ /**
14
+ * The filepath(s) to remove – may be a file or a directory.
15
+ * An initial existence check is made for this filepath.
16
+ * Important: This value is resolved to a full path.
17
+ * Please be aware of how and from where the Node.js file system is resolving your path!
18
+ */
19
+ paths?: string | string[];
20
+ /** Show the stats of the removed items */
21
+ stat?: boolean;
22
+ /** Print more information to console */
23
+ verbose?: boolean;
24
+ }
25
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +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,CAAC;IAEd;;;;;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;CACnB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "remove-glob",
3
+ "version": "0.2.0",
4
+ "description": "A tiny utility to remove items or directories recursively, also supports glob",
5
+ "bin": {
6
+ "remove": "dist/cli.js"
7
+ },
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./package.json": "./package.json"
17
+ },
18
+ "module": "./dist/index.js",
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "files": [
23
+ "/dist",
24
+ "/src"
25
+ ],
26
+ "license": "MIT",
27
+ "author": "Ghislain B.",
28
+ "homepage": "https://github.com/ghiscoding/remove-glob",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/ghiscoding/remove-glob.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/ghiscoding/remove-glob/issues"
35
+ },
36
+ "dependencies": {
37
+ "cli-nano": "^1.0.2",
38
+ "tinyglobby": "^0.2.14"
39
+ },
40
+ "engines": {
41
+ "node": ">=20.0.0"
42
+ }
43
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { parseArgs } from 'cli-nano';
7
+
8
+ import { removeSync } from './index.js';
9
+ import type { RemoveOptions } from './interfaces.js';
10
+
11
+ function readPackage() {
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const pkgPath = resolve(__dirname, '../package.json');
14
+ const pkg = readFileSync(pkgPath, 'utf8');
15
+ return JSON.parse(pkg);
16
+ }
17
+
18
+ function handleError(err?: Error) {
19
+ if (err) {
20
+ console.error(err);
21
+ process.exit(1);
22
+ } else {
23
+ process.exit(0);
24
+ }
25
+ }
26
+
27
+ try {
28
+ const results = parseArgs({
29
+ command: {
30
+ name: 'remove',
31
+ description: 'Remove all items recursively',
32
+ positionals: [
33
+ {
34
+ name: 'paths',
35
+ description: 'directory or file paths to remove',
36
+ type: 'string',
37
+ variadic: true,
38
+ required: false,
39
+ },
40
+ ],
41
+ },
42
+ options: {
43
+ cwd: {
44
+ type: 'string',
45
+ description: 'Directory to resolve from (default ".")',
46
+ },
47
+ dryRun: {
48
+ type: 'boolean',
49
+ default: false,
50
+ description: 'Show which files/dirs would be deleted but without actually removing them',
51
+ },
52
+ glob: {
53
+ type: 'string',
54
+ description: 'Glob pattern to find which files/dirs to remove',
55
+ },
56
+ stat: {
57
+ type: 'boolean',
58
+ default: false,
59
+ description: 'Show the stats of the items being removed',
60
+ },
61
+ verbose: {
62
+ type: 'boolean',
63
+ default: false,
64
+ description: 'If true, it will log each file or directory being removed',
65
+ },
66
+ },
67
+ version: readPackage().version,
68
+ });
69
+
70
+ // execute remove function
71
+ removeSync(results as RemoveOptions, err => handleError(err));
72
+ } catch (err) {
73
+ handleError(err as Error);
74
+ }
package/src/index.ts ADDED
@@ -0,0 +1,89 @@
1
+ import { existsSync, readdirSync, rmSync, statSync, unlinkSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { globSync } from 'tinyglobby';
4
+
5
+ import type { RemoveOptions } from './interfaces.js';
6
+
7
+ /** Helper to throw or callback with error */
8
+ function throwOrCallback(err?: Error, cb?: (e?: Error) => void) {
9
+ if (typeof cb === 'function') {
10
+ cb(err);
11
+ } else {
12
+ throw err;
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Remove the files or directories, the item(s) can be provided via positional arguments or via a `--glob` pattern.
18
+ * @param {RemoveOptions} options - CLI options
19
+ * @param {(e?: Error) => void} callback - optional callback that will be executed after remove is finished or when an error occurs
20
+ */
21
+ export function removeSync(opts: RemoveOptions = {}, callback?: (e?: Error) => void) {
22
+ const cb = callback || opts.callback;
23
+ let paths = opts.paths || [];
24
+ if (!paths.length && !opts.glob) {
25
+ throwOrCallback(
26
+ new Error(
27
+ 'Please make sure to provide file paths via command arguments or via `--glob` pattern, i.e.: "remove dir" or "remove --glob dir/**/*.js"',
28
+ ),
29
+ cb,
30
+ );
31
+ return;
32
+ }
33
+ if (paths.length && opts.glob) {
34
+ throwOrCallback(
35
+ new Error('Providing both `--paths` and `--glob` pattern are not supported, you must provide only one of these options.'),
36
+ cb,
37
+ );
38
+ return;
39
+ }
40
+ let pathExists = false;
41
+ if (!Array.isArray(paths)) {
42
+ paths = paths.length ? [paths] : [];
43
+ }
44
+ const requiresCwdChange = !!(paths.length && opts.cwd);
45
+ if (!paths.length) {
46
+ paths = globSync([opts.glob!], { cwd: opts.cwd, dot: true, onlyFiles: false, absolute: true });
47
+ }
48
+ opts.stat && console.time('Duration');
49
+ opts.dryRun && console.log('=== dry-run ===');
50
+
51
+ paths.forEach(path => {
52
+ // do we need to resolve file/dir from a different cwd?
53
+ if (requiresCwdChange) {
54
+ path = resolve(opts.cwd || '.', path);
55
+ }
56
+
57
+ if (existsSync(path)) {
58
+ if (statSync(path).isDirectory()) {
59
+ // directories
60
+ if (opts.dryRun) {
61
+ console.log(`would remove directory: ${path}`);
62
+ } else {
63
+ opts.verbose && console.log(`removing directory: ${path}`);
64
+ readdirSync(path).forEach(name => {
65
+ removeSync({ paths: join(path, name) }); // recursively remove content
66
+ });
67
+ rmSync(path, { recursive: true, force: true });
68
+ }
69
+ } else {
70
+ // files
71
+ if (opts.dryRun) {
72
+ console.log(`would remove file: ${path}`);
73
+ } else {
74
+ opts.verbose && console.log(`removing file: ${path}`);
75
+ unlinkSync(path);
76
+ }
77
+ }
78
+ pathExists = true;
79
+ }
80
+ });
81
+
82
+ if (opts.stat || opts.verbose) {
83
+ console.log(`Removed: ${paths.length} items`);
84
+ console.timeEnd('Duration');
85
+ }
86
+ opts.dryRun && console.log('=== dry-run ===');
87
+ if (typeof cb === 'function') cb();
88
+ return pathExists;
89
+ }
@@ -0,0 +1,30 @@
1
+ export interface RemoveOptions {
2
+ /** Callback to run when the execution finished or an error occured */
3
+ callback?: (e?: Error) => void;
4
+
5
+ /**
6
+ * The directory to resolve your `filepath` from.
7
+ * Defaults to the `process.cwd()` – aka, the directory that your command is run within.
8
+ */
9
+ cwd?: string;
10
+
11
+ /** Show which files would be deleted but without actually deleting them */
12
+ dryRun?: boolean;
13
+
14
+ /** Glob pattern to find which files/directories to remove */
15
+ glob?: string;
16
+
17
+ /**
18
+ * The filepath(s) to remove – may be a file or a directory.
19
+ * An initial existence check is made for this filepath.
20
+ * Important: This value is resolved to a full path.
21
+ * Please be aware of how and from where the Node.js file system is resolving your path!
22
+ */
23
+ paths?: string | string[];
24
+
25
+ /** Show the stats of the removed items */
26
+ stat?: boolean;
27
+
28
+ /** Print more information to console */
29
+ verbose?: boolean;
30
+ }