cross-spawn-esm 1.0.0 → 1.1.1

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 CHANGED
@@ -101,4 +101,84 @@ Github: <https://github.com/kevva/shebang-command>
101
101
  > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
102
102
  > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
103
103
  > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
104
- > THE SOFTWARE.
104
+ > THE SOFTWARE.
105
+
106
+ ## which
107
+
108
+ Github: <https://github.com/npm/node-which>
109
+
110
+ > The ISC License
111
+ >
112
+ > Copyright (c) Isaac Z. Schlueter and Contributors
113
+ >
114
+ > Permission to use, copy, modify, and/or distribute this software for any
115
+ > purpose with or without fee is hereby granted, provided that the above
116
+ > copyright notice and this permission notice appear in all copies.
117
+ >
118
+ > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119
+ > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
120
+ > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121
+ > ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
122
+ > WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
123
+ > ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
124
+ > IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
125
+
126
+ ## isexe
127
+
128
+ Github: <https://github.com/isaacs/isexe>
129
+
130
+ > # Blue Oak Model License
131
+ >
132
+ > Version 1.0.0
133
+ >
134
+ > ## Purpose
135
+ >
136
+ > This license gives everyone as much permission to work with
137
+ > this software as possible, while protecting contributors
138
+ > from liability.
139
+ >
140
+ > ## Acceptance
141
+ >
142
+ > In order to receive this license, you must agree to its
143
+ > rules. The rules of this license are both obligations
144
+ > under that agreement and conditions to your license.
145
+ > You must not do anything with this software that triggers
146
+ > a rule that you cannot or will not follow.
147
+ >
148
+ > ## Copyright
149
+ >
150
+ > Each contributor licenses you to do everything with this
151
+ > software that would otherwise infringe that contributor's
152
+ > copyright in it.
153
+ >
154
+ > ## Notices
155
+ >
156
+ > You must ensure that everyone who gets a copy of
157
+ > any part of this software from you, with or without
158
+ > changes, also gets the text of this license or a link to
159
+ > <https://blueoakcouncil.org/license/1.0.0>.
160
+ >
161
+ > ## Excuse
162
+ >
163
+ > If anyone notifies you in writing that you have not
164
+ > complied with [Notices](#notices), you can keep your
165
+ > license by taking all practical steps to comply within 30
166
+ > days after the notice. If you do not do so, your license
167
+ > ends immediately.
168
+ >
169
+ > ## Patent
170
+ >
171
+ > Each contributor licenses you to do everything with this
172
+ > software that would otherwise infringe any patent claims
173
+ > they can license or become able to license.
174
+ >
175
+ > ## Reliability
176
+ >
177
+ > No contributor can revoke this license.
178
+ >
179
+ > ## No Liability
180
+ >
181
+ > ***As far as the law allows, this software comes as is,
182
+ > without any warranty or condition, and no contributor
183
+ > will be liable to anyone for any damages related to this
184
+ > software or this license, under any kind of legal claim.***
package/README.md CHANGED
@@ -5,9 +5,6 @@
5
5
  <a href="https://github.com/Timbic/cross-spawn-esm"><img src="https://img.shields.io/badge/Github-gray.svg?logo=github" alt="github repo"></a>
6
6
  </p>
7
7
 
8
- > **Note:** This package is still in development and not recommended for production use yet. However, testing it in your projects is greatly
9
- > appreciated. If you find any errors, please open an issue - PRs are also welcomed!
10
-
11
8
  This is a "fork" of [cross-spawn](https://www.npmjs.com/package/cross-spawn?activeTab=readme) ( a cross-platform solution to node's spawn
12
9
  and spawnSync ) which ports its codebase to modern ESM and TypeScript.
13
10
 
@@ -65,7 +62,7 @@ const result = spawnSync("npm", ["list", "-g", "-depth", "0"], { stdio: "inherit
65
62
 
66
63
  - Overall smaller bundle size
67
64
  - Tree-shaking friendly
68
- - Fewer dependencies
65
+ - Zero dependencies
69
66
  - No need for an additional types package (`@types/cross-spawn`)
70
67
  - Modern codebase and active maintenance
71
68
  - Better documentation
@@ -126,7 +123,7 @@ import { _parse, _enoent } from "cross-spawn-esm";
126
123
  >
127
124
  > **After**: const parsed = _parse.parse(...)
128
125
 
129
- - New `_utils` object exposes all the lower-level helpers (`shebangCommand`, `readShebang`, `detectShebang`, `enterCwd`, `resolveCommand`,
126
+ - New `_utils` object exposes all the lower-level helpers (`shebangCommand`, `readShebang`, `detectShebang`, `resolveCommand`,
130
127
  `resolveCommandAttempt`, `escapeLineBreaks`, `escapeMetaChars`, `escapeCommand`, `escapeArgument`, `pathKey`) If you were relying on the
131
128
  original **cross-spawn** dependencies ( **path-key** and **shebang-command** ), their improved versions can be found in `_utils`.
132
129
 
package/dist/index.d.ts CHANGED
@@ -13,10 +13,6 @@ interface ParsedCommand {
13
13
  args: ReadonlyArray<string>;
14
14
  };
15
15
  }
16
- /**
17
- * Change the process working directory to `cwd`.
18
- */
19
- declare function enterCwd(cwd?: string): boolean;
20
16
  /**
21
17
  * Resolve `parsed.command` to an absolute file path by searching the
22
18
  * environment's `PATH`, using the custom `cwd` when one is set.
@@ -222,7 +218,6 @@ export declare const _utils: {
222
218
  shebangCommand: typeof shebangCommand;
223
219
  readShebang: typeof readShebang;
224
220
  detectShebang: typeof detectShebang;
225
- enterCwd: typeof enterCwd;
226
221
  resolveCommand: typeof resolveCommand;
227
222
  resolveCommandAttempt: typeof resolveCommandAttempt;
228
223
  escapeLineBreaks: typeof escapeLineBreaks;
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import cp from "node:child_process";
2
2
  import path from "node:path";
3
- import which from "which";
4
3
  import fs from "node:fs";
5
4
  //#region src/utils/constants.ts
6
5
  const _cwd = process.cwd();
@@ -18,35 +17,72 @@ function pathKey({ env = _env, platform = _platform }) {
18
17
  return platform === "win32" ? Object.keys(env).reverse().find((key) => key.toUpperCase() === "PATH") ?? "Path" : "PATH";
19
18
  }
20
19
  //#endregion
21
- //#region src/utils/resolve-command.ts
22
- function enterCwd(cwd) {
23
- if (cwd == null) return false;
20
+ //#region src/utils/isexe.ts
21
+ const execOther = 1;
22
+ const execGroup = 8;
23
+ const execOwner = 64;
24
+ const execOwnerOrGroup = 72;
25
+ function isInPathExt(file, pathExt) {
26
+ const extensions = pathExt.split(path.delimiter);
27
+ if (extensions.includes("")) return true;
28
+ return extensions.some((ext) => {
29
+ const e = ext.toLowerCase();
30
+ return e !== "" && file.slice(-e.length).toLowerCase() === e;
31
+ });
32
+ }
33
+ function isExecutableMode(stat) {
34
+ const myUid = process.getuid?.();
35
+ const myGroups = process.getgroups?.() ?? [];
36
+ const myGid = process.getgid?.() ?? myGroups[0];
37
+ if (myUid === void 0 || myGid === void 0) throw new Error("cannot get uid or gid");
38
+ const groups = /* @__PURE__ */ new Set([myGid, ...myGroups]);
39
+ const { mode, uid, gid } = stat;
40
+ return !!(mode & execOther || mode & execGroup && groups.has(gid) || mode & execOwner && uid === myUid || mode & execOwnerOrGroup && myUid === 0);
41
+ }
42
+ function isexeSync(file, { pathExt = process.env.PATHEXT ?? "" } = {}) {
24
43
  try {
25
- process.chdir(cwd);
26
- return true;
44
+ const stat = fs.statSync(file);
45
+ if (!stat.isFile()) return false;
46
+ return isWin ? isInPathExt(file, pathExt) : isExecutableMode(stat);
27
47
  } catch {
28
48
  return false;
29
49
  }
30
50
  }
51
+ //#endregion
52
+ //#region src/utils/which.ts
53
+ const pathSeparatorRegExp = new RegExp(`[${path.posix.sep}${path.sep === path.posix.sep ? "" : path.sep}]`.replace(/(\\)/g, "\\$1"));
54
+ function whichSync(command, { cwd = _cwd, path: optPath = _env.PATH, pathExt: optPathExt = _env.PATHEXT } = {}) {
55
+ const delimiter = path.delimiter;
56
+ const dirs = command.match(pathSeparatorRegExp) ? [""] : [...isWin ? [cwd] : [], ...(optPath ?? "").split(delimiter)];
57
+ const pathExtExe = isWin ? optPathExt ?? [
58
+ ".EXE",
59
+ ".CMD",
60
+ ".BAT",
61
+ ".COM"
62
+ ].join(delimiter) : void 0;
63
+ const extensions = pathExtExe?.split(delimiter).flatMap((ext) => [ext, ext.toLowerCase()]) ?? [""];
64
+ if (isWin && command.includes(".") && extensions[0] !== "") extensions.unshift("");
65
+ for (const dir of dirs) {
66
+ const base = path.resolve(cwd, dir === "" ? command : path.join(dir.replace(/^"(.*)"$/, "$1"), command));
67
+ for (const ext of extensions) {
68
+ const candidate = base + ext;
69
+ if (isexeSync(candidate, { pathExt: pathExtExe })) return candidate;
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ //#endregion
75
+ //#region src/utils/resolve-command.ts
31
76
  function resolveCommandAttempt(parsed, withoutPathExt) {
32
77
  const env = parsed.options.env ?? _env;
33
- const cwd = parsed.options.cwd?.toString();
34
- const switchCwd = process.chdir;
35
- const switched = cwd != null && process.chdir !== void 0 && !switchCwd?.disabled && enterCwd(cwd);
36
- try {
37
- const resolved = which.sync(parsed.command, {
38
- path: env[pathKey({ env })],
39
- pathExt: withoutPathExt ? path.delimiter : void 0
40
- });
41
- return path.resolve(cwd ?? "", resolved);
42
- } catch {
43
- return null;
44
- } finally {
45
- if (switched) process.chdir(_cwd);
46
- }
78
+ return whichSync(parsed.command, {
79
+ cwd: parsed.options.cwd?.toString(),
80
+ path: env[pathKey({ env })],
81
+ pathExt: withoutPathExt ? path.delimiter : void 0
82
+ });
47
83
  }
48
84
  function resolveCommand(parsed) {
49
- return resolveCommandAttempt(parsed) ?? resolveCommandAttempt(parsed, true);
85
+ return resolveCommandAttempt(parsed) ?? (isWin ? resolveCommandAttempt(parsed, true) : null);
50
86
  }
51
87
  //#endregion
52
88
  //#region src/enoent.ts
@@ -195,7 +231,6 @@ const _utils = {
195
231
  shebangCommand,
196
232
  readShebang,
197
233
  detectShebang,
198
- enterCwd,
199
234
  resolveCommand,
200
235
  resolveCommandAttempt,
201
236
  escapeLineBreaks,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cross-spawn-esm",
3
3
  "type": "module",
4
- "version": "1.0.0",
4
+ "version": "1.1.1",
5
5
  "description": "ESM version of cross-spawn package",
6
6
  "author": "Timur Bikmuhametov <tim.bic22@gmail.com>",
7
7
  "license": "MIT",
@@ -32,14 +32,10 @@
32
32
  "publishConfig": {
33
33
  "access": "public"
34
34
  },
35
- "dependencies": {
36
- "which": "7.0.0"
37
- },
38
35
  "devDependencies": {
39
36
  "@timbic/eslint-config": "1.2.2",
40
37
  "@timbic/prettier-config": "1.2.3",
41
38
  "@types/node": "26.6.1",
42
- "@types/which": "3.0.4",
43
39
  "bumpp": "12.3.0",
44
40
  "eslint": "10.10.0",
45
41
  "husky": "9.1.7",