cross-spawn-esm 0.0.1 → 1.1.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/README.md +2 -5
- package/dist/index.d.ts +0 -5
- package/dist/index.js +57 -22
- package/package.json +62 -68
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
|
-
-
|
|
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`, `
|
|
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/
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
26
|
-
return
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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,69 +1,63 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"pnpm fmt",
|
|
65
|
-
"pnpm lint:fix"
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
"packageManager": "pnpm@12.4.2"
|
|
69
|
-
}
|
|
2
|
+
"name": "cross-spawn-esm",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"description": "ESM version of cross-spawn package",
|
|
6
|
+
"author": "Timur Bikmuhametov <tim.bic22@gmail.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"cross-spawn",
|
|
10
|
+
"spawn",
|
|
11
|
+
"spawnSync",
|
|
12
|
+
"windows",
|
|
13
|
+
"cross-platform",
|
|
14
|
+
"path-ext",
|
|
15
|
+
"shebang",
|
|
16
|
+
"cmd",
|
|
17
|
+
"execute"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/Timbic/cross-spawn-esm.git"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@timbic/eslint-config": "1.2.2",
|
|
37
|
+
"@timbic/prettier-config": "1.2.3",
|
|
38
|
+
"@types/node": "26.6.1",
|
|
39
|
+
"bumpp": "12.3.0",
|
|
40
|
+
"eslint": "10.10.0",
|
|
41
|
+
"husky": "9.1.7",
|
|
42
|
+
"lint-staged": "17.5.1",
|
|
43
|
+
"prettier": "3.9.6",
|
|
44
|
+
"tsdown": "0.23.0",
|
|
45
|
+
"typescript": "6.0.3"
|
|
46
|
+
},
|
|
47
|
+
"lint-staged": {
|
|
48
|
+
"*/**/*.{js,ts,md,json}": [
|
|
49
|
+
"pnpm fmt",
|
|
50
|
+
"pnpm lint:fix"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"dev": "tsdown --watch",
|
|
55
|
+
"build": "tsdown",
|
|
56
|
+
"fmt": "prettier --cache --write .",
|
|
57
|
+
"fmt:chk": "prettier --check .",
|
|
58
|
+
"lint": "eslint --cache",
|
|
59
|
+
"lint:fix": "eslint --cache --fix",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"release": "bumpp"
|
|
62
|
+
}
|
|
63
|
+
}
|