@peiyanlu/cli-utils 0.0.3 → 0.0.4

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.
@@ -135,26 +135,28 @@ const parseGitHubRepo = (url) => {
135
135
  const eol = (n = 1) => node_os.EOL.repeat(n);
136
136
 
137
137
  //#endregion
138
- //#region src/shell.ts
138
+ //#region src/styleText.ts
139
139
  const dim = (text) => (0, node_util.styleText)(["dim"], text);
140
140
  const red = (text) => (0, node_util.styleText)(["red"], text);
141
- const yellow = (text) => (0, node_util.styleText)(["yellow"], text);
142
- const underline = (text) => (0, node_util.styleText)(["underline"], text);
141
+
142
+ //#endregion
143
+ //#region src/shell.ts
144
+ /** 异步执行 `spawn` 获取字符串类型的结果 */
143
145
  const spawnAsync = (cmd, args, options) => {
144
- return new Promise((resolve$1) => {
146
+ return new Promise((resolve$2) => {
145
147
  const { trim, error, dryRun, ...others } = options ?? {};
146
- const fullCmd = [cmd, ...args].join(" ");
148
+ const fullCmd = stringifyArgs([cmd, ...args]);
147
149
  if (dryRun) {
148
150
  console.log(`${dim("[dry-run]")} ${fullCmd}`);
149
- return resolve$1(void 0);
151
+ return resolve$2(void 0);
150
152
  }
151
153
  const child = (0, node_child_process.spawn)(cmd, args, { ...others });
152
154
  let stdout = "";
153
- child.stdout?.setEncoding("utf-8");
155
+ child.stdout.setEncoding("utf-8");
154
156
  child.stdout?.on("data", (data) => stdout += trim ? data.trim() : data);
155
157
  let stderr = "";
156
- child.stderr?.setEncoding("utf-8");
157
- child.stderr?.on("data", (data) => stderr += trim ? data.trim() : data);
158
+ child.stderr.setEncoding("utf-8");
159
+ child.stderr.on("data", (data) => stderr += trim ? data.trim() : data);
158
160
  child.on("close", (code) => {
159
161
  if (stderr) {
160
162
  const err = `${red("spawnAsync")} ${dim(fullCmd)} ${stderr}`;
@@ -165,38 +167,69 @@ const spawnAsync = (cmd, args, options) => {
165
167
  case "throw": throw new Error(err);
166
168
  }
167
169
  }
168
- resolve$1(0 === code ? stdout : void 0);
170
+ resolve$2(0 === code ? stdout : void 0);
169
171
  });
170
172
  });
171
173
  };
172
- const execAsync = (cmd, options) => {
173
- return new Promise((resolve$1) => {
174
+ /** 异步执行 `exec` 获取字符串类型的结果 */
175
+ const execAsync = (cmd, argsOrOptions, maybeOptions) => {
176
+ return new Promise((resolve$2) => {
177
+ let command;
178
+ let options;
179
+ if (Array.isArray(argsOrOptions)) {
180
+ command = stringifyArgs([cmd, ...argsOrOptions]);
181
+ options = maybeOptions;
182
+ } else {
183
+ command = cmd;
184
+ options = argsOrOptions;
185
+ }
174
186
  const { trim, dryRun, error, ...others } = options ?? {};
175
187
  if (dryRun) {
176
- console.log(`${dim("[dry-run]")} ${cmd}`);
177
- return resolve$1(void 0);
188
+ console.log(`${dim("[dry-run]")} ${command}`);
189
+ return resolve$2(void 0);
178
190
  }
179
- (0, node_child_process.exec)(cmd, { ...others }, (err, stdout) => {
180
- if (err) {
181
- const msg = `${red("execAsync")} ${dim(cmd)} ${err.message}`;
191
+ (0, node_child_process.exec)(command, { ...others }, (stderr, stdout) => {
192
+ if (stderr) {
193
+ const err = `${red("execAsync")} ${dim(command)} ${stderr.message}`;
182
194
  switch (error) {
183
195
  case "log":
184
- console.error(msg);
196
+ console.error(err);
185
197
  break;
186
- case "throw": throw new Error(msg);
198
+ case "throw": throw new Error(err);
187
199
  }
188
200
  }
189
- resolve$1(err ? void 0 : trim ? stdout.trim() : stdout);
201
+ resolve$2(stderr ? void 0 : trim ? stdout.trim() : stdout);
190
202
  });
191
203
  });
192
204
  };
205
+ /** 基于 {@link spawnAsync} 实现 */
193
206
  const runGit = async (args, options = { trim: true }) => {
194
207
  return spawnAsync("git", args, options);
195
208
  };
209
+ /** 基于 {@link execAsync} 实现 */
196
210
  const runNpm = (args, options = { trim: true }) => {
197
- return execAsync(["npm", ...args].join(" "), options);
211
+ return execAsync("npm", args, options);
212
+ };
213
+ /** 基于 {@link spawnSync} 实现 */
214
+ const runGitSync = (args, options) => {
215
+ const { stdout } = (0, node_child_process.spawnSync)("git", args, {
216
+ encoding: "utf-8",
217
+ ...options
218
+ });
219
+ return stdout.toString().trim();
220
+ };
221
+ /** 基于 {@link execSync} 实现 */
222
+ const runNpmSync = (args, options) => {
223
+ return (0, node_child_process.execSync)(stringifyArgs(["npm", ...args]), {
224
+ encoding: "utf-8",
225
+ ...options
226
+ }).toString().trim();
198
227
  };
199
- const fixArgs = (args) => args.trim() ? args.trim().split(" ") : [];
228
+ /** 将字符串以空格分割为数组 */
229
+ const parseArgs = (args) => args.trim() ? args.trim().split(" ") : [];
230
+ /** 将数组以空格拼接为字符串 */
231
+ const stringifyArgs = (args) => args.length ? args.join(" ") : "";
232
+ /** 支持所有支持 `--version` 命令的脚本查看版本 */
200
233
  const checkVersion = async (cmd) => {
201
234
  return execAsync(`${cmd} --version`);
202
235
  };
@@ -234,14 +267,16 @@ function joinUrl(input) {
234
267
 
235
268
  //#endregion
236
269
  //#region src/git.ts
270
+ /** 判断指定目录是否是 git 仓库 */
237
271
  const isGitRepo = async (dir) => {
238
- return !!await runGit([
272
+ return "true" === await runGit([
239
273
  "-C",
240
- dir ? `./${dir}` : ".",
274
+ (0, node_path.resolve)(process.cwd(), dir || "."),
241
275
  "rev-parse",
242
276
  "--is-inside-work-tree"
243
277
  ]);
244
278
  };
279
+ /** 获取指定的 git 配置 */
245
280
  const getGitConfig = (key, global = true) => {
246
281
  return runGit([
247
282
  "config",
@@ -249,6 +284,7 @@ const getGitConfig = (key, global = true) => {
249
284
  key
250
285
  ]);
251
286
  };
287
+ /** 获取 git 远程地址 */
252
288
  const getGitRemoteUrl = async (remoteName = "origin") => {
253
289
  return runGit([
254
290
  "remote",
@@ -263,6 +299,7 @@ const getGitRemoteUrl = async (remoteName = "origin") => {
263
299
 
264
300
  //#endregion
265
301
  //#region src/npm.ts
302
+ /** 获取指定包的版本 */
266
303
  const pkgVersion = (pkg) => {
267
304
  return runNpm([
268
305
  "view",
@@ -278,13 +315,11 @@ exports.PkgManager = PkgManager;
278
315
  exports.YesOrNo = YesOrNo;
279
316
  exports.checkVersion = checkVersion;
280
317
  exports.copyDirAsync = copyDirAsync;
281
- exports.dim = dim;
282
318
  exports.editFile = editFile;
283
319
  exports.editJsonFile = editJsonFile;
284
320
  exports.emptyDir = emptyDir;
285
321
  exports.eol = eol;
286
322
  exports.execAsync = execAsync;
287
- exports.fixArgs = fixArgs;
288
323
  exports.getGitConfig = getGitConfig;
289
324
  exports.getGitRemoteUrl = getGitRemoteUrl;
290
325
  exports.isEmpty = isEmpty;
@@ -292,17 +327,18 @@ exports.isGitRepo = isGitRepo;
292
327
  exports.isTestFile = isTestFile;
293
328
  exports.isValidPackageName = isValidPackageName;
294
329
  exports.joinUrl = joinUrl;
330
+ exports.parseArgs = parseArgs;
295
331
  exports.parseGitHubRepo = parseGitHubRepo;
296
332
  exports.pkgFromUserAgent = pkgFromUserAgent;
297
333
  exports.pkgVersion = pkgVersion;
298
334
  exports.readJsonFile = readJsonFile;
299
335
  exports.readSubDirs = readSubDirs;
300
- exports.red = red;
301
336
  exports.runCliForTest = runCliForTest;
302
337
  exports.runGit = runGit;
338
+ exports.runGitSync = runGitSync;
303
339
  exports.runNpm = runNpm;
340
+ exports.runNpmSync = runNpmSync;
304
341
  exports.spawnAsync = spawnAsync;
342
+ exports.stringifyArgs = stringifyArgs;
305
343
  exports.toValidPackageName = toValidPackageName;
306
- exports.toValidProjectName = toValidProjectName;
307
- exports.underline = underline;
308
- exports.yellow = yellow;
344
+ exports.toValidProjectName = toValidProjectName;
@@ -1,5 +1,6 @@
1
+ import { ExecOptionsWithStringEncoding, SpawnOptionsWithoutStdio } from "node:child_process";
1
2
  import * as child_process0 from "child_process";
2
- import { ExecOptions, SpawnOptions, SpawnSyncOptionsWithStringEncoding } from "child_process";
3
+ import { ExecSyncOptionsWithStringEncoding, SpawnSyncOptionsWithStringEncoding } from "child_process";
3
4
 
4
5
  //#region src/enums.d.ts
5
6
  declare enum PkgManager {
@@ -38,12 +39,15 @@ interface PkgInfo {
38
39
  version: string;
39
40
  }
40
41
  interface ExecResultOptions {
42
+ /** 去掉结果的首尾空格 */
41
43
  trim?: boolean;
44
+ /** 仅打印命令,不实际执行命令 */
42
45
  dryRun?: boolean;
46
+ /** log: 打印错误信息,返回 undefined; throw: 抛出错误; ignore: 返回 undefined */
43
47
  error?: 'log' | 'throw' | 'ignore';
44
48
  }
45
- type SpawnAsyncOptions<T = SpawnOptions> = T & ExecResultOptions;
46
- type ExecAsyncOptions<T = ExecOptions> = T & ExecResultOptions;
49
+ type SpawnAsyncOptions = SpawnOptionsWithoutStdio & ExecResultOptions;
50
+ type ExecAsyncOptions = ExecOptionsWithStringEncoding & ExecResultOptions;
47
51
  //#endregion
48
52
  //#region src/utils.d.ts
49
53
  declare const isValidPackageName: (packageName: string) => boolean;
@@ -68,15 +72,27 @@ declare const parseGitHubRepo: (url: string) => string[];
68
72
  declare const eol: (n?: number) => string;
69
73
  //#endregion
70
74
  //#region src/shell.d.ts
71
- declare const dim: (text: string) => string;
72
- declare const red: (text: string) => string;
73
- declare const yellow: (text: string) => string;
74
- declare const underline: (text: string) => string;
75
- declare const spawnAsync: <T = SpawnOptions>(cmd: string, args: string[], options?: SpawnAsyncOptions<T>) => Promise<string | undefined>;
76
- declare const execAsync: <T = ExecOptions>(cmd: string, options?: ExecAsyncOptions<T>) => Promise<string | undefined>;
75
+ /** 异步执行 `spawn` 获取字符串类型的结果 */
76
+ declare const spawnAsync: (cmd: string, args: string[], options?: SpawnAsyncOptions) => Promise<string | undefined>;
77
+ type ExecAsync = {
78
+ (cmd: string, options?: ExecAsyncOptions): Promise<string | undefined>;
79
+ (cmd: string, args: string[], options?: ExecAsyncOptions): Promise<string | undefined>;
80
+ };
81
+ /** 异步执行 `exec` 获取字符串类型的结果 */
82
+ declare const execAsync: ExecAsync;
83
+ /** 基于 {@link spawnAsync} 实现 */
77
84
  declare const runGit: (args: string[], options?: SpawnAsyncOptions) => Promise<string | undefined>;
85
+ /** 基于 {@link execAsync} 实现 */
78
86
  declare const runNpm: (args: string[], options?: ExecAsyncOptions) => Promise<string | undefined>;
79
- declare const fixArgs: (args: string) => string[];
87
+ /** 基于 {@link spawnSync} 实现 */
88
+ declare const runGitSync: (args: string[], options?: SpawnSyncOptionsWithStringEncoding) => string;
89
+ /** 基于 {@link execSync} 实现 */
90
+ declare const runNpmSync: (args: string[], options?: ExecSyncOptionsWithStringEncoding) => string;
91
+ /** 将字符串以空格分割为数组 */
92
+ declare const parseArgs: (args: string) => string[];
93
+ /** 将数组以空格拼接为字符串 */
94
+ declare const stringifyArgs: (args: string[]) => string;
95
+ /** 支持所有支持 `--version` 命令的脚本查看版本 */
80
96
  declare const checkVersion: (cmd: string) => Promise<string | undefined>;
81
97
  //#endregion
82
98
  //#region src/joinUrl.d.ts
@@ -84,11 +100,15 @@ declare function joinUrl(...args: string[]): string;
84
100
  declare function joinUrl(input: readonly string[]): string;
85
101
  //#endregion
86
102
  //#region src/git.d.ts
103
+ /** 判断指定目录是否是 git 仓库 */
87
104
  declare const isGitRepo: (dir?: string) => Promise<boolean>;
105
+ /** 获取指定的 git 配置 */
88
106
  declare const getGitConfig: (key: string, global?: boolean) => Promise<string | undefined>;
107
+ /** 获取 git 远程地址 */
89
108
  declare const getGitRemoteUrl: (remoteName?: string) => Promise<string | undefined>;
90
109
  //#endregion
91
110
  //#region src/npm.d.ts
111
+ /** 获取指定包的版本 */
92
112
  declare const pkgVersion: (pkg: string) => Promise<string | undefined>;
93
113
  //#endregion
94
- export { CliOptions, ConfirmResult, CopyOptions, ExecAsyncOptions, ExecResultOptions, HttpLibrary, PkgInfo, PkgManager, SpawnAsyncOptions, YesOrNo, checkVersion, copyDirAsync, dim, editFile, editJsonFile, emptyDir, eol, execAsync, fixArgs, getGitConfig, getGitRemoteUrl, isEmpty, isGitRepo, isTestFile, isValidPackageName, joinUrl, parseGitHubRepo, pkgFromUserAgent, pkgVersion, readJsonFile, readSubDirs, red, runCliForTest, runGit, runNpm, spawnAsync, toValidPackageName, toValidProjectName, underline, yellow };
114
+ export { CliOptions, ConfirmResult, CopyOptions, ExecAsyncOptions, ExecResultOptions, HttpLibrary, PkgInfo, PkgManager, SpawnAsyncOptions, YesOrNo, checkVersion, copyDirAsync, editFile, editJsonFile, emptyDir, eol, execAsync, getGitConfig, getGitRemoteUrl, isEmpty, isGitRepo, isTestFile, isValidPackageName, joinUrl, parseArgs, parseGitHubRepo, pkgFromUserAgent, pkgVersion, readJsonFile, readSubDirs, runCliForTest, runGit, runGitSync, runNpm, runNpmSync, spawnAsync, stringifyArgs, toValidPackageName, toValidProjectName };
@@ -1,5 +1,6 @@
1
+ import { ExecOptionsWithStringEncoding, SpawnOptionsWithoutStdio } from "node:child_process";
1
2
  import * as child_process0 from "child_process";
2
- import { ExecOptions, SpawnOptions, SpawnSyncOptionsWithStringEncoding } from "child_process";
3
+ import { ExecSyncOptionsWithStringEncoding, SpawnSyncOptionsWithStringEncoding } from "child_process";
3
4
 
4
5
  //#region src/enums.d.ts
5
6
  declare enum PkgManager {
@@ -38,12 +39,15 @@ interface PkgInfo {
38
39
  version: string;
39
40
  }
40
41
  interface ExecResultOptions {
42
+ /** 去掉结果的首尾空格 */
41
43
  trim?: boolean;
44
+ /** 仅打印命令,不实际执行命令 */
42
45
  dryRun?: boolean;
46
+ /** log: 打印错误信息,返回 undefined; throw: 抛出错误; ignore: 返回 undefined */
43
47
  error?: 'log' | 'throw' | 'ignore';
44
48
  }
45
- type SpawnAsyncOptions<T = SpawnOptions> = T & ExecResultOptions;
46
- type ExecAsyncOptions<T = ExecOptions> = T & ExecResultOptions;
49
+ type SpawnAsyncOptions = SpawnOptionsWithoutStdio & ExecResultOptions;
50
+ type ExecAsyncOptions = ExecOptionsWithStringEncoding & ExecResultOptions;
47
51
  //#endregion
48
52
  //#region src/utils.d.ts
49
53
  declare const isValidPackageName: (packageName: string) => boolean;
@@ -68,15 +72,27 @@ declare const parseGitHubRepo: (url: string) => string[];
68
72
  declare const eol: (n?: number) => string;
69
73
  //#endregion
70
74
  //#region src/shell.d.ts
71
- declare const dim: (text: string) => string;
72
- declare const red: (text: string) => string;
73
- declare const yellow: (text: string) => string;
74
- declare const underline: (text: string) => string;
75
- declare const spawnAsync: <T = SpawnOptions>(cmd: string, args: string[], options?: SpawnAsyncOptions<T>) => Promise<string | undefined>;
76
- declare const execAsync: <T = ExecOptions>(cmd: string, options?: ExecAsyncOptions<T>) => Promise<string | undefined>;
75
+ /** 异步执行 `spawn` 获取字符串类型的结果 */
76
+ declare const spawnAsync: (cmd: string, args: string[], options?: SpawnAsyncOptions) => Promise<string | undefined>;
77
+ type ExecAsync = {
78
+ (cmd: string, options?: ExecAsyncOptions): Promise<string | undefined>;
79
+ (cmd: string, args: string[], options?: ExecAsyncOptions): Promise<string | undefined>;
80
+ };
81
+ /** 异步执行 `exec` 获取字符串类型的结果 */
82
+ declare const execAsync: ExecAsync;
83
+ /** 基于 {@link spawnAsync} 实现 */
77
84
  declare const runGit: (args: string[], options?: SpawnAsyncOptions) => Promise<string | undefined>;
85
+ /** 基于 {@link execAsync} 实现 */
78
86
  declare const runNpm: (args: string[], options?: ExecAsyncOptions) => Promise<string | undefined>;
79
- declare const fixArgs: (args: string) => string[];
87
+ /** 基于 {@link spawnSync} 实现 */
88
+ declare const runGitSync: (args: string[], options?: SpawnSyncOptionsWithStringEncoding) => string;
89
+ /** 基于 {@link execSync} 实现 */
90
+ declare const runNpmSync: (args: string[], options?: ExecSyncOptionsWithStringEncoding) => string;
91
+ /** 将字符串以空格分割为数组 */
92
+ declare const parseArgs: (args: string) => string[];
93
+ /** 将数组以空格拼接为字符串 */
94
+ declare const stringifyArgs: (args: string[]) => string;
95
+ /** 支持所有支持 `--version` 命令的脚本查看版本 */
80
96
  declare const checkVersion: (cmd: string) => Promise<string | undefined>;
81
97
  //#endregion
82
98
  //#region src/joinUrl.d.ts
@@ -84,11 +100,15 @@ declare function joinUrl(...args: string[]): string;
84
100
  declare function joinUrl(input: readonly string[]): string;
85
101
  //#endregion
86
102
  //#region src/git.d.ts
103
+ /** 判断指定目录是否是 git 仓库 */
87
104
  declare const isGitRepo: (dir?: string) => Promise<boolean>;
105
+ /** 获取指定的 git 配置 */
88
106
  declare const getGitConfig: (key: string, global?: boolean) => Promise<string | undefined>;
107
+ /** 获取 git 远程地址 */
89
108
  declare const getGitRemoteUrl: (remoteName?: string) => Promise<string | undefined>;
90
109
  //#endregion
91
110
  //#region src/npm.d.ts
111
+ /** 获取指定包的版本 */
92
112
  declare const pkgVersion: (pkg: string) => Promise<string | undefined>;
93
113
  //#endregion
94
- export { CliOptions, ConfirmResult, CopyOptions, ExecAsyncOptions, ExecResultOptions, HttpLibrary, PkgInfo, PkgManager, SpawnAsyncOptions, YesOrNo, checkVersion, copyDirAsync, dim, editFile, editJsonFile, emptyDir, eol, execAsync, fixArgs, getGitConfig, getGitRemoteUrl, isEmpty, isGitRepo, isTestFile, isValidPackageName, joinUrl, parseGitHubRepo, pkgFromUserAgent, pkgVersion, readJsonFile, readSubDirs, red, runCliForTest, runGit, runNpm, spawnAsync, toValidPackageName, toValidProjectName, underline, yellow };
114
+ export { CliOptions, ConfirmResult, CopyOptions, ExecAsyncOptions, ExecResultOptions, HttpLibrary, PkgInfo, PkgManager, SpawnAsyncOptions, YesOrNo, checkVersion, copyDirAsync, editFile, editJsonFile, emptyDir, eol, execAsync, getGitConfig, getGitRemoteUrl, isEmpty, isGitRepo, isTestFile, isValidPackageName, joinUrl, parseArgs, parseGitHubRepo, pkgFromUserAgent, pkgVersion, readJsonFile, readSubDirs, runCliForTest, runGit, runGitSync, runNpm, runNpmSync, spawnAsync, stringifyArgs, toValidPackageName, toValidProjectName };
@@ -1,4 +1,4 @@
1
- import { exec, spawn, spawnSync } from "node:child_process";
1
+ import { exec, execSync, spawn, spawnSync } from "node:child_process";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { copyFile, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
4
4
  import { EOL } from "node:os";
@@ -135,26 +135,28 @@ const parseGitHubRepo = (url) => {
135
135
  const eol = (n = 1) => EOL.repeat(n);
136
136
 
137
137
  //#endregion
138
- //#region src/shell.ts
138
+ //#region src/styleText.ts
139
139
  const dim = (text) => styleText(["dim"], text);
140
140
  const red = (text) => styleText(["red"], text);
141
- const yellow = (text) => styleText(["yellow"], text);
142
- const underline = (text) => styleText(["underline"], text);
141
+
142
+ //#endregion
143
+ //#region src/shell.ts
144
+ /** 异步执行 `spawn` 获取字符串类型的结果 */
143
145
  const spawnAsync = (cmd, args, options) => {
144
146
  return new Promise((resolve$1) => {
145
147
  const { trim, error, dryRun, ...others } = options ?? {};
146
- const fullCmd = [cmd, ...args].join(" ");
148
+ const fullCmd = stringifyArgs([cmd, ...args]);
147
149
  if (dryRun) {
148
150
  console.log(`${dim("[dry-run]")} ${fullCmd}`);
149
151
  return resolve$1(void 0);
150
152
  }
151
153
  const child = spawn(cmd, args, { ...others });
152
154
  let stdout = "";
153
- child.stdout?.setEncoding("utf-8");
155
+ child.stdout.setEncoding("utf-8");
154
156
  child.stdout?.on("data", (data) => stdout += trim ? data.trim() : data);
155
157
  let stderr = "";
156
- child.stderr?.setEncoding("utf-8");
157
- child.stderr?.on("data", (data) => stderr += trim ? data.trim() : data);
158
+ child.stderr.setEncoding("utf-8");
159
+ child.stderr.on("data", (data) => stderr += trim ? data.trim() : data);
158
160
  child.on("close", (code) => {
159
161
  if (stderr) {
160
162
  const err = `${red("spawnAsync")} ${dim(fullCmd)} ${stderr}`;
@@ -169,34 +171,65 @@ const spawnAsync = (cmd, args, options) => {
169
171
  });
170
172
  });
171
173
  };
172
- const execAsync = (cmd, options) => {
174
+ /** 异步执行 `exec` 获取字符串类型的结果 */
175
+ const execAsync = (cmd, argsOrOptions, maybeOptions) => {
173
176
  return new Promise((resolve$1) => {
177
+ let command;
178
+ let options;
179
+ if (Array.isArray(argsOrOptions)) {
180
+ command = stringifyArgs([cmd, ...argsOrOptions]);
181
+ options = maybeOptions;
182
+ } else {
183
+ command = cmd;
184
+ options = argsOrOptions;
185
+ }
174
186
  const { trim, dryRun, error, ...others } = options ?? {};
175
187
  if (dryRun) {
176
- console.log(`${dim("[dry-run]")} ${cmd}`);
188
+ console.log(`${dim("[dry-run]")} ${command}`);
177
189
  return resolve$1(void 0);
178
190
  }
179
- exec(cmd, { ...others }, (err, stdout) => {
180
- if (err) {
181
- const msg = `${red("execAsync")} ${dim(cmd)} ${err.message}`;
191
+ exec(command, { ...others }, (stderr, stdout) => {
192
+ if (stderr) {
193
+ const err = `${red("execAsync")} ${dim(command)} ${stderr.message}`;
182
194
  switch (error) {
183
195
  case "log":
184
- console.error(msg);
196
+ console.error(err);
185
197
  break;
186
- case "throw": throw new Error(msg);
198
+ case "throw": throw new Error(err);
187
199
  }
188
200
  }
189
- resolve$1(err ? void 0 : trim ? stdout.trim() : stdout);
201
+ resolve$1(stderr ? void 0 : trim ? stdout.trim() : stdout);
190
202
  });
191
203
  });
192
204
  };
205
+ /** 基于 {@link spawnAsync} 实现 */
193
206
  const runGit = async (args, options = { trim: true }) => {
194
207
  return spawnAsync("git", args, options);
195
208
  };
209
+ /** 基于 {@link execAsync} 实现 */
196
210
  const runNpm = (args, options = { trim: true }) => {
197
- return execAsync(["npm", ...args].join(" "), options);
211
+ return execAsync("npm", args, options);
212
+ };
213
+ /** 基于 {@link spawnSync} 实现 */
214
+ const runGitSync = (args, options) => {
215
+ const { stdout } = spawnSync("git", args, {
216
+ encoding: "utf-8",
217
+ ...options
218
+ });
219
+ return stdout.toString().trim();
220
+ };
221
+ /** 基于 {@link execSync} 实现 */
222
+ const runNpmSync = (args, options) => {
223
+ return execSync(stringifyArgs(["npm", ...args]), {
224
+ encoding: "utf-8",
225
+ ...options
226
+ }).toString().trim();
198
227
  };
199
- const fixArgs = (args) => args.trim() ? args.trim().split(" ") : [];
228
+ /** 将字符串以空格分割为数组 */
229
+ const parseArgs = (args) => args.trim() ? args.trim().split(" ") : [];
230
+ /** 将数组以空格拼接为字符串 */
231
+ const stringifyArgs = (args) => args.length ? args.join(" ") : "";
232
+ /** 支持所有支持 `--version` 命令的脚本查看版本 */
200
233
  const checkVersion = async (cmd) => {
201
234
  return execAsync(`${cmd} --version`);
202
235
  };
@@ -234,14 +267,16 @@ function joinUrl(input) {
234
267
 
235
268
  //#endregion
236
269
  //#region src/git.ts
270
+ /** 判断指定目录是否是 git 仓库 */
237
271
  const isGitRepo = async (dir) => {
238
- return !!await runGit([
272
+ return "true" === await runGit([
239
273
  "-C",
240
- dir ? `./${dir}` : ".",
274
+ resolve(process.cwd(), dir || "."),
241
275
  "rev-parse",
242
276
  "--is-inside-work-tree"
243
277
  ]);
244
278
  };
279
+ /** 获取指定的 git 配置 */
245
280
  const getGitConfig = (key, global = true) => {
246
281
  return runGit([
247
282
  "config",
@@ -249,6 +284,7 @@ const getGitConfig = (key, global = true) => {
249
284
  key
250
285
  ]);
251
286
  };
287
+ /** 获取 git 远程地址 */
252
288
  const getGitRemoteUrl = async (remoteName = "origin") => {
253
289
  return runGit([
254
290
  "remote",
@@ -263,6 +299,7 @@ const getGitRemoteUrl = async (remoteName = "origin") => {
263
299
 
264
300
  //#endregion
265
301
  //#region src/npm.ts
302
+ /** 获取指定包的版本 */
266
303
  const pkgVersion = (pkg) => {
267
304
  return runNpm([
268
305
  "view",
@@ -272,4 +309,4 @@ const pkgVersion = (pkg) => {
272
309
  };
273
310
 
274
311
  //#endregion
275
- export { ConfirmResult, HttpLibrary, PkgManager, YesOrNo, checkVersion, copyDirAsync, dim, editFile, editJsonFile, emptyDir, eol, execAsync, fixArgs, getGitConfig, getGitRemoteUrl, isEmpty, isGitRepo, isTestFile, isValidPackageName, joinUrl, parseGitHubRepo, pkgFromUserAgent, pkgVersion, readJsonFile, readSubDirs, red, runCliForTest, runGit, runNpm, spawnAsync, toValidPackageName, toValidProjectName, underline, yellow };
312
+ export { ConfirmResult, HttpLibrary, PkgManager, YesOrNo, checkVersion, copyDirAsync, editFile, editJsonFile, emptyDir, eol, execAsync, getGitConfig, getGitRemoteUrl, isEmpty, isGitRepo, isTestFile, isValidPackageName, joinUrl, parseArgs, parseGitHubRepo, pkgFromUserAgent, pkgVersion, readJsonFile, readSubDirs, runCliForTest, runGit, runGitSync, runNpm, runNpmSync, spawnAsync, stringifyArgs, toValidPackageName, toValidProjectName };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peiyanlu/cli-utils",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Shared utils for building interactive Node.js CLI applications.",
5
5
  "license": "MIT",
6
6
  "type": "module",