remnem 0.1.8 → 0.1.9

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 CHANGED
@@ -1,33 +1,52 @@
1
1
  # remnem
2
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.
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, **instantly**.
4
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.
5
+ A single self-contained CLI written in **Rust**: a lean, parallel, directory-only walker finds every `node_modules`, then each one is disposed of by an **O(1) rename** rather than a slow recursive unlink — so clearing a 1000-package monorepo takes a couple hundred milliseconds instead of tens of seconds.
6
6
 
7
7
  ```
8
8
  $ remnem
9
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
10
+ found 1947 node_modules:
11
+ node_modules
12
+ apps/web/node_modules
13
+ ...
14
+ permanently delete these 1947 directories? [y/N] y
15
+
16
+ deleted: 1947/1947 node_modules in 130ms
17
+ (space is being reclaimed in the background)
18
18
  ```
19
19
 
20
- ## Delete vs. Trash
20
+ ## How it's instant
21
+
22
+ Physically deleting `node_modules` means unlinking hundreds of thousands of
23
+ files — that is I/O-bound and unavoidably slow (tens of seconds on a big
24
+ monorepo). remnem sidesteps that on the critical path:
21
25
 
22
- By default `remnem` **permanently deletes** each `node_modules` in parallel
23
- space is reclaimed immediately.
26
+ 1. **Find** a parallel, directory-only walk. It reads directory entries via
27
+ `readdir`'s `d_type` (no per-file `stat`), never looks at regular files, and
28
+ never descends *into* a `node_modules` (the whole subtree is going anyway).
29
+ So the walk is proportional to your *source* tree, not the installed
30
+ dependency tree.
31
+ 2. **Rename aside** — each `node_modules` is `rename`d to a hidden sibling in the
32
+ same directory. On one filesystem that is an O(1) metadata operation no matter
33
+ how large the tree is. The instant it returns, `node_modules` is gone from its
34
+ location — **a clean reinstall can start immediately**.
35
+ 3. **Reclaim in the background** — a detached background process `rm -rf`s the
36
+ renamed directories, so the disk-freeing I/O never blocks you. Space comes
37
+ back within a few seconds, hands-free.
24
38
 
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.
39
+ Pass **`--sync`** if you'd rather block until the space is actually reclaimed
40
+ (e.g. a script that measures free disk right after).
41
+
42
+ ## Delete vs. Trash
43
+
44
+ By default `remnem` **permanently deletes** (via the instant rename-then-reap
45
+ above). Pass **`-t` / `--trash`** to move each `node_modules` to the OS trash
46
+ instead (Finder Trash on macOS, the freedesktop trash on Linux, the Recycle Bin
47
+ on Windows) — recoverable from the trash, with the space reclaimed when you empty
48
+ it. A `node_modules` on a *different* volume (rare) can't be renamed instantly, so
49
+ those fall back to a direct delete.
31
50
 
32
51
  ## Install
33
52
 
@@ -36,36 +55,29 @@ npm install -g remnem
36
55
  # or: bun install -g remnem
37
56
  ```
38
57
 
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).
58
+ The right prebuilt binary is pulled in automatically for your platform via
59
+ `optionalDependencies` the main `remnem` package is a tiny launcher that execs
60
+ it. Supported: **macOS** (arm64, x64), **Linux** (arm64 & x64, glibc & musl),
61
+ **Windows** (arm64, x64).
42
62
 
43
63
  Then from any repo root:
44
64
 
45
65
  ```sh
46
- remnem
66
+ remnem # or: npx remnem / bunx remnem
47
67
  ```
48
68
 
49
69
  ### From source
50
70
 
51
71
  ```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
72
+ cargo build --release # produces target/release/remnem
73
+ ./target/release/remnem --help
55
74
  ```
56
75
 
57
76
  ## What it clears
58
77
 
59
78
  **Every `node_modules` directory** under the given root — the root's own, every
60
79
  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.
80
+ `package.json` files untouched.
69
81
 
70
82
  ## Usage
71
83
 
@@ -76,22 +88,27 @@ Arguments:
76
88
  path Project root to clean (default: current directory)
77
89
 
78
90
  Options:
79
- -t, --trash Move to the Trash instead of deleting (instant, recoverable)
91
+ -t, --trash Move to the Trash instead of deleting (recoverable)
80
92
  -l, --list List what would be cleared; touch nothing
81
- --no-measure Skip sizing each node_modules (faster; sizes show as 0)
93
+ -m, --measure Size each node_modules (slow: walks every dependency tree)
94
+ -w, --workspace Also resolve & report the bun/pnpm workspace layout (slow)
95
+ --sync Wait for the disk space to actually free before returning
82
96
  --json Print the raw result as JSON
83
97
  -y, --yes Skip the confirmation prompt
84
98
  -h, --help Show this help
85
99
  ```
86
100
 
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.
101
+ By default `remnem` deletes each `node_modules` after printing what it found and
102
+ asking for confirmation (skipped with `-y`, or when stdin isn't a TTY, e.g. in
103
+ CI). Use `-l` to list without touching anything, `-t` to move to the Trash, or
104
+ `--sync` to wait for the space to be reclaimed.
105
+
106
+ Sizing (`-m`) and workspace-layout resolution (`-w`) each require an extra tree
107
+ walk, so they are **off by default** — the fast path does neither.
91
108
 
92
- ## Workspace resolution
109
+ ## Workspace resolution (`-w`)
93
110
 
94
- `remnem` mirrors how bun and pnpm resolve workspace packages:
111
+ With `-w`, `remnem` reports the workspace layout the way bun and pnpm resolve it:
95
112
 
96
113
  | Source | Field | Example |
97
114
  | --- | --- | --- |
@@ -108,34 +125,15 @@ matcher bun/npm/yarn use):
108
125
  - `!pattern` excludes previously-matched directories (`!**/test/**` drops a
109
126
  directory named `test` and its contents)
110
127
 
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.
128
+ This is purely informational: clearing always targets every nested
129
+ `node_modules`, not only workspace packages.
132
130
 
133
131
  ## Development
134
132
 
135
133
  ```sh
136
134
  cargo test # Rust unit tests (workspace resolution + glob semantics)
137
- bun run build:debug # debug build
138
- bun run build # release build (LTO)
135
+ cargo build --release # release build (LTO)
136
+ node __test__/smoke.mjs ./target/release/remnem # end-to-end smoke test
139
137
  ```
140
138
 
141
139
  ## License
package/bin/remnem.js CHANGED
@@ -1,213 +1,96 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
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;
4
+ // Thin launcher. remnem ships as a compiled Rust binary, one per platform, in an
5
+ // optional dependency package (@leonsilicon/remnem-<platform>). This shim
6
+ // resolves the binary for the current platform and hands off to it with the same
7
+ // argv, stdio, and exit code — so `remnem` behaves exactly like the native
8
+ // executable while still installing through npm's platform-package mechanism.
9
+
10
+ const { spawnSync } = require("child_process");
11
+ const { existsSync } = require("fs");
12
+ const { join } = require("path");
13
+
14
+ // Map Node's platform/arch to the npm sub-package that carries the binary. Keep
15
+ // this in sync with the `optionalDependencies` in package.json and the `npm/*`
16
+ // package directories.
17
+ const PACKAGES = {
18
+ "darwin-arm64": "@leonsilicon/remnem-darwin-arm64",
19
+ "darwin-x64": "@leonsilicon/remnem-darwin-x64",
20
+ "linux-arm64-gnu": "@leonsilicon/remnem-linux-arm64-gnu",
21
+ "linux-arm64-musl": "@leonsilicon/remnem-linux-arm64-musl",
22
+ "linux-x64-gnu": "@leonsilicon/remnem-linux-x64-gnu",
23
+ "linux-x64-musl": "@leonsilicon/remnem-linux-x64-musl",
24
+ "win32-arm64-msvc": "@leonsilicon/remnem-win32-arm64-msvc",
25
+ "win32-x64-msvc": "@leonsilicon/remnem-win32-x64-msvc",
26
+ };
27
+
28
+ // On Linux, tell glibc from musl so we pick the matching binary package.
29
+ function isMusl() {
30
+ if (process.platform !== "linux") return false;
31
+ try {
32
+ // `process.report` exposes the runtime's libc in its header on modern Node.
33
+ if (process.report && typeof process.report.getReport === "function") {
34
+ const report = process.report.getReport();
35
+ const header = report.header || {};
36
+ if (typeof header.glibcVersionRuntime === "string") return false;
79
37
  }
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;
38
+ } catch {}
108
39
  try {
109
- bytesRead = fs.readSync(0, buf, 0, buf.length, null);
40
+ // Fallback: the ldd on musl systems mentions musl.
41
+ return require("fs").readFileSync("/usr/bin/ldd", "utf8").includes("musl");
110
42
  } catch {
43
+ // Default to gnu; if wrong the resolution below fails loudly with guidance.
111
44
  return false;
112
45
  }
113
- const answer = buf.toString("utf8", 0, bytesRead).trim().toLowerCase();
114
- return answer === "y" || answer === "yes";
115
46
  }
116
47
 
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;
48
+ function platformKey() {
49
+ const { platform, arch } = process;
50
+ if (platform === "linux") {
51
+ return `linux-${arch}-${isMusl() ? "musl" : "gnu"}`;
138
52
  }
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);
53
+ if (platform === "win32") {
54
+ return `win32-${arch}-msvc`;
166
55
  }
56
+ return `${platform}-${arch}`;
57
+ }
167
58
 
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;
59
+ function resolveBinary() {
60
+ const key = platformKey();
61
+ const pkg = PACKAGES[key];
62
+ if (!pkg) {
63
+ return { error: `remnem: unsupported platform ${process.platform}-${process.arch}` };
176
64
  }
65
+ const exe = process.platform === "win32" ? "remnem.exe" : "remnem";
177
66
 
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
- }
67
+ // Prefer resolving through the package's own manifest so we find it wherever
68
+ // the package manager placed it (hoisted, nested, pnpm store, etc.).
69
+ try {
70
+ const manifest = require.resolve(`${pkg}/package.json`);
71
+ const binPath = join(manifest, "..", exe);
72
+ if (existsSync(binPath)) return { binPath };
73
+ } catch {}
74
+
75
+ return {
76
+ error:
77
+ `remnem: could not find the ${pkg} package for your platform.\n` +
78
+ `Install it with your package manager, or reinstall remnem so npm can pull the\n` +
79
+ `matching optional dependency (${pkg}).`,
80
+ };
207
81
  }
208
82
 
209
- function replacer(_key, value) {
210
- return typeof value === "bigint" ? Number(value) : value;
83
+ const { binPath, error } = resolveBinary();
84
+ if (error) {
85
+ process.stderr.write(error + "\n");
86
+ process.exit(1);
211
87
  }
212
88
 
213
- main();
89
+ // Hand off: inherit stdio so the interactive confirmation prompt and all output
90
+ // pass straight through, and propagate the binary's exit code.
91
+ const result = spawnSync(binPath, process.argv.slice(2), { stdio: "inherit" });
92
+ if (result.error) {
93
+ process.stderr.write(`remnem: failed to run ${binPath}: ${result.error.message}\n`);
94
+ process.exit(1);
95
+ }
96
+ process.exit(result.status === null ? 1 : result.status);
package/package.json CHANGED
@@ -1,10 +1,8 @@
1
1
  {
2
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)",
3
+ "version": "0.1.9",
4
+ "description": "Find and delete every nested node_modules in a project as fast as possible (Rust binary)",
5
5
  "type": "commonjs",
6
- "main": "index.js",
7
- "types": "index.d.ts",
8
6
  "license": "MIT",
9
7
  "author": "Leon Si",
10
8
  "homepage": "https://github.com/leonsilicon/remnem#readme",
@@ -22,7 +20,6 @@
22
20
  "clean",
23
21
  "cleaner",
24
22
  "delete",
25
- "napi-rs",
26
23
  "rust",
27
24
  "bun",
28
25
  "pnpm"
@@ -31,52 +28,30 @@
31
28
  "remnem": "bin/remnem.js"
32
29
  },
33
30
  "files": [
34
- "index.js",
35
- "index.d.ts",
36
31
  "bin/remnem.js",
37
32
  "README.md",
38
33
  "LICENSE"
39
34
  ],
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
35
  "engines": {
55
36
  "node": ">= 18"
56
37
  },
57
38
  "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"
39
+ "@leonsilicon/remnem-darwin-x64": "0.1.9",
40
+ "@leonsilicon/remnem-darwin-arm64": "0.1.9",
41
+ "@leonsilicon/remnem-linux-x64-gnu": "0.1.9",
42
+ "@leonsilicon/remnem-linux-arm64-gnu": "0.1.9",
43
+ "@leonsilicon/remnem-linux-x64-musl": "0.1.9",
44
+ "@leonsilicon/remnem-linux-arm64-musl": "0.1.9",
45
+ "@leonsilicon/remnem-win32-x64-msvc": "0.1.9",
46
+ "@leonsilicon/remnem-win32-arm64-msvc": "0.1.9"
66
47
  },
67
48
  "publishConfig": {
68
49
  "access": "public",
69
50
  "provenance": true
70
51
  },
71
52
  "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"
53
+ "build": "cargo build --release",
54
+ "test": "cargo test"
78
55
  },
79
- "devDependencies": {
80
- "@napi-rs/cli": "^3.0.0"
81
- }
82
- }
56
+ "devDependencies": {}
57
+ }
package/index.d.ts DELETED
@@ -1,68 +0,0 @@
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 DELETED
@@ -1,591 +0,0 @@
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