@scelar/nodepod 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -0
- package/README.md +240 -0
- package/dist/child_process-BJOMsZje.js +8233 -0
- package/dist/child_process-BJOMsZje.js.map +1 -0
- package/dist/child_process-Cj8vOcuc.cjs +7434 -0
- package/dist/child_process-Cj8vOcuc.cjs.map +1 -0
- package/dist/index-Cb1Cgdnd.js +35308 -0
- package/dist/index-Cb1Cgdnd.js.map +1 -0
- package/dist/index-DsMGS-xc.cjs +37195 -0
- package/dist/index-DsMGS-xc.cjs.map +1 -0
- package/dist/index.cjs +65 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +59 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +95 -0
- package/src/__tests__/smoke.test.ts +11 -0
- package/src/constants/cdn-urls.ts +18 -0
- package/src/constants/config.ts +236 -0
- package/src/cross-origin.ts +26 -0
- package/src/engine-factory.ts +176 -0
- package/src/engine-types.ts +56 -0
- package/src/helpers/byte-encoding.ts +39 -0
- package/src/helpers/digest.ts +9 -0
- package/src/helpers/event-loop.ts +96 -0
- package/src/helpers/wasm-cache.ts +133 -0
- package/src/iframe-sandbox.ts +141 -0
- package/src/index.ts +192 -0
- package/src/isolation-helpers.ts +148 -0
- package/src/memory-volume.ts +941 -0
- package/src/module-transformer.ts +368 -0
- package/src/packages/archive-extractor.ts +248 -0
- package/src/packages/browser-bundler.ts +284 -0
- package/src/packages/installer.ts +396 -0
- package/src/packages/registry-client.ts +131 -0
- package/src/packages/version-resolver.ts +411 -0
- package/src/polyfills/assert.ts +384 -0
- package/src/polyfills/async_hooks.ts +144 -0
- package/src/polyfills/buffer.ts +628 -0
- package/src/polyfills/child_process.ts +2288 -0
- package/src/polyfills/chokidar.ts +336 -0
- package/src/polyfills/cluster.ts +106 -0
- package/src/polyfills/console.ts +136 -0
- package/src/polyfills/constants.ts +123 -0
- package/src/polyfills/crypto.ts +885 -0
- package/src/polyfills/dgram.ts +87 -0
- package/src/polyfills/diagnostics_channel.ts +76 -0
- package/src/polyfills/dns.ts +134 -0
- package/src/polyfills/domain.ts +68 -0
- package/src/polyfills/esbuild.ts +854 -0
- package/src/polyfills/events.ts +276 -0
- package/src/polyfills/fs.ts +2888 -0
- package/src/polyfills/fsevents.ts +79 -0
- package/src/polyfills/http.ts +1449 -0
- package/src/polyfills/http2.ts +199 -0
- package/src/polyfills/https.ts +76 -0
- package/src/polyfills/inspector.ts +62 -0
- package/src/polyfills/lightningcss.ts +105 -0
- package/src/polyfills/module.ts +191 -0
- package/src/polyfills/net.ts +353 -0
- package/src/polyfills/os.ts +238 -0
- package/src/polyfills/path.ts +206 -0
- package/src/polyfills/perf_hooks.ts +102 -0
- package/src/polyfills/process.ts +690 -0
- package/src/polyfills/punycode.ts +159 -0
- package/src/polyfills/querystring.ts +93 -0
- package/src/polyfills/quic.ts +118 -0
- package/src/polyfills/readdirp.ts +229 -0
- package/src/polyfills/readline.ts +692 -0
- package/src/polyfills/repl.ts +134 -0
- package/src/polyfills/rollup.ts +119 -0
- package/src/polyfills/sea.ts +33 -0
- package/src/polyfills/sqlite.ts +78 -0
- package/src/polyfills/stream.ts +1620 -0
- package/src/polyfills/string_decoder.ts +25 -0
- package/src/polyfills/tailwindcss-oxide.ts +309 -0
- package/src/polyfills/test.ts +197 -0
- package/src/polyfills/timers.ts +32 -0
- package/src/polyfills/tls.ts +105 -0
- package/src/polyfills/trace_events.ts +50 -0
- package/src/polyfills/tty.ts +71 -0
- package/src/polyfills/url.ts +174 -0
- package/src/polyfills/util.ts +559 -0
- package/src/polyfills/v8.ts +126 -0
- package/src/polyfills/vm.ts +132 -0
- package/src/polyfills/volume-registry.ts +15 -0
- package/src/polyfills/wasi.ts +44 -0
- package/src/polyfills/worker_threads.ts +326 -0
- package/src/polyfills/ws.ts +595 -0
- package/src/polyfills/zlib.ts +881 -0
- package/src/request-proxy.ts +716 -0
- package/src/script-engine.ts +3375 -0
- package/src/sdk/nodepod-fs.ts +93 -0
- package/src/sdk/nodepod-process.ts +86 -0
- package/src/sdk/nodepod-terminal.ts +350 -0
- package/src/sdk/nodepod.ts +509 -0
- package/src/sdk/types.ts +70 -0
- package/src/shell/commands/bun.ts +121 -0
- package/src/shell/commands/directory.ts +297 -0
- package/src/shell/commands/file-ops.ts +525 -0
- package/src/shell/commands/git.ts +2142 -0
- package/src/shell/commands/node.ts +80 -0
- package/src/shell/commands/npm.ts +198 -0
- package/src/shell/commands/pm-types.ts +45 -0
- package/src/shell/commands/pnpm.ts +82 -0
- package/src/shell/commands/search.ts +264 -0
- package/src/shell/commands/shell-env.ts +352 -0
- package/src/shell/commands/text-processing.ts +1152 -0
- package/src/shell/commands/yarn.ts +84 -0
- package/src/shell/shell-builtins.ts +19 -0
- package/src/shell/shell-helpers.ts +250 -0
- package/src/shell/shell-interpreter.ts +514 -0
- package/src/shell/shell-parser.ts +429 -0
- package/src/shell/shell-types.ts +85 -0
- package/src/syntax-transforms.ts +561 -0
- package/src/threading/engine-worker.ts +64 -0
- package/src/threading/inline-worker.ts +372 -0
- package/src/threading/offload-types.ts +112 -0
- package/src/threading/offload-worker.ts +383 -0
- package/src/threading/offload.ts +271 -0
- package/src/threading/process-context.ts +92 -0
- package/src/threading/process-handle.ts +275 -0
- package/src/threading/process-manager.ts +956 -0
- package/src/threading/process-worker-entry.ts +854 -0
- package/src/threading/shared-vfs.ts +352 -0
- package/src/threading/sync-channel.ts +135 -0
- package/src/threading/task-queue.ts +177 -0
- package/src/threading/vfs-bridge.ts +231 -0
- package/src/threading/worker-pool.ts +233 -0
- package/src/threading/worker-protocol.ts +358 -0
- package/src/threading/worker-vfs.ts +218 -0
- package/src/types/externals.d.ts +38 -0
- package/src/types/fs-streams.ts +142 -0
- package/src/types/manifest.ts +17 -0
- package/src/worker-sandbox.ts +90 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { ShellCommand } from "../shell-types";
|
|
2
|
+
import type { PmDeps } from "./pm-types";
|
|
3
|
+
import { VERSIONS } from "../../constants/config";
|
|
4
|
+
|
|
5
|
+
const A_RESET = "\x1b[0m";
|
|
6
|
+
const A_BOLD = "\x1b[1m";
|
|
7
|
+
|
|
8
|
+
export function createNodeCommand(deps: PmDeps): ShellCommand {
|
|
9
|
+
return {
|
|
10
|
+
name: "node",
|
|
11
|
+
async execute(params, ctx) {
|
|
12
|
+
if (!deps.hasFile("/"))
|
|
13
|
+
return { stdout: "", stderr: "Volume unavailable\n", exitCode: 1 };
|
|
14
|
+
|
|
15
|
+
let target: string | null = null;
|
|
16
|
+
let evalCode: string | null = null;
|
|
17
|
+
let printCode: string | null = null;
|
|
18
|
+
const scriptArgs: string[] = [];
|
|
19
|
+
let collectingArgs = false;
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < params.length; i++) {
|
|
22
|
+
if (collectingArgs) {
|
|
23
|
+
scriptArgs.push(params[i]);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (params[i] === "-e" || params[i] === "--eval") {
|
|
27
|
+
evalCode = params[++i] ?? "";
|
|
28
|
+
} else if (params[i] === "-p" || params[i] === "--print") {
|
|
29
|
+
printCode = params[++i] ?? "";
|
|
30
|
+
} else if (params[i] === "--version" || params[i] === "-v") {
|
|
31
|
+
return { stdout: VERSIONS.NODE + "\n", stderr: "", exitCode: 0 };
|
|
32
|
+
} else if (params[i] === "--help" || params[i] === "-h") {
|
|
33
|
+
return {
|
|
34
|
+
stdout: `${A_BOLD}Usage:${A_RESET} node [options] [script.js] [arguments]\n`,
|
|
35
|
+
stderr: "",
|
|
36
|
+
exitCode: 0,
|
|
37
|
+
};
|
|
38
|
+
} else if (
|
|
39
|
+
params[i] === "-r" ||
|
|
40
|
+
params[i] === "--require" ||
|
|
41
|
+
params[i] === "--experimental-specifier-resolution" ||
|
|
42
|
+
params[i] === "--loader" ||
|
|
43
|
+
params[i] === "--import"
|
|
44
|
+
) {
|
|
45
|
+
i++;
|
|
46
|
+
} else if (params[i].startsWith("-")) {
|
|
47
|
+
// skip unknown flags (--harmony, --inspect, etc.)
|
|
48
|
+
} else {
|
|
49
|
+
target = params[i];
|
|
50
|
+
collectingArgs = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (evalCode !== null) {
|
|
55
|
+
return deps.evalCode(evalCode, ctx);
|
|
56
|
+
}
|
|
57
|
+
if (printCode !== null) {
|
|
58
|
+
return deps.printCode(printCode, ctx);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!target)
|
|
62
|
+
return {
|
|
63
|
+
stdout: "",
|
|
64
|
+
stderr: `${A_BOLD}Usage:${A_RESET} node <file> [args...]\n`,
|
|
65
|
+
exitCode: 1,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return deps.executeNodeBinary(target, scriptArgs, ctx);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createNpxCommand(deps: PmDeps): ShellCommand {
|
|
74
|
+
return {
|
|
75
|
+
name: "npx",
|
|
76
|
+
async execute(params, ctx) {
|
|
77
|
+
return deps.npxExecute(params, ctx);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { ShellCommand } from "../shell-types";
|
|
2
|
+
import type { PmDeps } from "./pm-types";
|
|
3
|
+
import { VERSIONS, NPM_REGISTRY_URL_SLASH } from "../../constants/config";
|
|
4
|
+
|
|
5
|
+
const A_RESET = "\x1b[0m";
|
|
6
|
+
const A_BOLD = "\x1b[1m";
|
|
7
|
+
const A_CYAN = "\x1b[36m";
|
|
8
|
+
|
|
9
|
+
export function createNpmCommand(deps: PmDeps): ShellCommand {
|
|
10
|
+
return {
|
|
11
|
+
name: "npm",
|
|
12
|
+
async execute(params, ctx) {
|
|
13
|
+
if (!deps.hasFile("/"))
|
|
14
|
+
return { stdout: "", stderr: "Volume unavailable\n", exitCode: 1 };
|
|
15
|
+
|
|
16
|
+
const sub = params[0];
|
|
17
|
+
if (!sub || sub === "help" || sub === "--help") {
|
|
18
|
+
return {
|
|
19
|
+
stdout:
|
|
20
|
+
`${A_BOLD}Usage:${A_RESET} npm <command>\n\n` +
|
|
21
|
+
`${A_BOLD}Commands:${A_RESET}\n` +
|
|
22
|
+
` ${A_CYAN}run${A_RESET} <script> Run a package.json script\n` +
|
|
23
|
+
` ${A_CYAN}start${A_RESET} Alias for npm run start\n` +
|
|
24
|
+
` ${A_CYAN}test${A_RESET} Alias for npm run test\n` +
|
|
25
|
+
` ${A_CYAN}install${A_RESET} [pkg] Install packages\n` +
|
|
26
|
+
` ${A_CYAN}uninstall${A_RESET} <pkg> Remove a package\n` +
|
|
27
|
+
` ${A_CYAN}ls${A_RESET} List installed packages\n` +
|
|
28
|
+
` ${A_CYAN}init${A_RESET} Create a package.json\n` +
|
|
29
|
+
` ${A_CYAN}create${A_RESET} <pkg> Create a project (runs create-<pkg>)\n` +
|
|
30
|
+
` ${A_CYAN}version${A_RESET} Show version info\n` +
|
|
31
|
+
` ${A_CYAN}info${A_RESET} <pkg> Show package info\n` +
|
|
32
|
+
` ${A_CYAN}exec${A_RESET} <cmd> Execute a package binary\n` +
|
|
33
|
+
` ${A_CYAN}prefix${A_RESET} Show prefix\n` +
|
|
34
|
+
` ${A_CYAN}root${A_RESET} Show node_modules path\n` +
|
|
35
|
+
` ${A_CYAN}bin${A_RESET} Show bin directory\n` +
|
|
36
|
+
` ${A_CYAN}config${A_RESET} Manage configuration\n`,
|
|
37
|
+
stderr: "",
|
|
38
|
+
exitCode: 0,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
switch (sub) {
|
|
43
|
+
case "run":
|
|
44
|
+
case "run-script":
|
|
45
|
+
return deps.runScript(params.slice(1), ctx);
|
|
46
|
+
case "start":
|
|
47
|
+
return deps.runScript(["start"], ctx);
|
|
48
|
+
case "test":
|
|
49
|
+
case "t":
|
|
50
|
+
case "tst":
|
|
51
|
+
return deps.runScript(["test"], ctx);
|
|
52
|
+
case "install":
|
|
53
|
+
case "i":
|
|
54
|
+
case "add":
|
|
55
|
+
return deps.installPackages(params.slice(1), ctx);
|
|
56
|
+
case "ci":
|
|
57
|
+
try {
|
|
58
|
+
deps.removeNodeModules(ctx.cwd);
|
|
59
|
+
} catch {
|
|
60
|
+
/* */
|
|
61
|
+
}
|
|
62
|
+
return deps.installPackages([], ctx);
|
|
63
|
+
case "uninstall":
|
|
64
|
+
case "remove":
|
|
65
|
+
case "rm":
|
|
66
|
+
case "un":
|
|
67
|
+
return deps.uninstallPackages(params.slice(1), ctx);
|
|
68
|
+
case "ls":
|
|
69
|
+
case "list":
|
|
70
|
+
return deps.listPackages(ctx);
|
|
71
|
+
case "init":
|
|
72
|
+
case "create":
|
|
73
|
+
return deps.npmInitOrCreate(params.slice(1), sub, ctx);
|
|
74
|
+
case "version":
|
|
75
|
+
case "-v":
|
|
76
|
+
case "--version":
|
|
77
|
+
return { stdout: VERSIONS.NPM + "\n", stderr: "", exitCode: 0 };
|
|
78
|
+
case "info":
|
|
79
|
+
case "view":
|
|
80
|
+
case "show":
|
|
81
|
+
return deps.npmInfo(params.slice(1), ctx);
|
|
82
|
+
case "exec":
|
|
83
|
+
return deps.npxExecute(params.slice(1), ctx);
|
|
84
|
+
case "prefix":
|
|
85
|
+
return { stdout: ctx.cwd + "\n", stderr: "", exitCode: 0 };
|
|
86
|
+
case "root":
|
|
87
|
+
return {
|
|
88
|
+
stdout: ctx.cwd + "/node_modules\n",
|
|
89
|
+
stderr: "",
|
|
90
|
+
exitCode: 0,
|
|
91
|
+
};
|
|
92
|
+
case "bin":
|
|
93
|
+
return {
|
|
94
|
+
stdout: ctx.cwd + "/node_modules/.bin\n",
|
|
95
|
+
stderr: "",
|
|
96
|
+
exitCode: 0,
|
|
97
|
+
};
|
|
98
|
+
case "pack":
|
|
99
|
+
return deps.npmPack(ctx);
|
|
100
|
+
case "config":
|
|
101
|
+
case "c":
|
|
102
|
+
return deps.npmConfig(params.slice(1), ctx);
|
|
103
|
+
case "outdated":
|
|
104
|
+
return {
|
|
105
|
+
stdout: "",
|
|
106
|
+
stderr: deps.formatWarn(
|
|
107
|
+
"outdated check not available in nodepod",
|
|
108
|
+
"npm",
|
|
109
|
+
),
|
|
110
|
+
exitCode: 0,
|
|
111
|
+
};
|
|
112
|
+
case "audit":
|
|
113
|
+
return {
|
|
114
|
+
stdout: "found 0 vulnerabilities\n",
|
|
115
|
+
stderr: "",
|
|
116
|
+
exitCode: 0,
|
|
117
|
+
};
|
|
118
|
+
case "fund":
|
|
119
|
+
return {
|
|
120
|
+
stdout: "0 packages are looking for funding\n",
|
|
121
|
+
stderr: "",
|
|
122
|
+
exitCode: 0,
|
|
123
|
+
};
|
|
124
|
+
case "cache":
|
|
125
|
+
if (params[1] === "clean" || params[1] === "clear") {
|
|
126
|
+
return { stdout: "Cache cleared.\n", stderr: "", exitCode: 0 };
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
stdout: "",
|
|
130
|
+
stderr: deps.formatErr(
|
|
131
|
+
`cache: unknown subcommand ${params[1] ?? ""}`,
|
|
132
|
+
"npm",
|
|
133
|
+
),
|
|
134
|
+
exitCode: 1,
|
|
135
|
+
};
|
|
136
|
+
case "whoami":
|
|
137
|
+
return { stdout: "nodepod-user\n", stderr: "", exitCode: 0 };
|
|
138
|
+
case "ping":
|
|
139
|
+
return {
|
|
140
|
+
stdout: `PING ${NPM_REGISTRY_URL_SLASH} - ok\n`,
|
|
141
|
+
stderr: "",
|
|
142
|
+
exitCode: 0,
|
|
143
|
+
};
|
|
144
|
+
case "set-script": {
|
|
145
|
+
const scriptName = params[1];
|
|
146
|
+
const scriptCmd = params.slice(2).join(" ");
|
|
147
|
+
if (!scriptName || !scriptCmd) {
|
|
148
|
+
return {
|
|
149
|
+
stdout: "",
|
|
150
|
+
stderr: deps.formatErr(
|
|
151
|
+
"Usage: npm set-script <name> <command>",
|
|
152
|
+
"npm",
|
|
153
|
+
),
|
|
154
|
+
exitCode: 1,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const pkgPath = ctx.cwd + "/package.json";
|
|
159
|
+
const raw = deps.readFile(pkgPath);
|
|
160
|
+
const pkg = JSON.parse(raw);
|
|
161
|
+
if (!pkg.scripts) pkg.scripts = {};
|
|
162
|
+
pkg.scripts[scriptName] = scriptCmd;
|
|
163
|
+
deps.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
164
|
+
return {
|
|
165
|
+
stdout: "",
|
|
166
|
+
stderr: deps.formatWarn(
|
|
167
|
+
"`set-script` is deprecated. Use `npm pkg set scripts.${scriptName}=\"${scriptCmd}\"` instead.",
|
|
168
|
+
"npm",
|
|
169
|
+
),
|
|
170
|
+
exitCode: 0,
|
|
171
|
+
};
|
|
172
|
+
} catch (e: any) {
|
|
173
|
+
return {
|
|
174
|
+
stdout: "",
|
|
175
|
+
stderr: deps.formatErr(
|
|
176
|
+
e.message || "Failed to update package.json",
|
|
177
|
+
"npm",
|
|
178
|
+
),
|
|
179
|
+
exitCode: 1,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
case "pkg":
|
|
184
|
+
return deps.npmPkg ? deps.npmPkg(params.slice(1), ctx) : {
|
|
185
|
+
stdout: "",
|
|
186
|
+
stderr: deps.formatErr("npm pkg not implemented", "npm"),
|
|
187
|
+
exitCode: 1,
|
|
188
|
+
};
|
|
189
|
+
default:
|
|
190
|
+
return {
|
|
191
|
+
stdout: "",
|
|
192
|
+
stderr: deps.formatErr(`Unknown command "${sub}"`, "npm"),
|
|
193
|
+
exitCode: 1,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Shared types for package manager commands (npm, pnpm, yarn, bun).
|
|
2
|
+
// Each PM file is a factory that receives these deps from child_process.ts.
|
|
3
|
+
|
|
4
|
+
import type { ShellCommand, ShellResult, ShellContext } from "../shell-types";
|
|
5
|
+
|
|
6
|
+
export type PkgManager = "npm" | "pnpm" | "yarn" | "bun";
|
|
7
|
+
|
|
8
|
+
export interface PmDeps {
|
|
9
|
+
installPackages: (
|
|
10
|
+
args: string[],
|
|
11
|
+
ctx: ShellContext,
|
|
12
|
+
pm?: PkgManager,
|
|
13
|
+
) => Promise<ShellResult>;
|
|
14
|
+
uninstallPackages: (
|
|
15
|
+
args: string[],
|
|
16
|
+
ctx: ShellContext,
|
|
17
|
+
pm?: PkgManager,
|
|
18
|
+
) => Promise<ShellResult>;
|
|
19
|
+
listPackages: (ctx: ShellContext, pm?: PkgManager) => Promise<ShellResult>;
|
|
20
|
+
runScript: (args: string[], ctx: ShellContext) => Promise<ShellResult>;
|
|
21
|
+
npmInitOrCreate: (
|
|
22
|
+
args: string[],
|
|
23
|
+
sub: string,
|
|
24
|
+
ctx: ShellContext,
|
|
25
|
+
) => Promise<ShellResult>;
|
|
26
|
+
npmInfo: (args: string[], ctx: ShellContext) => Promise<ShellResult>;
|
|
27
|
+
npmPack: (ctx: ShellContext) => ShellResult;
|
|
28
|
+
npmConfig: (args: string[], ctx: ShellContext) => ShellResult;
|
|
29
|
+
npxExecute: (params: string[], ctx: ShellContext) => Promise<ShellResult>;
|
|
30
|
+
executeNodeBinary: (
|
|
31
|
+
filePath: string,
|
|
32
|
+
args: string[],
|
|
33
|
+
ctx: ShellContext,
|
|
34
|
+
opts?: { isFork?: boolean },
|
|
35
|
+
) => Promise<ShellResult>;
|
|
36
|
+
evalCode: (code: string, ctx: ShellContext) => ShellResult;
|
|
37
|
+
printCode: (code: string, ctx: ShellContext) => ShellResult;
|
|
38
|
+
removeNodeModules: (cwd: string) => void;
|
|
39
|
+
formatErr: (msg: string, pm: PkgManager) => string;
|
|
40
|
+
formatWarn: (msg: string, pm: PkgManager) => string;
|
|
41
|
+
hasFile: (path: string) => boolean;
|
|
42
|
+
readFile: (path: string) => string;
|
|
43
|
+
writeFile: (path: string, data: string) => void;
|
|
44
|
+
npmPkg?: (args: string[], ctx: ShellContext) => ShellResult;
|
|
45
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ShellCommand } from "../shell-types";
|
|
2
|
+
import type { PmDeps } from "./pm-types";
|
|
3
|
+
import { VERSIONS } from "../../constants/config";
|
|
4
|
+
|
|
5
|
+
const A_RESET = "\x1b[0m";
|
|
6
|
+
const A_BOLD = "\x1b[1m";
|
|
7
|
+
const A_CYAN = "\x1b[36m";
|
|
8
|
+
|
|
9
|
+
export function createPnpmCommand(deps: PmDeps): ShellCommand {
|
|
10
|
+
return {
|
|
11
|
+
name: "pnpm",
|
|
12
|
+
async execute(params, ctx) {
|
|
13
|
+
if (!deps.hasFile("/"))
|
|
14
|
+
return { stdout: "", stderr: "Volume unavailable\n", exitCode: 1 };
|
|
15
|
+
|
|
16
|
+
const sub = params[0];
|
|
17
|
+
if (!sub || sub === "help" || sub === "--help") {
|
|
18
|
+
return {
|
|
19
|
+
stdout:
|
|
20
|
+
`${A_BOLD}Usage:${A_RESET} pnpm <command>\n\n` +
|
|
21
|
+
`${A_BOLD}Manage your dependencies:${A_RESET}\n` +
|
|
22
|
+
` ${A_CYAN}add${A_RESET} [pkg] Install packages\n` +
|
|
23
|
+
` ${A_CYAN}install${A_RESET} Install from manifest\n` +
|
|
24
|
+
` ${A_CYAN}remove${A_RESET} <pkg> Remove a package\n` +
|
|
25
|
+
` ${A_CYAN}list${A_RESET} List installed packages\n\n` +
|
|
26
|
+
`${A_BOLD}Run your scripts:${A_RESET}\n` +
|
|
27
|
+
` ${A_CYAN}run${A_RESET} <script> Run a script\n` +
|
|
28
|
+
` ${A_CYAN}exec${A_RESET} <cmd> Execute a package binary\n` +
|
|
29
|
+
` ${A_CYAN}dlx${A_RESET} <pkg> Download and execute a package\n\n` +
|
|
30
|
+
`${A_BOLD}Create a project:${A_RESET}\n` +
|
|
31
|
+
` ${A_CYAN}init${A_RESET} Create a package.json\n` +
|
|
32
|
+
` ${A_CYAN}create${A_RESET} <pkg> Create a project\n\n` +
|
|
33
|
+
` ${A_CYAN}version${A_RESET} Show version info\n`,
|
|
34
|
+
stderr: "",
|
|
35
|
+
exitCode: 0,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
switch (sub) {
|
|
40
|
+
case "add":
|
|
41
|
+
return deps.installPackages(params.slice(1), ctx, "pnpm");
|
|
42
|
+
case "install":
|
|
43
|
+
case "i":
|
|
44
|
+
return deps.installPackages(params.slice(1), ctx, "pnpm");
|
|
45
|
+
case "remove":
|
|
46
|
+
case "rm":
|
|
47
|
+
case "uninstall":
|
|
48
|
+
case "un":
|
|
49
|
+
return deps.uninstallPackages(params.slice(1), ctx, "pnpm");
|
|
50
|
+
case "list":
|
|
51
|
+
case "ls":
|
|
52
|
+
return deps.listPackages(ctx, "pnpm");
|
|
53
|
+
case "run":
|
|
54
|
+
return deps.runScript(params.slice(1), ctx);
|
|
55
|
+
case "start":
|
|
56
|
+
return deps.runScript(["start"], ctx);
|
|
57
|
+
case "test":
|
|
58
|
+
case "t":
|
|
59
|
+
return deps.runScript(["test"], ctx);
|
|
60
|
+
case "exec":
|
|
61
|
+
return deps.npxExecute(params.slice(1), ctx);
|
|
62
|
+
case "dlx":
|
|
63
|
+
return deps.npxExecute(params.slice(1), ctx);
|
|
64
|
+
case "init":
|
|
65
|
+
case "create":
|
|
66
|
+
return deps.npmInitOrCreate(params.slice(1), sub, ctx);
|
|
67
|
+
case "version":
|
|
68
|
+
case "-v":
|
|
69
|
+
case "--version":
|
|
70
|
+
return { stdout: VERSIONS.PNPM + "\n", stderr: "", exitCode: 0 };
|
|
71
|
+
case "audit":
|
|
72
|
+
return { stdout: "No known vulnerabilities found\n", stderr: "", exitCode: 0 };
|
|
73
|
+
case "outdated":
|
|
74
|
+
return { stdout: "", stderr: "", exitCode: 0 };
|
|
75
|
+
case "why":
|
|
76
|
+
return { stdout: "", stderr: deps.formatWarn("why: not available in nodepod", "pnpm"), exitCode: 0 };
|
|
77
|
+
default:
|
|
78
|
+
return { stdout: "", stderr: deps.formatErr(`Unknown command "${sub}"`, "pnpm"), exitCode: 1 };
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import type { BuiltinFn } from "../shell-types";
|
|
2
|
+
import { ok, fail, resolvePath, globToRegex } from "../shell-helpers";
|
|
3
|
+
import { LS_BLOCK_SIZE } from "../../constants/config";
|
|
4
|
+
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Helpers */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
|
|
9
|
+
function matchSize(fileSize: number, spec: string): boolean {
|
|
10
|
+
const m = spec.match(/^([+-]?)(\d+)([cwbkMG]?)$/);
|
|
11
|
+
if (!m) return true;
|
|
12
|
+
const op = m[1];
|
|
13
|
+
let n = parseInt(m[2]);
|
|
14
|
+
const unit = m[3];
|
|
15
|
+
if (unit === "c") {
|
|
16
|
+
/* bytes */
|
|
17
|
+
} else if (unit === "w") n *= 2;
|
|
18
|
+
else if (unit === "k") n *= 1024;
|
|
19
|
+
else if (unit === "M") n *= 1048576;
|
|
20
|
+
else if (unit === "G") n *= 1073741824;
|
|
21
|
+
else n *= LS_BLOCK_SIZE;
|
|
22
|
+
|
|
23
|
+
if (op === "+") return fileSize > n;
|
|
24
|
+
if (op === "-") return fileSize < n;
|
|
25
|
+
return fileSize === n;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function matchMtime(mtimeMs: number, spec: string): boolean {
|
|
29
|
+
const m = spec.match(/^([+-]?)(\d+)$/);
|
|
30
|
+
if (!m) return true;
|
|
31
|
+
const op = m[1];
|
|
32
|
+
const days = parseInt(m[2]);
|
|
33
|
+
const age = (Date.now() - mtimeMs) / 86400000;
|
|
34
|
+
if (op === "+") return age > days;
|
|
35
|
+
if (op === "-") return age < days;
|
|
36
|
+
return Math.floor(age) === days;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* ------------------------------------------------------------------ */
|
|
40
|
+
/* Commands */
|
|
41
|
+
/* ------------------------------------------------------------------ */
|
|
42
|
+
|
|
43
|
+
const find_cmd: BuiltinFn = async (args, ctx) => {
|
|
44
|
+
let searchDir = ctx.cwd;
|
|
45
|
+
let namePattern = "";
|
|
46
|
+
let inamePattern = "";
|
|
47
|
+
let pathPattern = "";
|
|
48
|
+
let typeFilter = "";
|
|
49
|
+
let maxDepth = Infinity;
|
|
50
|
+
let minDepth = 0;
|
|
51
|
+
let sizeFilter = "";
|
|
52
|
+
let mtimeFilter = "";
|
|
53
|
+
let execCmd = "";
|
|
54
|
+
let execArgs: string[] = [];
|
|
55
|
+
let deleteMode = false;
|
|
56
|
+
let print0 = false;
|
|
57
|
+
let printMode = true;
|
|
58
|
+
let emptyFilter = false;
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < args.length; i++) {
|
|
61
|
+
const a = args[i];
|
|
62
|
+
if (a === "-name" && i + 1 < args.length) {
|
|
63
|
+
namePattern = args[++i];
|
|
64
|
+
} else if (a === "-iname" && i + 1 < args.length) {
|
|
65
|
+
inamePattern = args[++i];
|
|
66
|
+
} else if (a === "-path" || (a === "-wholename" && i + 1 < args.length)) {
|
|
67
|
+
pathPattern = args[++i];
|
|
68
|
+
} else if (a === "-type" && i + 1 < args.length) {
|
|
69
|
+
typeFilter = args[++i];
|
|
70
|
+
} else if (a === "-maxdepth" && i + 1 < args.length) {
|
|
71
|
+
maxDepth = parseInt(args[++i]);
|
|
72
|
+
} else if (a === "-mindepth" && i + 1 < args.length) {
|
|
73
|
+
minDepth = parseInt(args[++i]);
|
|
74
|
+
} else if (a === "-size" && i + 1 < args.length) {
|
|
75
|
+
sizeFilter = args[++i];
|
|
76
|
+
} else if (a === "-mtime" && i + 1 < args.length) {
|
|
77
|
+
mtimeFilter = args[++i];
|
|
78
|
+
} else if (a === "-empty") {
|
|
79
|
+
emptyFilter = true;
|
|
80
|
+
} else if (a === "-delete") {
|
|
81
|
+
deleteMode = true;
|
|
82
|
+
printMode = false;
|
|
83
|
+
} else if (a === "-print0") {
|
|
84
|
+
print0 = true;
|
|
85
|
+
} else if (a === "-print") {
|
|
86
|
+
printMode = true;
|
|
87
|
+
} else if (a === "-exec") {
|
|
88
|
+
const cmdParts: string[] = [];
|
|
89
|
+
i++;
|
|
90
|
+
while (i < args.length && args[i] !== ";") {
|
|
91
|
+
cmdParts.push(args[i]);
|
|
92
|
+
i++;
|
|
93
|
+
}
|
|
94
|
+
if (cmdParts.length > 0) {
|
|
95
|
+
execCmd = cmdParts[0];
|
|
96
|
+
execArgs = cmdParts.slice(1);
|
|
97
|
+
printMode = false;
|
|
98
|
+
}
|
|
99
|
+
} else if (!a.startsWith("-")) {
|
|
100
|
+
searchDir = resolvePath(a, ctx.cwd);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const nameRe = namePattern
|
|
105
|
+
? new RegExp("^" + globToRegex(namePattern) + "$")
|
|
106
|
+
: null;
|
|
107
|
+
const inameRe = inamePattern
|
|
108
|
+
? new RegExp("^" + globToRegex(inamePattern) + "$", "i")
|
|
109
|
+
: null;
|
|
110
|
+
const pathRe = pathPattern ? new RegExp(globToRegex(pathPattern)) : null;
|
|
111
|
+
|
|
112
|
+
const results: string[] = [];
|
|
113
|
+
let execOut = "";
|
|
114
|
+
|
|
115
|
+
const walk = (dir: string, depth: number) => {
|
|
116
|
+
if (depth > maxDepth) return;
|
|
117
|
+
try {
|
|
118
|
+
for (const name of ctx.volume.readdirSync(dir)) {
|
|
119
|
+
const full = dir === "/" ? `/${name}` : `${dir}/${name}`;
|
|
120
|
+
try {
|
|
121
|
+
const st = ctx.volume.statSync(full);
|
|
122
|
+
const isDir = st.isDirectory();
|
|
123
|
+
const isFile = st.isFile();
|
|
124
|
+
|
|
125
|
+
if (depth >= minDepth) {
|
|
126
|
+
let match = true;
|
|
127
|
+
if (typeFilter) {
|
|
128
|
+
if (typeFilter === "f" && !isFile) match = false;
|
|
129
|
+
if (typeFilter === "d" && !isDir) match = false;
|
|
130
|
+
}
|
|
131
|
+
if (nameRe && !nameRe.test(name)) match = false;
|
|
132
|
+
if (inameRe && !inameRe.test(name)) match = false;
|
|
133
|
+
if (pathRe && !pathRe.test(full)) match = false;
|
|
134
|
+
if (sizeFilter && isFile) {
|
|
135
|
+
const fileSize = ctx.volume.readFileSync(full).length;
|
|
136
|
+
if (!matchSize(fileSize, sizeFilter)) match = false;
|
|
137
|
+
}
|
|
138
|
+
if (mtimeFilter) {
|
|
139
|
+
const mtime = st.mtimeMs || Date.now();
|
|
140
|
+
if (!matchMtime(mtime, mtimeFilter)) match = false;
|
|
141
|
+
}
|
|
142
|
+
if (emptyFilter) {
|
|
143
|
+
if (isDir) {
|
|
144
|
+
try {
|
|
145
|
+
if (ctx.volume.readdirSync(full).length > 0) match = false;
|
|
146
|
+
} catch {
|
|
147
|
+
match = false;
|
|
148
|
+
}
|
|
149
|
+
} else if (isFile) {
|
|
150
|
+
if (ctx.volume.readFileSync(full).length > 0) match = false;
|
|
151
|
+
} else match = false;
|
|
152
|
+
}
|
|
153
|
+
if (match) results.push(full);
|
|
154
|
+
}
|
|
155
|
+
if (isDir) walk(full, depth + 1);
|
|
156
|
+
} catch {
|
|
157
|
+
/* skip */
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
/* skip */
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
walk(searchDir, 1);
|
|
166
|
+
|
|
167
|
+
if (deleteMode) {
|
|
168
|
+
for (const path of results.reverse()) {
|
|
169
|
+
try {
|
|
170
|
+
const st = ctx.volume.statSync(path);
|
|
171
|
+
if (st.isDirectory()) ctx.volume.rmdirSync(path);
|
|
172
|
+
else ctx.volume.unlinkSync(path);
|
|
173
|
+
} catch {
|
|
174
|
+
/* */
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return ok();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (execCmd) {
|
|
181
|
+
for (const path of results) {
|
|
182
|
+
const expandedArgs = execArgs.map((a) => (a === "{}" ? path : a));
|
|
183
|
+
const fullCmd = [execCmd, ...expandedArgs].join(" ");
|
|
184
|
+
const result = await ctx.exec(fullCmd, { cwd: ctx.cwd, env: ctx.env });
|
|
185
|
+
execOut += result.stdout;
|
|
186
|
+
}
|
|
187
|
+
return ok(execOut);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (print0) return ok(results.join("\0"));
|
|
191
|
+
if (printMode) return ok(results.join("\n") + (results.length ? "\n" : ""));
|
|
192
|
+
return ok();
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const xargs_cmd: BuiltinFn = async (args, ctx, stdin) => {
|
|
196
|
+
if (!stdin) return ok();
|
|
197
|
+
|
|
198
|
+
let maxArgs = Infinity;
|
|
199
|
+
let placeholder = "";
|
|
200
|
+
let nullDelim = false;
|
|
201
|
+
const cmdParts: string[] = [];
|
|
202
|
+
|
|
203
|
+
for (let i = 0; i < args.length; i++) {
|
|
204
|
+
if (args[i] === "-n" && i + 1 < args.length)
|
|
205
|
+
maxArgs = parseInt(args[++i]) || 1;
|
|
206
|
+
else if (args[i] === "-I" && i + 1 < args.length) placeholder = args[++i];
|
|
207
|
+
else if (args[i] === "-0" || args[i] === "--null") nullDelim = true;
|
|
208
|
+
else if (args[i] === "-t") {
|
|
209
|
+
/* */
|
|
210
|
+
} else cmdParts.push(args[i]);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (cmdParts.length === 0) cmdParts.push("echo");
|
|
214
|
+
|
|
215
|
+
const delim = nullDelim ? "\0" : /\s+/;
|
|
216
|
+
const items = stdin.trim().split(delim).filter(Boolean);
|
|
217
|
+
const cmd = cmdParts.join(" ");
|
|
218
|
+
let out = "";
|
|
219
|
+
let err = "";
|
|
220
|
+
let lastCode = 0;
|
|
221
|
+
|
|
222
|
+
if (placeholder) {
|
|
223
|
+
for (const item of items) {
|
|
224
|
+
const expanded = cmd.replace(
|
|
225
|
+
new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
|
|
226
|
+
item,
|
|
227
|
+
);
|
|
228
|
+
const result = await ctx.exec(expanded, { cwd: ctx.cwd, env: ctx.env });
|
|
229
|
+
out += result.stdout;
|
|
230
|
+
err += result.stderr;
|
|
231
|
+
lastCode = result.exitCode;
|
|
232
|
+
}
|
|
233
|
+
} else if (maxArgs < Infinity) {
|
|
234
|
+
for (let i = 0; i < items.length; i += maxArgs) {
|
|
235
|
+
const batch = items.slice(i, i + maxArgs).join(" ");
|
|
236
|
+
const result = await ctx.exec(`${cmd} ${batch}`, {
|
|
237
|
+
cwd: ctx.cwd,
|
|
238
|
+
env: ctx.env,
|
|
239
|
+
});
|
|
240
|
+
out += result.stdout;
|
|
241
|
+
err += result.stderr;
|
|
242
|
+
lastCode = result.exitCode;
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
const result = await ctx.exec(`${cmd} ${items.join(" ")}`, {
|
|
246
|
+
cwd: ctx.cwd,
|
|
247
|
+
env: ctx.env,
|
|
248
|
+
});
|
|
249
|
+
out += result.stdout;
|
|
250
|
+
err += result.stderr;
|
|
251
|
+
lastCode = result.exitCode;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { stdout: out, stderr: err, exitCode: lastCode };
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/* ------------------------------------------------------------------ */
|
|
258
|
+
/* Registry */
|
|
259
|
+
/* ------------------------------------------------------------------ */
|
|
260
|
+
|
|
261
|
+
export const searchCommands: [string, BuiltinFn][] = [
|
|
262
|
+
["find", find_cmd],
|
|
263
|
+
["xargs", xargs_cmd],
|
|
264
|
+
];
|