Skip to content

Commit 147f919

Browse files
committed
feat: add quoteShellArg function to process utilities
1 parent 0b66d76 commit 147f919

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

src/common/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export { linear, scale } from "./math";
44

55
export { parseKeyValuePairs, parseValueToBoolean } from "./parse";
66

7-
export { $ } from "./process";
7+
export { $, quoteShellArg } from "./process";
88

99
export { PromiseWithResolvers, createLock, createSingleton, sleep } from "./promise";
1010

src/common/process.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,23 @@ export function $(cmd: string | TemplateStringsArray, ...values: any[]) {
3030

3131
return ResultAsync.fromPromise(promise, errorToMessage(`Failed to execute command: ${cmd}`));
3232
}
33+
34+
const REGEXP_NULL_CHAR = /\x00+/g;
35+
const REGEXP_SAFE_CHARS = /^[A-Za-z0-9,:=_./-]+$/;
36+
const REGEXP_SINGLE_QUOTES = /'+/g;
37+
38+
export const quoteShellArg = (arg: string) => {
39+
if (!arg) return "''";
40+
41+
const cleaned = String(arg).replace(REGEXP_NULL_CHAR, "");
42+
43+
const matches = REGEXP_SAFE_CHARS.exec(cleaned);
44+
if (matches?.[0].length === cleaned.length) return cleaned;
45+
46+
const quoted = cleaned.replace(REGEXP_SINGLE_QUOTES, matched =>
47+
matched.length === 1 ? `'\\''` : `'"${matched}"'`,
48+
);
49+
const trimmed = `'${quoted}'`.replace(/^''/, "").replace(/''$/, "");
50+
51+
return trimmed;
52+
};

0 commit comments

Comments
 (0)