remnem 0.0.0 → 0.1.8
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 +21 -0
- package/README.md +143 -0
- package/bin/remnem.js +213 -0
- package/index.d.ts +68 -0
- package/index.js +591 -0
- package/package.json +82 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Leon Si
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# remnem
|
|
2
|
+
|
|
3
|
+
**r**e**m**ove **n**ode_**m**odules — find every nested `node_modules` in a project (root + all workspaces + any nested ones) and delete them all, as fast as possible.
|
|
4
|
+
|
|
5
|
+
Written in Rust ([napi-rs](https://napi.rs)) with a parallel directory walker and parallel deletion. Uses the **same workspace resolution as [bun](https://bun.sh/docs/install/workspaces) and [pnpm](https://pnpm.io/pnpm-workspace_yaml)** to describe the workspace layout.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ remnem
|
|
9
|
+
root: /Users/you/dev/my-monorepo
|
|
10
|
+
package.json workspace (12 packages)
|
|
11
|
+
found 13 node_modules totalling 2.4 GB:
|
|
12
|
+
318 MB node_modules
|
|
13
|
+
1.1 GB apps/web/node_modules
|
|
14
|
+
...
|
|
15
|
+
permanently delete these 13 directories? [y/N] y
|
|
16
|
+
|
|
17
|
+
deleted: 13/13 node_modules (2.4 GB) in 412ms
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Delete vs. Trash
|
|
21
|
+
|
|
22
|
+
By default `remnem` **permanently deletes** each `node_modules` in parallel —
|
|
23
|
+
space is reclaimed immediately.
|
|
24
|
+
|
|
25
|
+
Pass **`-t` / `--trash`** to move them to the OS trash instead (Finder Trash on
|
|
26
|
+
macOS, the freedesktop trash on Linux, the Recycle Bin on Windows). On the same
|
|
27
|
+
volume that is a directory *rename* — O(1), effectively instant no matter how
|
|
28
|
+
many files the tree holds — and recoverable from the trash. The disk space is
|
|
29
|
+
reclaimed when you empty it. A `node_modules` on a *different* volume (rare)
|
|
30
|
+
can't be renamed instantly, so those fall back to a direct delete.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install -g remnem
|
|
36
|
+
# or: bun install -g remnem
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The right prebuilt native binary is pulled in automatically for your platform
|
|
40
|
+
via `optionalDependencies`. Supported: **macOS** (arm64, x64), **Linux** (arm64
|
|
41
|
+
& x64, glibc & musl), **Windows** (arm64, x64).
|
|
42
|
+
|
|
43
|
+
Then from any repo root:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
remnem
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### From source
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
bun install
|
|
53
|
+
bun run build # builds the native addon for your host → remnem.<platform>.node
|
|
54
|
+
bun link # makes `remnem` available on your PATH
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## What it clears
|
|
58
|
+
|
|
59
|
+
**Every `node_modules` directory** under the given root — the root's own, every
|
|
60
|
+
workspace package's, and any stray nested ones — leaving all your source and
|
|
61
|
+
`package.json` files untouched. The walker never descends *into* a
|
|
62
|
+
`node_modules` (the whole subtree is going to be removed anyway), so it stays
|
|
63
|
+
fast even on trees with hundreds of thousands of files.
|
|
64
|
+
|
|
65
|
+
Workspace resolution (reading `package.json#workspaces` for bun/npm/yarn, or
|
|
66
|
+
`pnpm-workspace.yaml#packages` for pnpm) is used to **report** the workspace
|
|
67
|
+
layout; clearing always targets every nested `node_modules`, not only workspace
|
|
68
|
+
packages.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
remnem [path] [options]
|
|
74
|
+
|
|
75
|
+
Arguments:
|
|
76
|
+
path Project root to clean (default: current directory)
|
|
77
|
+
|
|
78
|
+
Options:
|
|
79
|
+
-t, --trash Move to the Trash instead of deleting (instant, recoverable)
|
|
80
|
+
-l, --list List what would be cleared; touch nothing
|
|
81
|
+
--no-measure Skip sizing each node_modules (faster; sizes show as 0)
|
|
82
|
+
--json Print the raw result as JSON
|
|
83
|
+
-y, --yes Skip the confirmation prompt
|
|
84
|
+
-h, --help Show this help
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
By default `remnem` permanently deletes each `node_modules`, after printing what it
|
|
88
|
+
found and asking for confirmation (skipped with `-y`, or when stdout isn't a TTY,
|
|
89
|
+
e.g. in CI). Use `-t` to move them to the Trash instead (space reclaimed when you
|
|
90
|
+
empty it), or `-l` to list what would be cleared without touching anything.
|
|
91
|
+
|
|
92
|
+
## Workspace resolution
|
|
93
|
+
|
|
94
|
+
`remnem` mirrors how bun and pnpm resolve workspace packages:
|
|
95
|
+
|
|
96
|
+
| Source | Field | Example |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| bun / npm / yarn | `package.json` → `workspaces` | `["packages/*", "!packages/excluded"]` |
|
|
99
|
+
| bun / npm / yarn | `package.json` → `workspaces.packages` | `{ "packages": ["libs/*"] }` |
|
|
100
|
+
| pnpm | `pnpm-workspace.yaml` → `packages` | `- 'packages/*'`<br>`- '!**/test/**'` |
|
|
101
|
+
|
|
102
|
+
Glob semantics match [picomatch](https://github.com/micromatch/picomatch) (the
|
|
103
|
+
matcher bun/npm/yarn use):
|
|
104
|
+
|
|
105
|
+
- `*` matches exactly one path segment (`packages/*` → `packages/a`, not `packages/a/b`)
|
|
106
|
+
- `**` matches any number of segments, and a trailing `/**` is **optional**
|
|
107
|
+
(`components/**` matches `components` itself and everything beneath it)
|
|
108
|
+
- `!pattern` excludes previously-matched directories (`!**/test/**` drops a
|
|
109
|
+
directory named `test` and its contents)
|
|
110
|
+
|
|
111
|
+
A directory only counts as a workspace package when it contains its own
|
|
112
|
+
`package.json`.
|
|
113
|
+
|
|
114
|
+
## API
|
|
115
|
+
|
|
116
|
+
The napi-rs core is also usable directly from JavaScript:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
const { clean, resolveWorkspace } = require("remnem");
|
|
120
|
+
|
|
121
|
+
// Clear every nested node_modules under a root.
|
|
122
|
+
// trash: false (default) → permanent parallel delete; true → move to Trash.
|
|
123
|
+
const result = clean({ root: "/path/to/repo", dryRun: false, measure: true, trash: false });
|
|
124
|
+
// → { root, workspaceKind, workspacePackages, cleaned: [{ path, bytes, deleted, trashed, error }], totalBytes, count, failed }
|
|
125
|
+
|
|
126
|
+
// Just inspect how bun/pnpm would see the workspace (no deletion).
|
|
127
|
+
const ws = resolveWorkspace("/path/to/repo");
|
|
128
|
+
// → { workspaceKind: "pnpm" | "package.json" | "none", workspacePackages: [...] }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
See `index.d.ts` for the full typed surface.
|
|
132
|
+
|
|
133
|
+
## Development
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
cargo test # Rust unit tests (workspace resolution + glob semantics)
|
|
137
|
+
bun run build:debug # debug build
|
|
138
|
+
bun run build # release build (LTO)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|
package/bin/remnem.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { clean } = require("../index.js");
|
|
5
|
+
|
|
6
|
+
const HELP = `remnem — delete every nested node_modules, fast
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
remnem [path] [options]
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
path Project root to clean (default: current directory)
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-t, --trash Move to the Trash instead of deleting (instant, recoverable)
|
|
16
|
+
-l, --list List what would be cleared; touch nothing
|
|
17
|
+
--no-measure Skip sizing each node_modules (faster; sizes show as 0)
|
|
18
|
+
--json Print the raw result as JSON
|
|
19
|
+
-y, --yes Skip the confirmation prompt
|
|
20
|
+
-h, --help Show this help
|
|
21
|
+
|
|
22
|
+
Finds every node_modules directory under <path> (root + all workspace packages
|
|
23
|
+
+ any nested ones), using the same workspace resolution as bun / pnpm to report
|
|
24
|
+
the layout, then permanently deletes them in parallel.
|
|
25
|
+
|
|
26
|
+
With -t, moves them to the Trash instead — on the same volume that is a rename
|
|
27
|
+
(instant no matter how large) and recoverable in Finder; the space is reclaimed
|
|
28
|
+
when you empty the Trash.
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
function parseArgs(argv) {
|
|
32
|
+
const opts = {
|
|
33
|
+
root: undefined,
|
|
34
|
+
list: false,
|
|
35
|
+
measure: true,
|
|
36
|
+
trash: false,
|
|
37
|
+
json: false,
|
|
38
|
+
yes: false,
|
|
39
|
+
help: false,
|
|
40
|
+
};
|
|
41
|
+
for (let i = 0; i < argv.length; i++) {
|
|
42
|
+
const arg = argv[i];
|
|
43
|
+
switch (arg) {
|
|
44
|
+
case "-h":
|
|
45
|
+
case "--help":
|
|
46
|
+
opts.help = true;
|
|
47
|
+
break;
|
|
48
|
+
case "-l":
|
|
49
|
+
case "--list":
|
|
50
|
+
opts.list = true;
|
|
51
|
+
break;
|
|
52
|
+
case "-t":
|
|
53
|
+
case "--trash":
|
|
54
|
+
opts.trash = true;
|
|
55
|
+
break;
|
|
56
|
+
case "--no-measure":
|
|
57
|
+
opts.measure = false;
|
|
58
|
+
break;
|
|
59
|
+
case "--measure":
|
|
60
|
+
opts.measure = true;
|
|
61
|
+
break;
|
|
62
|
+
case "--json":
|
|
63
|
+
opts.json = true;
|
|
64
|
+
break;
|
|
65
|
+
case "-y":
|
|
66
|
+
case "--yes":
|
|
67
|
+
opts.yes = true;
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
if (arg.startsWith("-")) {
|
|
71
|
+
process.stderr.write(`remnem: unknown option ${arg}\n\n${HELP}`);
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
if (opts.root !== undefined) {
|
|
75
|
+
process.stderr.write(`remnem: unexpected extra argument ${arg}\n`);
|
|
76
|
+
process.exit(2);
|
|
77
|
+
}
|
|
78
|
+
opts.root = arg;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return opts;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function formatBytes(n) {
|
|
85
|
+
const bytes = typeof n === "bigint" ? Number(n) : n;
|
|
86
|
+
if (!bytes) return "0 B";
|
|
87
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
88
|
+
const exp = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
|
89
|
+
const value = bytes / 1024 ** exp;
|
|
90
|
+
return `${value.toFixed(value >= 10 || exp === 0 ? 0 : 1)} ${units[exp]}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function relativizePath(root, p) {
|
|
94
|
+
if (p === root) return ".";
|
|
95
|
+
if (p.startsWith(root + "/")) return p.slice(root.length + 1);
|
|
96
|
+
return p;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Confirmation prompt (synchronous) so a bare `remnem` in a real repo can't nuke
|
|
100
|
+
// node_modules by a stray keystroke. Skipped with -y, with --list, or when not
|
|
101
|
+
// attached to a TTY (CI / piped).
|
|
102
|
+
function confirm(question) {
|
|
103
|
+
if (!process.stdin.isTTY) return true;
|
|
104
|
+
const fs = require("fs");
|
|
105
|
+
process.stdout.write(question);
|
|
106
|
+
const buf = Buffer.alloc(64);
|
|
107
|
+
let bytesRead = 0;
|
|
108
|
+
try {
|
|
109
|
+
bytesRead = fs.readSync(0, buf, 0, buf.length, null);
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const answer = buf.toString("utf8", 0, bytesRead).trim().toLowerCase();
|
|
114
|
+
return answer === "y" || answer === "yes";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function main() {
|
|
118
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
119
|
+
if (opts.help) {
|
|
120
|
+
process.stdout.write(HELP);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Phase 1: dry-run scan so we can show the user exactly what will go, then
|
|
125
|
+
// (unless -y / non-TTY) confirm before the real deletion.
|
|
126
|
+
const scan = clean({ root: opts.root, dryRun: true, measure: opts.measure });
|
|
127
|
+
|
|
128
|
+
const kindLabel =
|
|
129
|
+
scan.workspaceKind === "none"
|
|
130
|
+
? "no workspace config"
|
|
131
|
+
: `${scan.workspaceKind} workspace (${scan.workspacePackages.length} package${
|
|
132
|
+
scan.workspacePackages.length === 1 ? "" : "s"
|
|
133
|
+
})`;
|
|
134
|
+
|
|
135
|
+
if (opts.json && opts.list) {
|
|
136
|
+
process.stdout.write(JSON.stringify(scan, replacer, 2) + "\n");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (scan.count === 0) {
|
|
141
|
+
process.stdout.write(`remnem: no node_modules found under ${scan.root} (${kindLabel})\n`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
process.stdout.write(`root: ${scan.root}\n`);
|
|
146
|
+
process.stdout.write(` ${kindLabel}\n`);
|
|
147
|
+
process.stdout.write(
|
|
148
|
+
`found ${scan.count} node_modules${
|
|
149
|
+
opts.measure ? ` totalling ${formatBytes(scan.totalBytes)}` : ""
|
|
150
|
+
}:\n`,
|
|
151
|
+
);
|
|
152
|
+
for (const dir of scan.cleaned) {
|
|
153
|
+
const size = opts.measure ? ` ${formatBytes(dir.bytes).padStart(8)}` : "";
|
|
154
|
+
process.stdout.write(`${size} ${relativizePath(scan.root, dir.path)}\n`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (opts.list) {
|
|
158
|
+
process.stdout.write(`\n(list only — nothing ${opts.trash ? "trashed" : "deleted"})\n`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const verb = opts.trash ? "move to Trash" : "permanently delete";
|
|
163
|
+
if (!opts.yes && !confirm(`\n${verb} these ${scan.count} directories? [y/N] `)) {
|
|
164
|
+
process.stdout.write("aborted.\n");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Phase 2: real disposal. Re-measure is unnecessary — reuse sizes we have.
|
|
169
|
+
const start = process.hrtime.bigint();
|
|
170
|
+
const result = clean({ root: opts.root, dryRun: false, measure: false, trash: opts.trash });
|
|
171
|
+
const elapsedMs = Number(process.hrtime.bigint() - start) / 1e6;
|
|
172
|
+
|
|
173
|
+
if (opts.json) {
|
|
174
|
+
process.stdout.write(JSON.stringify(result, replacer, 2) + "\n");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const done = result.count - result.failed;
|
|
179
|
+
const trashedCount = result.cleaned.filter((d) => d.trashed).length;
|
|
180
|
+
// Report how the space went: "trashed" (recoverable, empty Trash to reclaim)
|
|
181
|
+
// vs "deleted" (gone). A trash run that fell back to hard-remove for some
|
|
182
|
+
// items is noted so the count still adds up.
|
|
183
|
+
let action;
|
|
184
|
+
if (!opts.trash) {
|
|
185
|
+
action = "deleted";
|
|
186
|
+
} else if (trashedCount === done) {
|
|
187
|
+
action = "moved to Trash";
|
|
188
|
+
} else {
|
|
189
|
+
action = `moved to Trash (${done - trashedCount} hard-deleted)`;
|
|
190
|
+
}
|
|
191
|
+
process.stdout.write(
|
|
192
|
+
`\n${action}: ${done}/${result.count} node_modules${
|
|
193
|
+
opts.measure ? ` (${formatBytes(scan.totalBytes)})` : ""
|
|
194
|
+
} in ${elapsedMs.toFixed(0)}ms\n`,
|
|
195
|
+
);
|
|
196
|
+
if (opts.trash && trashedCount > 0) {
|
|
197
|
+
process.stdout.write(`empty the Trash to reclaim the space (or re-run without -t to delete).\n`);
|
|
198
|
+
}
|
|
199
|
+
if (result.failed > 0) {
|
|
200
|
+
for (const dir of result.cleaned) {
|
|
201
|
+
if (dir.error) {
|
|
202
|
+
process.stderr.write(` failed: ${relativizePath(result.root, dir.path)} — ${dir.error}\n`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function replacer(_key, value) {
|
|
210
|
+
return typeof value === "bigint" ? Number(value) : value;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
main();
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* auto-generated by NAPI-RS */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
* Find every nested `node_modules` under `root` and (unless `dry_run`) delete
|
|
5
|
+
* them in parallel. Returns a structured summary.
|
|
6
|
+
*/
|
|
7
|
+
export declare function clean(options?: CleanOptions | undefined | null): CleanResult
|
|
8
|
+
|
|
9
|
+
/** A single deleted (or would-be-deleted) `node_modules` directory. */
|
|
10
|
+
export interface CleanedDir {
|
|
11
|
+
path: string
|
|
12
|
+
/** Bytes the directory held (0 when `measure` is false). */
|
|
13
|
+
bytes: bigint
|
|
14
|
+
/** `true` if this directory was (or would be) disposed of successfully. */
|
|
15
|
+
deleted: boolean
|
|
16
|
+
/** `true` if it was moved to the Trash (vs. permanently removed). */
|
|
17
|
+
trashed: boolean
|
|
18
|
+
/** Error message if disposal failed. */
|
|
19
|
+
error?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Options for [`clean`]. */
|
|
23
|
+
export interface CleanOptions {
|
|
24
|
+
/** Project root to clean. Defaults to the current working directory. */
|
|
25
|
+
root?: string
|
|
26
|
+
/** When `true`, only find (do not delete). Defaults to `false`. */
|
|
27
|
+
dryRun?: boolean
|
|
28
|
+
/**
|
|
29
|
+
* When `true`, measure the on-disk size of each `node_modules` before
|
|
30
|
+
* deleting (a second parallel pass). Defaults to `true`.
|
|
31
|
+
*/
|
|
32
|
+
measure?: boolean
|
|
33
|
+
/**
|
|
34
|
+
* When `true`, move each `node_modules` to the OS Trash — a same-volume
|
|
35
|
+
* rename, effectively instant, recoverable in Finder; space is reclaimed
|
|
36
|
+
* when the Trash is emptied. When `false` (the default), permanently
|
|
37
|
+
* `remove_dir_all` them in parallel (reclaims space immediately, not
|
|
38
|
+
* recoverable).
|
|
39
|
+
*/
|
|
40
|
+
trash?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Result of a [`clean`] run. */
|
|
44
|
+
export interface CleanResult {
|
|
45
|
+
/** Absolute project root that was cleaned. */
|
|
46
|
+
root: string
|
|
47
|
+
/** Which workspace manifest drove resolution: `"none" | "package.json" | "pnpm"`. */
|
|
48
|
+
workspaceKind: string
|
|
49
|
+
/**
|
|
50
|
+
* Resolved workspace-package directories (absolute paths). Informational —
|
|
51
|
+
* deletion targets every nested `node_modules`, not just these.
|
|
52
|
+
*/
|
|
53
|
+
workspacePackages: Array<string>
|
|
54
|
+
/** Every `node_modules` directory found (and, unless `dry_run`, deleted). */
|
|
55
|
+
cleaned: Array<CleanedDir>
|
|
56
|
+
/** Total bytes across all found directories (0 when `measure` is false). */
|
|
57
|
+
totalBytes: bigint
|
|
58
|
+
/** Total directories found. */
|
|
59
|
+
count: number
|
|
60
|
+
/** Directories that failed to delete. */
|
|
61
|
+
failed: number
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Resolve workspace layout without deleting anything. Useful for inspecting how
|
|
66
|
+
* bun/pnpm would see the workspace.
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveWorkspace(root?: string | undefined | null): CleanResult
|
package/index.js
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
// prettier-ignore
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
const { readFileSync } = require('fs')
|
|
7
|
+
let nativeBinding = null
|
|
8
|
+
const loadErrors = []
|
|
9
|
+
|
|
10
|
+
const isMusl = () => {
|
|
11
|
+
let musl = false
|
|
12
|
+
if (process.platform === 'linux') {
|
|
13
|
+
musl = isMuslFromFilesystem()
|
|
14
|
+
if (musl === null) {
|
|
15
|
+
musl = isMuslFromReport()
|
|
16
|
+
}
|
|
17
|
+
if (musl === null) {
|
|
18
|
+
musl = isMuslFromChildProcess()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return musl
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-')
|
|
25
|
+
|
|
26
|
+
const isMuslFromFilesystem = () => {
|
|
27
|
+
try {
|
|
28
|
+
return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl')
|
|
29
|
+
} catch {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const isMuslFromReport = () => {
|
|
35
|
+
let report = null
|
|
36
|
+
if (process.report && typeof process.report.getReport === 'function') {
|
|
37
|
+
process.report.excludeNetwork = true
|
|
38
|
+
report = process.report.getReport()
|
|
39
|
+
}
|
|
40
|
+
if (!report) {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
if (report.header && report.header.glibcVersionRuntime) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(report.sharedObjects)) {
|
|
47
|
+
if (report.sharedObjects.some(isFileMusl)) {
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isMuslFromChildProcess = () => {
|
|
55
|
+
try {
|
|
56
|
+
return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
|
|
57
|
+
} catch (e) {
|
|
58
|
+
// If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function requireNative() {
|
|
64
|
+
if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
|
|
65
|
+
try {
|
|
66
|
+
return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
loadErrors.push(err)
|
|
69
|
+
}
|
|
70
|
+
} else if (process.platform === 'android') {
|
|
71
|
+
if (process.arch === 'arm64') {
|
|
72
|
+
try {
|
|
73
|
+
return require('./remnem.android-arm64.node')
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadErrors.push(e)
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const binding = require('@leonsilicon/remnem-android-arm64')
|
|
79
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-android-arm64/package.json').version
|
|
80
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
81
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
82
|
+
}
|
|
83
|
+
return binding
|
|
84
|
+
} catch (e) {
|
|
85
|
+
loadErrors.push(e)
|
|
86
|
+
}
|
|
87
|
+
} else if (process.arch === 'arm') {
|
|
88
|
+
try {
|
|
89
|
+
return require('./remnem.android-arm-eabi.node')
|
|
90
|
+
} catch (e) {
|
|
91
|
+
loadErrors.push(e)
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const binding = require('@leonsilicon/remnem-android-arm-eabi')
|
|
95
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-android-arm-eabi/package.json').version
|
|
96
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
97
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
98
|
+
}
|
|
99
|
+
return binding
|
|
100
|
+
} catch (e) {
|
|
101
|
+
loadErrors.push(e)
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`))
|
|
105
|
+
}
|
|
106
|
+
} else if (process.platform === 'win32') {
|
|
107
|
+
if (process.arch === 'x64') {
|
|
108
|
+
if ((process.config && process.config.variables && process.config.variables.shlib_suffix === 'dll.a') || (process.config && process.config.variables && process.config.variables.node_target_type === 'shared_library')) {
|
|
109
|
+
try {
|
|
110
|
+
return require('./remnem.win32-x64-gnu.node')
|
|
111
|
+
} catch (e) {
|
|
112
|
+
loadErrors.push(e)
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const binding = require('@leonsilicon/remnem-win32-x64-gnu')
|
|
116
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-win32-x64-gnu/package.json').version
|
|
117
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
118
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
119
|
+
}
|
|
120
|
+
return binding
|
|
121
|
+
} catch (e) {
|
|
122
|
+
loadErrors.push(e)
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
try {
|
|
126
|
+
return require('./remnem.win32-x64-msvc.node')
|
|
127
|
+
} catch (e) {
|
|
128
|
+
loadErrors.push(e)
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const binding = require('@leonsilicon/remnem-win32-x64-msvc')
|
|
132
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-win32-x64-msvc/package.json').version
|
|
133
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
134
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
135
|
+
}
|
|
136
|
+
return binding
|
|
137
|
+
} catch (e) {
|
|
138
|
+
loadErrors.push(e)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} else if (process.arch === 'ia32') {
|
|
142
|
+
try {
|
|
143
|
+
return require('./remnem.win32-ia32-msvc.node')
|
|
144
|
+
} catch (e) {
|
|
145
|
+
loadErrors.push(e)
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const binding = require('@leonsilicon/remnem-win32-ia32-msvc')
|
|
149
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-win32-ia32-msvc/package.json').version
|
|
150
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
151
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
152
|
+
}
|
|
153
|
+
return binding
|
|
154
|
+
} catch (e) {
|
|
155
|
+
loadErrors.push(e)
|
|
156
|
+
}
|
|
157
|
+
} else if (process.arch === 'arm64') {
|
|
158
|
+
try {
|
|
159
|
+
return require('./remnem.win32-arm64-msvc.node')
|
|
160
|
+
} catch (e) {
|
|
161
|
+
loadErrors.push(e)
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const binding = require('@leonsilicon/remnem-win32-arm64-msvc')
|
|
165
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-win32-arm64-msvc/package.json').version
|
|
166
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
167
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
168
|
+
}
|
|
169
|
+
return binding
|
|
170
|
+
} catch (e) {
|
|
171
|
+
loadErrors.push(e)
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`))
|
|
175
|
+
}
|
|
176
|
+
} else if (process.platform === 'darwin') {
|
|
177
|
+
try {
|
|
178
|
+
return require('./remnem.darwin-universal.node')
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadErrors.push(e)
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const binding = require('@leonsilicon/remnem-darwin-universal')
|
|
184
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-darwin-universal/package.json').version
|
|
185
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
186
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
187
|
+
}
|
|
188
|
+
return binding
|
|
189
|
+
} catch (e) {
|
|
190
|
+
loadErrors.push(e)
|
|
191
|
+
}
|
|
192
|
+
if (process.arch === 'x64') {
|
|
193
|
+
try {
|
|
194
|
+
return require('./remnem.darwin-x64.node')
|
|
195
|
+
} catch (e) {
|
|
196
|
+
loadErrors.push(e)
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const binding = require('@leonsilicon/remnem-darwin-x64')
|
|
200
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-darwin-x64/package.json').version
|
|
201
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
202
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
203
|
+
}
|
|
204
|
+
return binding
|
|
205
|
+
} catch (e) {
|
|
206
|
+
loadErrors.push(e)
|
|
207
|
+
}
|
|
208
|
+
} else if (process.arch === 'arm64') {
|
|
209
|
+
try {
|
|
210
|
+
return require('./remnem.darwin-arm64.node')
|
|
211
|
+
} catch (e) {
|
|
212
|
+
loadErrors.push(e)
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const binding = require('@leonsilicon/remnem-darwin-arm64')
|
|
216
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-darwin-arm64/package.json').version
|
|
217
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
218
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
219
|
+
}
|
|
220
|
+
return binding
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadErrors.push(e)
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`))
|
|
226
|
+
}
|
|
227
|
+
} else if (process.platform === 'freebsd') {
|
|
228
|
+
if (process.arch === 'x64') {
|
|
229
|
+
try {
|
|
230
|
+
return require('./remnem.freebsd-x64.node')
|
|
231
|
+
} catch (e) {
|
|
232
|
+
loadErrors.push(e)
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const binding = require('@leonsilicon/remnem-freebsd-x64')
|
|
236
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-freebsd-x64/package.json').version
|
|
237
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
238
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
239
|
+
}
|
|
240
|
+
return binding
|
|
241
|
+
} catch (e) {
|
|
242
|
+
loadErrors.push(e)
|
|
243
|
+
}
|
|
244
|
+
} else if (process.arch === 'arm64') {
|
|
245
|
+
try {
|
|
246
|
+
return require('./remnem.freebsd-arm64.node')
|
|
247
|
+
} catch (e) {
|
|
248
|
+
loadErrors.push(e)
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const binding = require('@leonsilicon/remnem-freebsd-arm64')
|
|
252
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-freebsd-arm64/package.json').version
|
|
253
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
254
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
255
|
+
}
|
|
256
|
+
return binding
|
|
257
|
+
} catch (e) {
|
|
258
|
+
loadErrors.push(e)
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`))
|
|
262
|
+
}
|
|
263
|
+
} else if (process.platform === 'linux') {
|
|
264
|
+
if (process.arch === 'x64') {
|
|
265
|
+
if (isMusl()) {
|
|
266
|
+
try {
|
|
267
|
+
return require('./remnem.linux-x64-musl.node')
|
|
268
|
+
} catch (e) {
|
|
269
|
+
loadErrors.push(e)
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const binding = require('@leonsilicon/remnem-linux-x64-musl')
|
|
273
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-x64-musl/package.json').version
|
|
274
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
275
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
276
|
+
}
|
|
277
|
+
return binding
|
|
278
|
+
} catch (e) {
|
|
279
|
+
loadErrors.push(e)
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
try {
|
|
283
|
+
return require('./remnem.linux-x64-gnu.node')
|
|
284
|
+
} catch (e) {
|
|
285
|
+
loadErrors.push(e)
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const binding = require('@leonsilicon/remnem-linux-x64-gnu')
|
|
289
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-x64-gnu/package.json').version
|
|
290
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
291
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
292
|
+
}
|
|
293
|
+
return binding
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadErrors.push(e)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} else if (process.arch === 'arm64') {
|
|
299
|
+
if (isMusl()) {
|
|
300
|
+
try {
|
|
301
|
+
return require('./remnem.linux-arm64-musl.node')
|
|
302
|
+
} catch (e) {
|
|
303
|
+
loadErrors.push(e)
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const binding = require('@leonsilicon/remnem-linux-arm64-musl')
|
|
307
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-arm64-musl/package.json').version
|
|
308
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
309
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
310
|
+
}
|
|
311
|
+
return binding
|
|
312
|
+
} catch (e) {
|
|
313
|
+
loadErrors.push(e)
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
try {
|
|
317
|
+
return require('./remnem.linux-arm64-gnu.node')
|
|
318
|
+
} catch (e) {
|
|
319
|
+
loadErrors.push(e)
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
const binding = require('@leonsilicon/remnem-linux-arm64-gnu')
|
|
323
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-arm64-gnu/package.json').version
|
|
324
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
325
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
326
|
+
}
|
|
327
|
+
return binding
|
|
328
|
+
} catch (e) {
|
|
329
|
+
loadErrors.push(e)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
} else if (process.arch === 'arm') {
|
|
333
|
+
if (isMusl()) {
|
|
334
|
+
try {
|
|
335
|
+
return require('./remnem.linux-arm-musleabihf.node')
|
|
336
|
+
} catch (e) {
|
|
337
|
+
loadErrors.push(e)
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const binding = require('@leonsilicon/remnem-linux-arm-musleabihf')
|
|
341
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-arm-musleabihf/package.json').version
|
|
342
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
343
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
344
|
+
}
|
|
345
|
+
return binding
|
|
346
|
+
} catch (e) {
|
|
347
|
+
loadErrors.push(e)
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
try {
|
|
351
|
+
return require('./remnem.linux-arm-gnueabihf.node')
|
|
352
|
+
} catch (e) {
|
|
353
|
+
loadErrors.push(e)
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
const binding = require('@leonsilicon/remnem-linux-arm-gnueabihf')
|
|
357
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-arm-gnueabihf/package.json').version
|
|
358
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
359
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
360
|
+
}
|
|
361
|
+
return binding
|
|
362
|
+
} catch (e) {
|
|
363
|
+
loadErrors.push(e)
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
} else if (process.arch === 'loong64') {
|
|
367
|
+
if (isMusl()) {
|
|
368
|
+
try {
|
|
369
|
+
return require('./remnem.linux-loong64-musl.node')
|
|
370
|
+
} catch (e) {
|
|
371
|
+
loadErrors.push(e)
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
const binding = require('@leonsilicon/remnem-linux-loong64-musl')
|
|
375
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-loong64-musl/package.json').version
|
|
376
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
377
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
378
|
+
}
|
|
379
|
+
return binding
|
|
380
|
+
} catch (e) {
|
|
381
|
+
loadErrors.push(e)
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
try {
|
|
385
|
+
return require('./remnem.linux-loong64-gnu.node')
|
|
386
|
+
} catch (e) {
|
|
387
|
+
loadErrors.push(e)
|
|
388
|
+
}
|
|
389
|
+
try {
|
|
390
|
+
const binding = require('@leonsilicon/remnem-linux-loong64-gnu')
|
|
391
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-loong64-gnu/package.json').version
|
|
392
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
393
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
394
|
+
}
|
|
395
|
+
return binding
|
|
396
|
+
} catch (e) {
|
|
397
|
+
loadErrors.push(e)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} else if (process.arch === 'riscv64') {
|
|
401
|
+
if (isMusl()) {
|
|
402
|
+
try {
|
|
403
|
+
return require('./remnem.linux-riscv64-musl.node')
|
|
404
|
+
} catch (e) {
|
|
405
|
+
loadErrors.push(e)
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const binding = require('@leonsilicon/remnem-linux-riscv64-musl')
|
|
409
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-riscv64-musl/package.json').version
|
|
410
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
411
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
412
|
+
}
|
|
413
|
+
return binding
|
|
414
|
+
} catch (e) {
|
|
415
|
+
loadErrors.push(e)
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
try {
|
|
419
|
+
return require('./remnem.linux-riscv64-gnu.node')
|
|
420
|
+
} catch (e) {
|
|
421
|
+
loadErrors.push(e)
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
const binding = require('@leonsilicon/remnem-linux-riscv64-gnu')
|
|
425
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-riscv64-gnu/package.json').version
|
|
426
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
427
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
428
|
+
}
|
|
429
|
+
return binding
|
|
430
|
+
} catch (e) {
|
|
431
|
+
loadErrors.push(e)
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
} else if (process.arch === 'ppc64') {
|
|
435
|
+
try {
|
|
436
|
+
return require('./remnem.linux-ppc64-gnu.node')
|
|
437
|
+
} catch (e) {
|
|
438
|
+
loadErrors.push(e)
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
const binding = require('@leonsilicon/remnem-linux-ppc64-gnu')
|
|
442
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-ppc64-gnu/package.json').version
|
|
443
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
444
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
445
|
+
}
|
|
446
|
+
return binding
|
|
447
|
+
} catch (e) {
|
|
448
|
+
loadErrors.push(e)
|
|
449
|
+
}
|
|
450
|
+
} else if (process.arch === 's390x') {
|
|
451
|
+
try {
|
|
452
|
+
return require('./remnem.linux-s390x-gnu.node')
|
|
453
|
+
} catch (e) {
|
|
454
|
+
loadErrors.push(e)
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const binding = require('@leonsilicon/remnem-linux-s390x-gnu')
|
|
458
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-linux-s390x-gnu/package.json').version
|
|
459
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
460
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
461
|
+
}
|
|
462
|
+
return binding
|
|
463
|
+
} catch (e) {
|
|
464
|
+
loadErrors.push(e)
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`))
|
|
468
|
+
}
|
|
469
|
+
} else if (process.platform === 'openharmony') {
|
|
470
|
+
if (process.arch === 'arm64') {
|
|
471
|
+
try {
|
|
472
|
+
return require('./remnem.openharmony-arm64.node')
|
|
473
|
+
} catch (e) {
|
|
474
|
+
loadErrors.push(e)
|
|
475
|
+
}
|
|
476
|
+
try {
|
|
477
|
+
const binding = require('@leonsilicon/remnem-openharmony-arm64')
|
|
478
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-openharmony-arm64/package.json').version
|
|
479
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
480
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
481
|
+
}
|
|
482
|
+
return binding
|
|
483
|
+
} catch (e) {
|
|
484
|
+
loadErrors.push(e)
|
|
485
|
+
}
|
|
486
|
+
} else if (process.arch === 'x64') {
|
|
487
|
+
try {
|
|
488
|
+
return require('./remnem.openharmony-x64.node')
|
|
489
|
+
} catch (e) {
|
|
490
|
+
loadErrors.push(e)
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
const binding = require('@leonsilicon/remnem-openharmony-x64')
|
|
494
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-openharmony-x64/package.json').version
|
|
495
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
496
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
497
|
+
}
|
|
498
|
+
return binding
|
|
499
|
+
} catch (e) {
|
|
500
|
+
loadErrors.push(e)
|
|
501
|
+
}
|
|
502
|
+
} else if (process.arch === 'arm') {
|
|
503
|
+
try {
|
|
504
|
+
return require('./remnem.openharmony-arm.node')
|
|
505
|
+
} catch (e) {
|
|
506
|
+
loadErrors.push(e)
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
const binding = require('@leonsilicon/remnem-openharmony-arm')
|
|
510
|
+
const bindingPackageVersion = require('@leonsilicon/remnem-openharmony-arm/package.json').version
|
|
511
|
+
if (bindingPackageVersion !== '0.1.8' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
512
|
+
throw new Error(`Native binding package version mismatch, expected 0.1.8 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
513
|
+
}
|
|
514
|
+
return binding
|
|
515
|
+
} catch (e) {
|
|
516
|
+
loadErrors.push(e)
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
loadErrors.push(new Error(`Unsupported architecture on OpenHarmony: ${process.arch}`))
|
|
520
|
+
}
|
|
521
|
+
} else {
|
|
522
|
+
loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`))
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
nativeBinding = requireNative()
|
|
527
|
+
|
|
528
|
+
// NAPI_RS_FORCE_WASI is a tri-state flag:
|
|
529
|
+
// unset / any other value → native binding preferred, WASI is only a fallback
|
|
530
|
+
// 'true' → force WASI fallback even if native loaded
|
|
531
|
+
// 'error' → force WASI and throw if no WASI binding is found
|
|
532
|
+
// Treating any non-empty string as truthy (the historical behavior) meant
|
|
533
|
+
// NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
|
|
534
|
+
// the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
|
|
535
|
+
const forceWasi =
|
|
536
|
+
process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error'
|
|
537
|
+
|
|
538
|
+
if (!nativeBinding || forceWasi) {
|
|
539
|
+
let wasiBinding = null
|
|
540
|
+
let wasiBindingError = null
|
|
541
|
+
try {
|
|
542
|
+
wasiBinding = require('./remnem.wasi.cjs')
|
|
543
|
+
nativeBinding = wasiBinding
|
|
544
|
+
} catch (err) {
|
|
545
|
+
if (forceWasi) {
|
|
546
|
+
wasiBindingError = err
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (!nativeBinding || forceWasi) {
|
|
550
|
+
try {
|
|
551
|
+
wasiBinding = require('@leonsilicon/remnem-wasm32-wasi')
|
|
552
|
+
nativeBinding = wasiBinding
|
|
553
|
+
} catch (err) {
|
|
554
|
+
if (forceWasi) {
|
|
555
|
+
if (!wasiBindingError) {
|
|
556
|
+
wasiBindingError = err
|
|
557
|
+
} else {
|
|
558
|
+
wasiBindingError.cause = err
|
|
559
|
+
}
|
|
560
|
+
loadErrors.push(err)
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (process.env.NAPI_RS_FORCE_WASI === 'error' && !wasiBinding) {
|
|
565
|
+
const error = new Error('WASI binding not found and NAPI_RS_FORCE_WASI is set to error')
|
|
566
|
+
error.cause = wasiBindingError
|
|
567
|
+
throw error
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (!nativeBinding) {
|
|
572
|
+
if (loadErrors.length > 0) {
|
|
573
|
+
const error = new Error(
|
|
574
|
+
`Cannot find native binding. ` +
|
|
575
|
+
`npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
|
|
576
|
+
'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
|
|
577
|
+
)
|
|
578
|
+
// assign instead of the `new Error(message, { cause })` options form,
|
|
579
|
+
// which Node < 16.9 silently ignores
|
|
580
|
+
error.cause = loadErrors.reduce((err, cur) => {
|
|
581
|
+
cur.cause = err
|
|
582
|
+
return cur
|
|
583
|
+
})
|
|
584
|
+
throw error
|
|
585
|
+
}
|
|
586
|
+
throw new Error(`Failed to load native binding`)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
module.exports = nativeBinding
|
|
590
|
+
module.exports.clean = nativeBinding.clean
|
|
591
|
+
module.exports.resolveWorkspace = nativeBinding.resolveWorkspace
|
package/package.json
CHANGED
|
@@ -1 +1,82 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "remnem",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Find and delete every nested node_modules in a project as fast as possible (napi-rs / Rust)",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "Leon Si",
|
|
10
|
+
"homepage": "https://github.com/leonsilicon/remnem#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/leonsilicon/remnem.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/leonsilicon/remnem/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"node_modules",
|
|
20
|
+
"monorepo",
|
|
21
|
+
"workspace",
|
|
22
|
+
"clean",
|
|
23
|
+
"cleaner",
|
|
24
|
+
"delete",
|
|
25
|
+
"napi-rs",
|
|
26
|
+
"rust",
|
|
27
|
+
"bun",
|
|
28
|
+
"pnpm"
|
|
29
|
+
],
|
|
30
|
+
"bin": {
|
|
31
|
+
"remnem": "bin/remnem.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"index.js",
|
|
35
|
+
"index.d.ts",
|
|
36
|
+
"bin/remnem.js",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"napi": {
|
|
41
|
+
"binaryName": "remnem",
|
|
42
|
+
"targets": [
|
|
43
|
+
"x86_64-apple-darwin",
|
|
44
|
+
"aarch64-apple-darwin",
|
|
45
|
+
"x86_64-unknown-linux-gnu",
|
|
46
|
+
"aarch64-unknown-linux-gnu",
|
|
47
|
+
"x86_64-unknown-linux-musl",
|
|
48
|
+
"aarch64-unknown-linux-musl",
|
|
49
|
+
"x86_64-pc-windows-msvc",
|
|
50
|
+
"aarch64-pc-windows-msvc"
|
|
51
|
+
],
|
|
52
|
+
"packageName": "@leonsilicon/remnem"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">= 18"
|
|
56
|
+
},
|
|
57
|
+
"optionalDependencies": {
|
|
58
|
+
"@leonsilicon/remnem-darwin-x64": "0.1.8",
|
|
59
|
+
"@leonsilicon/remnem-darwin-arm64": "0.1.8",
|
|
60
|
+
"@leonsilicon/remnem-linux-x64-gnu": "0.1.8",
|
|
61
|
+
"@leonsilicon/remnem-linux-arm64-gnu": "0.1.8",
|
|
62
|
+
"@leonsilicon/remnem-linux-x64-musl": "0.1.8",
|
|
63
|
+
"@leonsilicon/remnem-linux-arm64-musl": "0.1.8",
|
|
64
|
+
"@leonsilicon/remnem-win32-x64-msvc": "0.1.8",
|
|
65
|
+
"@leonsilicon/remnem-win32-arm64-msvc": "0.1.8"
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public",
|
|
69
|
+
"provenance": true
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "napi build --platform --release",
|
|
73
|
+
"build:debug": "napi build --platform",
|
|
74
|
+
"artifacts": "napi artifacts",
|
|
75
|
+
"prepublishOnly": "napi prepublish -t npm",
|
|
76
|
+
"test": "cargo test",
|
|
77
|
+
"version": "napi version"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@napi-rs/cli": "^3.0.0"
|
|
81
|
+
}
|
|
82
|
+
}
|