@done-coding/cli-utils 0.5.0-alpha.0 → 0.7.0-alpha.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/es/index.mjs CHANGED
@@ -1,51 +1,54 @@
1
1
  #!/usr/bin/env node
2
- import O from "chalk";
3
- import { default as pt } from "chalk";
4
- import g from "node:path";
5
- import b, { existsSync as y, mkdirSync as H, writeFileSync as C, readFileSync as d } from "node:fs";
6
- import m from "crypto";
7
- import D from "prompts";
8
- import N from "yargs";
9
- import { hideBin as A } from "yargs/helpers";
10
- import { execSync as a } from "node:child_process";
11
- import v from "json5";
2
+ import m from "chalk";
3
+ import { default as oe } from "chalk";
4
+ import f from "node:path";
5
+ import u, { existsSync as p, mkdirSync as W, writeFileSync as b, readFileSync as v, rmSync as X } from "node:fs";
6
+ import _ from "crypto";
7
+ import q from "prompts";
8
+ import z from "yargs";
9
+ import { hideBin as Q } from "yargs/helpers";
10
+ import { execSync as g } from "node:child_process";
11
+ import j from "json5";
12
12
  export * from "json5";
13
- import { default as yt } from "json5";
14
- import u from "pinyin";
15
- import { default as Ct } from "lodash.get";
16
- import { default as $t } from "lodash.set";
17
- import { default as wt } from "lodash.curry";
18
- const c = Object.assign(
19
- (t, ...r) => console.log(...r.map((e) => O[t](e))),
13
+ import { default as ie } from "json5";
14
+ import Z from "lodash.merge";
15
+ import tt from "semver";
16
+ import { tmpdir as et } from "node:os";
17
+ import { default as ae } from "lodash.get";
18
+ import { default as fe } from "lodash.set";
19
+ import { default as ue } from "lodash.curry";
20
+ import E from "pinyin";
21
+ const l = Object.assign(
22
+ (t, ...e) => console.log(...e.map((r) => m[t](r))),
20
23
  {
21
24
  /** 成功 */
22
- success: (...t) => c("green", ...t),
25
+ success: (...t) => l("green", ...t),
23
26
  /** /步骤 */
24
- stage: (...t) => c("blue", ...t),
27
+ stage: (...t) => l("blue", ...t),
25
28
  /** 提示信息 */
26
- info: (...t) => c("cyan", ...t),
29
+ info: (...t) => l("cyan", ...t),
27
30
  /** 警告 */
28
- warn: (...t) => c("yellow", ...t),
31
+ warn: (...t) => l("yellow", ...t),
29
32
  /** 错误 */
30
- error: (...t) => c("red", ...t),
33
+ error: (...t) => l("red", ...t),
31
34
  /** 跳过 */
32
- skip: (...t) => c("gray", ...t)
35
+ skip: (...t) => l("gray", ...t)
33
36
  }
34
- ), tt = (t, {
37
+ ), Bt = (t, {
35
38
  /** 当前目录 */
36
- currentDir: r = process.cwd(),
39
+ currentDir: e = process.cwd(),
37
40
  /** 优先找最远的父目录 */
38
- isFindFarthest: e = !0
41
+ isFindFarthest: r = !0
39
42
  } = {}) => {
40
- const n = g.resolve(r).split(g.sep).map((o, i, l) => i ? g.join(l.slice(0, i).join(g.sep), o) : o);
41
- for (; n.length; ) {
42
- const o = e ? n.shift() : n.pop(), i = g.join(o, t);
43
- if (b.existsSync(i))
44
- return o;
43
+ const o = f.resolve(e).split(f.sep).map((s, n, c) => n ? f.join(c.slice(0, n).join(f.sep), s) : s);
44
+ for (; o.length; ) {
45
+ const s = r ? o.shift() : o.pop(), n = f.join(s, t);
46
+ if (u.existsSync(n))
47
+ return s;
45
48
  }
46
- }, $ = "aes-256-cbc", P = 16, p = "hex", h = ":";
47
- function w(t) {
48
- return m.pbkdf2Sync(
49
+ }, H = "aes-256-cbc", F = 16, M = "hex", A = ":";
50
+ function N(t) {
51
+ return _.pbkdf2Sync(
49
52
  t,
50
53
  "done-coding-cli-salt",
51
54
  // 使用固定的盐值
@@ -56,84 +59,84 @@ function w(t) {
56
59
  "sha256"
57
60
  );
58
61
  }
59
- function rt({
62
+ function kt({
60
63
  text: t,
61
- secretKey: r
64
+ secretKey: e
62
65
  }) {
63
66
  try {
64
- const e = w(r), n = m.randomBytes(P), o = m.createCipheriv($, e, n);
65
- let i = o.update(t);
66
- i = Buffer.concat([i, o.final()]);
67
- const l = n.toString(p), s = i.toString(p);
68
- return `${l}${h}${s}`;
69
- } catch (e) {
70
- return c.error(
71
- `加密失败: ${e instanceof Error ? e.message : String(e)}`
67
+ const r = N(e), o = _.randomBytes(F), s = _.createCipheriv(H, r, o);
68
+ let n = s.update(t);
69
+ n = Buffer.concat([n, s.final()]);
70
+ const c = o.toString(M), i = n.toString(M);
71
+ return `${c}${A}${i}`;
72
+ } catch (r) {
73
+ return l.error(
74
+ `加密失败: ${r instanceof Error ? r.message : String(r)}`
72
75
  ), "";
73
76
  }
74
77
  }
75
- function et({
78
+ function xt({
76
79
  encryptedText: t,
77
- secretKey: r
80
+ secretKey: e
78
81
  }) {
79
82
  try {
80
- if (!t.includes(h))
83
+ if (!t.includes(A))
81
84
  return "";
82
- const e = w(r), [n, o] = t.split(h);
83
- if (n.length !== P * 2)
85
+ const r = N(e), [o, s] = t.split(A);
86
+ if (o.length !== F * 2)
84
87
  return "";
85
- const i = Buffer.from(n, p), l = Buffer.from(o, p), s = m.createDecipheriv($, e, i);
86
- let f = s.update(l);
87
- return f = Buffer.concat([f, s.final()]), f.toString();
88
- } catch (e) {
89
- return c.error(
90
- `解密失败: ${e instanceof Error ? e.message : String(e)}`
88
+ const n = Buffer.from(o, M), c = Buffer.from(s, M), i = _.createDecipheriv(H, r, n);
89
+ let a = i.update(c);
90
+ return a = Buffer.concat([a, i.final()]), a.toString();
91
+ } catch (r) {
92
+ return l.error(
93
+ `解密失败: ${r instanceof Error ? r.message : String(r)}`
91
94
  ), "";
92
95
  }
93
96
  }
94
- const E = (...t) => {
95
- const [r, e = {}] = t;
96
- return D(r, {
97
- onCancel(n) {
98
- return c.error(`退出${n == null ? void 0 : n.name}输入`), process.exit(1);
97
+ const G = (...t) => {
98
+ const [e, r = {}] = t;
99
+ return q(e, {
100
+ onCancel(o) {
101
+ return l.error(`退出${o == null ? void 0 : o.name}输入`), process.exit(1);
99
102
  },
100
- ...e
103
+ ...r
101
104
  });
102
- }, R = (t, r) => {
103
- t ? c.error(t) : c.error(r.message), r != null && r.stack && c.error(r.stack), process.exit(1);
104
- }, T = () => {
105
- const t = A(process.argv);
106
- return N(t);
107
- }, j = (t, {
108
- usage: r,
109
- version: e,
110
- demandCommandCount: n,
111
- options: o,
112
- positionals: i,
113
- subcommands: l
105
+ }, rt = (t, e) => {
106
+ t ? l.error(t) : l.error(e.message), e != null && e.stack && l.error(e.stack), process.exit(1);
107
+ }, ot = () => {
108
+ const t = Q(process.argv);
109
+ return z(t);
110
+ }, J = (t, {
111
+ usage: e,
112
+ version: r,
113
+ demandCommandCount: o,
114
+ options: s,
115
+ positionals: n,
116
+ subcommands: c
114
117
  }) => {
115
- let s = t.strict();
116
- r && (s = s.usage(`Usage: ${r}`)), n && (s = s.demandCommand(n));
117
- const f = "help";
118
- return s = s.help(f), e ? s = s.version(e).alias("h", f).alias("v", "version") : s = s.alias("h", f), o && (s = s.options(o)), i && (s = Object.entries(i).reduce((S, [k, x]) => S.positional(k, x), s)), l && (s = s.command(l)), s;
119
- }, ot = async ({ handler: t, ...r }) => {
120
- const e = await j(T(), r).fail(R).argv;
121
- return t ? t(e) : e;
122
- }, nt = (t) => {
123
- const { command: r, describe: e, handler: n = () => {
124
- }, ...o } = t;
118
+ let i = t.strict();
119
+ e && (i = i.usage(`Usage: ${e}`)), o && (i = i.demandCommand(o));
120
+ const a = "help";
121
+ return i = i.help(a), r ? i = i.version(r).alias("h", a).alias("v", "version") : i = i.alias("h", a), s && (i = i.options(s)), n && (i = Object.entries(n).reduce((y, [R, S]) => y.positional(R, S), i)), c && (i = i.command(c)), i;
122
+ }, jt = async ({ handler: t, ...e }) => {
123
+ const r = await J(ot(), e).fail(rt).argv;
124
+ return t ? t(r) : r;
125
+ }, Ht = (t) => {
126
+ const { command: e, describe: r, handler: o = () => {
127
+ }, ...s } = t;
125
128
  return {
126
- command: r,
127
- describe: e,
128
- builder(i) {
129
- return j(i, o);
129
+ command: e,
130
+ describe: r,
131
+ builder(n) {
132
+ return J(n, s);
130
133
  },
131
- handler: n
134
+ handler: o
132
135
  };
133
136
  };
134
- var _ = /* @__PURE__ */ ((t) => (t.VSCODE = "VsCode", t.CURSOR = "Cursor", t.OTHER = "其他", t))(_ || {});
135
- const L = async () => {
136
- const { editorType: t } = await E([
137
+ var st = /* @__PURE__ */ ((t) => (t.VSCODE = "VsCode", t.CURSOR = "Cursor", t.OTHER = "其他", t))(st || {});
138
+ const nt = async () => {
139
+ const { editorType: t } = await G([
137
140
  {
138
141
  name: "editorType",
139
142
  type: "select",
@@ -143,39 +146,39 @@ const L = async () => {
143
146
  "VsCode",
144
147
  "其他"
145
148
  /* OTHER */
146
- ].map((r) => ({
147
- title: r,
148
- value: r
149
+ ].map((e) => ({
150
+ title: e,
151
+ value: e
149
152
  }))
150
153
  }
151
154
  ]);
152
155
  return t;
153
- }, F = {
156
+ }, it = {
154
157
  Cursor: "cursor",
155
158
  VsCode: "code"
156
- }, M = (t, r, e) => {
159
+ }, ct = (t, e, r) => {
157
160
  try {
158
- a(`${t} -v`, { stdio: "ignore" }), a(`${t} ${r}`);
161
+ g(`${t} -v`, { stdio: "ignore" }), g(`${t} ${e}`);
159
162
  } catch {
160
- e();
163
+ r();
161
164
  }
162
- }, B = (t, r) => {
163
- const e = (n) => c.info(`
164
- ${n}, 请用编辑器打开 ${t} 进行编辑
165
+ }, at = (t, e) => {
166
+ const r = (o) => l.info(`
167
+ ${o}, 请用编辑器打开 ${t} 进行编辑
165
168
  `);
166
- switch (r) {
169
+ switch (e) {
167
170
  case "Cursor":
168
171
  case "VsCode": {
169
- const n = F[r];
170
- M(n, t, () => {
171
- e(`${n}命令未安装`);
172
+ const o = it[e];
173
+ ct(o, t, () => {
174
+ r(`${o}命令未安装`);
172
175
  });
173
176
  break;
174
177
  }
175
178
  default:
176
- e("其他编辑器");
179
+ r("其他编辑器");
177
180
  }
178
- }, J = (t = process.cwd()) => ({
181
+ }, lt = (t = process.cwd()) => ({
179
182
  /** 必须保留 */
180
183
  rootDir: {
181
184
  type: "string",
@@ -184,12 +187,12 @@ const L = async () => {
184
187
  /** 必须设置默认值 */
185
188
  default: t
186
189
  }
187
- }), it = ({
190
+ }), Ft = ({
188
191
  configPathDefault: t,
189
- rootDirDefault: r
192
+ rootDirDefault: e
190
193
  }) => ({
191
194
  /** 必须保留 */
192
- ...J(r),
195
+ ...lt(e),
193
196
  /** 必须保留 */
194
197
  configPath: {
195
198
  type: "string",
@@ -198,114 +201,448 @@ const L = async () => {
198
201
  /** 必须设置默认值 */
199
202
  default: t
200
203
  }
201
- }), V = async (t, r) => {
202
- const { configPath: e, rootDir: n } = r, o = g.resolve(n, e), i = g.dirname(o);
203
- return y(i) || H(i, {
204
+ }), ft = async (t, e) => {
205
+ const { configPath: r, rootDir: o } = e, s = f.resolve(o, r), n = f.dirname(s);
206
+ return p(n) || W(n, {
204
207
  recursive: !0
205
- }), o.endsWith(".json5") ? (c.info(`json5模式写入 ${o}`), C(o, v.stringify(t, null, 2)), o) : (c.info(`json模式写入 ${o}`), C(o, JSON.stringify(t, null, 2)), o);
206
- }, st = async (t, r, {
207
- onFileGenerated: e,
208
- edit: n = !1
208
+ }), s.endsWith(".json5") ? (l.info(`json5模式写入 ${s}`), b(s, j.stringify(t, null, 2)), s) : (l.info(`json模式写入 ${s}`), b(s, JSON.stringify(t, null, 2)), s);
209
+ }, Nt = async (t, e, {
210
+ onFileGenerated: r,
211
+ edit: o = !1
209
212
  } = {}) => {
210
- const o = await V(t, r);
211
- if (e == null || e(o), n) {
212
- const i = await L();
213
- B(r.configPath, i);
213
+ const s = await ft(t, e);
214
+ if (r == null || r(s), o) {
215
+ const n = await nt();
216
+ at(e.configPath, n);
214
217
  }
215
- }, ct = async (t, r) => {
216
- const { configPath: e, rootDir: n } = t, o = g.resolve(n, e);
217
- if (!y(o)) {
218
- if (r)
219
- return c.info("配置文件不存在,使用onNotExists返回值"), r();
220
- const i = `配置文件不存在 ${o}`;
221
- throw new Error(i);
218
+ }, Gt = async (t, e) => {
219
+ const { configPath: r, rootDir: o } = t, s = f.resolve(o, r);
220
+ if (!p(s)) {
221
+ if (e)
222
+ return l.info("配置文件不存在,使用onNotExists返回值"), e();
223
+ const n = `配置文件不存在 ${s}`;
224
+ throw new Error(n);
222
225
  }
223
- return o.endsWith(".json5") ? (c.info(`json5模式解析 ${o}`), v.parse(d(o, "utf8"))) : (c.info(`json模式解析 ${o}`), JSON.parse(d(o, "utf8")));
224
- }, at = async () => {
225
- const { useDefaultConfig: t } = await E({
226
+ return s.endsWith(".json5") ? (l.info(`json5模式解析 ${s}`), j.parse(v(s, "utf8"))) : (l.info(`json模式解析 ${s}`), JSON.parse(v(s, "utf8")));
227
+ }, Jt = async () => {
228
+ const { useDefaultConfig: t } = await G({
226
229
  name: "useDefaultConfig",
227
230
  type: "confirm",
228
231
  message: "使用默认模板配置",
229
232
  initial: !0
230
233
  });
231
234
  return t;
232
- }, Y = "./package.json", ft = ({
235
+ }, L = "package.json", w = ({
233
236
  rootDir: t
234
237
  }) => {
235
- const r = g.resolve(t, Y);
236
- if (!y(r))
238
+ const e = f.resolve(t, L);
239
+ if (!p(e))
237
240
  throw new Error(`${t}未找到package.json文件`);
238
- const e = d(r, "utf-8");
239
- return JSON.parse(e);
240
- }, lt = ({
241
+ const r = v(e, "utf-8");
242
+ return JSON.parse(r);
243
+ }, gt = ({
244
+ rootDir: t,
245
+ pkgJson: e,
246
+ pkgName: r,
247
+ isDevPkg: o
248
+ }) => {
249
+ const s = e || w({ rootDir: t }), n = o ? s.devDependencies : s.dependencies;
250
+ let c = n == null ? void 0 : n[r];
251
+ if (!c) {
252
+ const i = o ? s.dependencies : s.devDependencies;
253
+ c = i == null ? void 0 : i[r], c && console.log(
254
+ m.yellow(
255
+ `${o ? "开发" : "生产"}依赖包${r}可能错误的安装在${o ? "dependencies" : "devDependencies"}`
256
+ )
257
+ );
258
+ return;
259
+ }
260
+ return c || console.log(m.cyan(`依赖包${r}未安装`)), c;
261
+ }, Lt = ({
262
+ patchConfig: t,
263
+ rootDir: e
264
+ }) => {
265
+ if (!t)
266
+ return;
267
+ const r = w({ rootDir: e }), o = Z(r, t), s = f.resolve(e, L);
268
+ b(s, JSON.stringify(o, null, 2), "utf-8");
269
+ }, O = (t) => {
270
+ const r = g("git rev-parse --show-toplevel", {
271
+ cwd: t
272
+ }).toString();
273
+ if (!r)
274
+ throw new Error("获取git根目录失败");
275
+ return r.trim();
276
+ }, Ut = () => {
277
+ var t;
278
+ try {
279
+ const e = g("git symbolic-ref --short HEAD", {
280
+ stdio: "ignore"
281
+ });
282
+ return (t = e == null ? void 0 : e.toString()) == null ? void 0 : t.trim();
283
+ } catch {
284
+ try {
285
+ const r = g("git rev-parse --short HEAD").toString().trim();
286
+ l.skip(`当前未指向具体某个分支, 当前commit hash: ${r}`);
287
+ } finally {
288
+ return;
289
+ }
290
+ }
291
+ }, ut = (t) => {
292
+ const e = t.match(/moving\s+from\s+(.*)\s+to\s+(.*)/);
293
+ if (e) {
294
+ const [, r, o] = e;
295
+ return {
296
+ fromBranch: r.trim(),
297
+ toBranch: o.trim()
298
+ };
299
+ }
300
+ }, I = 73, mt = (t) => {
301
+ const r = u.statSync(t).mode;
302
+ if ((r & I) === I)
303
+ return;
304
+ console.log(m.blue(`${t} 没有执行权限 添加... `));
305
+ const o = r | I;
306
+ u.chmodSync(t, o), console.log(m.green(`${t} 添加执行权限成功`));
307
+ };
308
+ var d = /* @__PURE__ */ ((t) => (t.PRE_COMMIT = "pre-commit", t.PRE_MERGE_COMMIT = "pre-merge-commit", t.PREPARE_COMMIT_MSG = "prepare-commit-msg", t.COMMIT_MSG = "commit-msg", t.PRE_REBASE = "pre-rebase", t.POST_COMMIT = "post-commit", t.POST_MERGE = "post-merge", t.PRE_PUSH = "pre-push", t))(d || {});
309
+ const pt = "husky", ht = ".husky", dt = ({ rootDir: t }) => {
310
+ const e = O(t), r = gt({
311
+ rootDir: e,
312
+ pkgJson: w({ rootDir: e }),
313
+ pkgName: pt,
314
+ isDevPkg: !0
315
+ });
316
+ if (!r)
317
+ throw new Error("husky版本获取失败, 可能husky未安装");
318
+ const o = r.replace(/^(\^|~)/, ""), s = "<9.0.0";
319
+ return tt.satisfies(o, s) ? (console.log(m.cyan(`${o}符合${s}`)), `#!/usr/bin/env sh
320
+ . "$(dirname -- "$0")/_/husky.sh"`) : (console.log(m.cyan(`${o}不符合${s}`)), "");
321
+ }, yt = ({ rootDir: t }) => {
322
+ const e = O(t);
323
+ return f.resolve(e, ht);
324
+ }, Kt = ({
325
+ hookNames: t,
326
+ rootDir: e,
327
+ getCode: r
328
+ }) => {
329
+ const o = yt({ rootDir: e });
330
+ u.existsSync(o) || u.mkdirSync(o, { recursive: !0 }), t.forEach((s) => {
331
+ const n = f.resolve(o, s), c = u.existsSync(n);
332
+ let i = r(s);
333
+ if (c)
334
+ u.readFileSync(n, "utf-8").includes(i) ? console.log(
335
+ m.gray(`${n} ${s}相关调用 ${i} 已存在 跳过`)
336
+ ) : (u.appendFileSync(
337
+ n,
338
+ `
339
+ ${i}
340
+ `
341
+ ), console.log(m.green(`${n} 添加 ${s}相关调用成功`)));
342
+ else {
343
+ const a = dt({
344
+ rootDir: e
345
+ });
346
+ u.writeFileSync(
347
+ n,
348
+ `${a}
349
+
350
+ ${i}
351
+ `,
352
+ "utf-8"
353
+ ), console.log(m.green(`${n} 添加 ${s}相关调用成功`));
354
+ }
355
+ mt(n);
356
+ });
357
+ }, Yt = [
358
+ // HooksNameEnum.PRE_MERGE_COMMIT,
359
+ d.PREPARE_COMMIT_MSG,
360
+ d.COMMIT_MSG
361
+ ], Vt = ({
362
+ hookName: t,
363
+ rootDir: e
364
+ }) => {
365
+ const r = O(e), o = f.resolve(r, ".git");
366
+ switch (t) {
367
+ case d.PREPARE_COMMIT_MSG:
368
+ case d.COMMIT_MSG: {
369
+ const s = f.resolve(o, "MERGE_MSG");
370
+ if (p(s))
371
+ return v(s, "utf-8");
372
+ }
373
+ }
374
+ return "";
375
+ }, Wt = ({
241
376
  remoteAlias: t
242
377
  } = {}) => {
243
378
  try {
244
- const r = a("git rev-parse HEAD").toString().trim(), e = a('git log -1 --pretty=format:"%an"').toString().trim(), n = a('git log -1 --pretty=format:"%ae"').toString().trim(), o = a('git log -1 --pretty=format:"%s"').toString().trim(), i = a("git config user.name").toString().trim(), l = a("git config user.email").toString().trim(), s = a("git rev-parse --abbrev-ref HEAD").toString().trim();
245
- let f = "";
379
+ const e = g("git rev-parse HEAD").toString().trim(), r = g('git log -1 --pretty=format:"%an"').toString().trim(), o = g('git log -1 --pretty=format:"%ae"').toString().trim(), s = g('git log -1 --pretty=format:"%s"').toString().trim(), n = g("git config user.name").toString().trim(), c = g("git config user.email").toString().trim(), i = g("git rev-parse --abbrev-ref HEAD").toString().trim();
380
+ let a = "";
246
381
  try {
247
- f = a(`git config --get remote.${t}.url`).toString().trim();
382
+ a = g(`git config --get remote.${t}.url`).toString().trim();
248
383
  } catch {
249
- c.warn("git远程仓库地址获取失败或者不存在");
384
+ l.warn("git远程仓库地址获取失败或者不存在");
250
385
  }
251
386
  return {
252
- lastHash: r,
253
- lastCommitter: e,
254
- lastCommitterPinYin: u(e, {
255
- style: u.STYLE_NORMAL,
387
+ lastHash: e,
388
+ lastCommitter: r,
389
+ lastCommitterPinYin: E(r, {
390
+ style: E.STYLE_NORMAL,
256
391
  heteronym: !1
257
392
  }).join(""),
258
- lastCommitEmail: n,
259
- lastCommitMsg: o,
260
- userName: i,
261
- userNamePinYin: u(i, {
262
- style: u.STYLE_NORMAL,
393
+ lastCommitEmail: o,
394
+ lastCommitMsg: s,
395
+ userName: n,
396
+ userNamePinYin: E(n, {
397
+ style: E.STYLE_NORMAL,
263
398
  heteronym: !1
264
399
  }).join(""),
265
- userEmail: l,
266
- branchName: s,
267
- remoteInfo: f ? {
400
+ userEmail: c,
401
+ branchName: i,
402
+ remoteInfo: a ? {
268
403
  alias: t,
269
- url: f
404
+ url: a
270
405
  } : void 0
271
406
  };
272
- } catch (r) {
273
- throw c.error("获取git最后提交信息失败"), r;
407
+ } catch (e) {
408
+ throw l.error("获取git最后提交信息失败"), e;
274
409
  }
275
- }, gt = ({
410
+ }, U = (t = "") => {
411
+ const e = /\s*Merge\s+branch\s+['|"](.+)['|"]\s+into\s+['|"](.+)['|"]\s*/i, r = t.match(e);
412
+ if (r) {
413
+ const [, i, a] = r;
414
+ return {
415
+ fromBranch: i,
416
+ toBranch: a
417
+ };
418
+ }
419
+ const o = /\s*Merge\s+branch\s+['|"](.+)['|"]\s+of\s+.+\s+into\s+['|"](.+)['|"]\s*/i, s = t.match(o);
420
+ if (s) {
421
+ const [, i, a] = s;
422
+ return {
423
+ fromBranch: i,
424
+ toBranch: a
425
+ };
426
+ }
427
+ const n = /\s*Merge\s+branch\s+['|"](.+)['|"](\s+of)?\s*/i, c = t.match(n);
428
+ if (c) {
429
+ const [, i] = c;
430
+ return {
431
+ fromBranch: i
432
+ };
433
+ }
434
+ }, Rt = (t) => {
435
+ if (t.startsWith(T.MERGE))
436
+ return {
437
+ fromBranch: t.replace(T.MERGE, "").trim()
438
+ };
439
+ }, Xt = () => {
440
+ const t = process.env.GIT_REFLOG_ACTION || "";
441
+ if (!t)
442
+ return;
443
+ const e = /merge\s+([^\s]+)\s*/i, r = t.match(e);
444
+ if (r) {
445
+ const [, n] = r;
446
+ return {
447
+ fromBranch: n
448
+ };
449
+ }
450
+ const o = /pull\s+([^\s]+)\s+([^\s]+)/, s = t.match(o);
451
+ if (s) {
452
+ const [, , n] = s;
453
+ return {
454
+ fromBranch: n
455
+ };
456
+ }
457
+ };
458
+ var T = /* @__PURE__ */ ((t) => (t.CHECKOUT = "checkout", t.MERGE = "merge", t.COMMIT = "commit", t.COMMIT_MERGE = "commit (merge)", t.PULL = "pull", t.RESET = "reset", t.REBASE_START = "rebase (start)", t.REBASE_FINISH = "rebase (finish)", t.REBASE_ABORT = "rebase (abort)", t.REBASE_CONTINUE = "rebase (continue)", t))(T || {});
459
+ const k = "__GIT_REPLACE_MARK__", $ = {
460
+ stringify(t) {
461
+ return JSON.stringify(t).replace(/"/g, k);
462
+ },
463
+ parse(t) {
464
+ return JSON.parse(t.replace(new RegExp(k, "g"), '"'));
465
+ }
466
+ }, qt = ({
467
+ count: t = 100
468
+ } = {}) => {
469
+ if (t <= 0)
470
+ return [];
471
+ const e = {
472
+ hash: "%H",
473
+ /** 提交信息 */
474
+ message: "%s",
475
+ /** 作者 */
476
+ author: "%an",
477
+ /** 作者邮箱 */
478
+ authorEmail: "%ae",
479
+ /** 创作日期 */
480
+ createDate: "%ai",
481
+ /** 提交者 */
482
+ committer: "%cn",
483
+ /** 提交者邮箱 */
484
+ committerEmail: "%ce",
485
+ /** 提交日期 */
486
+ commitTime: "%ci"
487
+ };
488
+ return g(
489
+ `git --no-pager log --oneline -n ${t} --pretty=format:"${$.stringify(
490
+ e
491
+ )}"`
492
+ ).toString().split(`
493
+ `).map((n) => {
494
+ const c = $.parse(n);
495
+ return {
496
+ ...c,
497
+ mergeInfo: U(c.message)
498
+ };
499
+ });
500
+ }, zt = ({
501
+ count: t = 100,
502
+ filterItem: e = () => !0
503
+ } = {}) => {
504
+ if (t <= 0)
505
+ return [];
506
+ const r = {
507
+ hash: "%H",
508
+ fullMessage: "%gs",
509
+ committer: "%cn",
510
+ committerEmail: "%ce",
511
+ commitTime: "%ci"
512
+ };
513
+ return g(
514
+ `git --no-pager reflog -n ${t} --pretty=format:"${$.stringify(
515
+ r
516
+ )}"`
517
+ ).toString().split(`
518
+ `).map((i) => $.parse(i)).filter(e).map((i) => {
519
+ const { fullMessage: a, ...y } = i, R = ":", [S] = a.split(R, 1), Y = a.slice(`${S}${R}`.length), h = S.trim(), C = Y.trim();
520
+ let P, D, V;
521
+ if (h.startsWith(
522
+ "checkout"
523
+ /* CHECKOUT */
524
+ ))
525
+ D = ut(C);
526
+ else if (h.startsWith(
527
+ "merge"
528
+ /* MERGE */
529
+ ))
530
+ P = Rt(h);
531
+ else if (h.startsWith(
532
+ "commit (merge)"
533
+ /* COMMIT_MERGE */
534
+ )) {
535
+ const B = U(C);
536
+ B || l.warn(
537
+ `${i.hash} 是合并提交 但是未从提交信息(${C})中检测到合并分支信息,推测手动更改了提交内容`
538
+ ), P = B;
539
+ }
540
+ return {
541
+ ...y,
542
+ type: h,
543
+ message: C,
544
+ mergeInfo: P,
545
+ checkoutInfo: D,
546
+ rebaseInfo: V
547
+ };
548
+ });
549
+ }, Qt = (t) => {
550
+ const e = O(t), r = f.resolve(e, ".git"), o = f.resolve(r, "rebase-merge");
551
+ if (u.existsSync(o))
552
+ return !0;
553
+ const s = f.resolve(r, "rebase-apply");
554
+ if (u.existsSync(s))
555
+ return !0;
556
+ const n = f.resolve(r, "REBASE_HEAD");
557
+ return !!u.existsSync(n);
558
+ }, Zt = ({
276
559
  branchName: t,
277
- version: r,
278
- remoteInfo: e
560
+ version: e,
561
+ remoteInfo: r
279
562
  }) => {
280
- e && (a(`git push ${e.alias} v${r}`, {
563
+ r && (g(`git push ${r.alias} v${e}`, {
281
564
  stdio: "inherit"
282
- }), a(`git push ${e.alias} ${t}`, {
565
+ }), g(`git push ${r.alias} ${t}`, {
283
566
  stdio: "inherit"
284
567
  }));
568
+ }, x = "git@gitee.com:justsosu/done-coding-cli-assets-config.git", St = (t) => `./.DONE_CODING_CLI/CONFIG_TEMP_DIR_FOR_${t}`, K = (t) => `./assets/${t}`, Ct = (t) => `${K(t)}/index.json`, te = async ({
569
+ moduleName: t,
570
+ onSuccess: e
571
+ }) => {
572
+ console.log(m.blue(`拉取${t}配置,请稍等...`));
573
+ const r = St(t), o = f.resolve(
574
+ et(),
575
+ r
576
+ );
577
+ if (p(o))
578
+ return console.log(
579
+ m.red(`${o} 已存在,请手动删除该目录再试`)
580
+ ), process.exit(1);
581
+ const s = () => {
582
+ X(o, { recursive: !0, force: !0 });
583
+ };
584
+ let n;
585
+ try {
586
+ g(`git clone ${x} ${o} --depth=1`);
587
+ const c = Ct(t), i = K(t), a = f.resolve(
588
+ o,
589
+ c
590
+ );
591
+ n = JSON.parse(u.readFileSync(a, "utf-8")), process.once("exit", () => {
592
+ p(o) && (console.log("发现进程退出,正在清理临时目录..."), s());
593
+ }), await e({
594
+ repoUrl: x,
595
+ config: n,
596
+ cliConfigFileRelativePath: c,
597
+ cliConfigDirRelativePath: i,
598
+ configTemporaryDir: o
599
+ });
600
+ } finally {
601
+ s();
602
+ }
603
+ return n;
285
604
  };
286
605
  export {
287
- _ as EditorTypeEnum,
288
- wt as _curry,
289
- Ct as _get,
290
- $t as _set,
291
- pt as chalk,
292
- ot as createMainCommand,
293
- nt as createSubcommand,
294
- et as decryptAES,
295
- rt as encryptAES,
296
- it as getConfigFileCommonOptions,
297
- L as getEditorType,
298
- lt as getGitLastCommitInfo,
299
- ft as getPackageJson,
300
- J as getRootDirOptions,
301
- at as getUseDefaultConfig,
302
- V as initConfigFile,
303
- st as initHandlerCommon,
304
- yt as json5,
305
- c as log,
306
- tt as lookForParentTarget,
307
- B as openFileInEditor,
308
- gt as pushGitPublishInfoToRemote,
309
- ct as readConfigFile,
310
- E as xPrompts
606
+ st as EditorTypeEnum,
607
+ T as GitRefLogTypeEnum,
608
+ d as HooksNameEnum,
609
+ Yt as SUPPORT_GET_COMMIT_BY_HOOKS_NAMES,
610
+ ue as _curry,
611
+ ae as _get,
612
+ fe as _set,
613
+ Kt as addHuskyHooks,
614
+ Lt as addPackageConfig,
615
+ oe as chalk,
616
+ Qt as checkCurrentIsRebasing,
617
+ jt as createMainCommand,
618
+ Ht as createSubcommand,
619
+ xt as decryptAES,
620
+ kt as encryptAES,
621
+ mt as fileAddX,
622
+ Vt as getCommitByHookName,
623
+ Ft as getConfigFileCommonOptions,
624
+ qt as getCurrentBranchLastCommitList,
625
+ Ut as getCurrentBranchName,
626
+ nt as getEditorType,
627
+ Wt as getGitLastCommitInfo,
628
+ O as getGitProjectDir,
629
+ zt as getLastReflogList,
630
+ w as getPackageJson,
631
+ gt as getRelyPkgVersion,
632
+ lt as getRootDirOptions,
633
+ Jt as getUseDefaultConfig,
634
+ ft as initConfigFile,
635
+ Nt as initHandlerCommon,
636
+ ie as json5,
637
+ l as log,
638
+ Bt as lookForParentTarget,
639
+ at as openFileInEditor,
640
+ Zt as pushGitPublishInfoToRemote,
641
+ te as readCliConfig,
642
+ Gt as readConfigFile,
643
+ ut as resolveCheckoutInfoByRefInfo,
644
+ U as resolveMergeInfoByCommitMsg,
645
+ Xt as resolveMergeInfoByGitReflogAction,
646
+ Rt as resolveMergeInfoByRefType,
647
+ G as xPrompts
311
648
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@done-coding/cli-utils",
3
- "version": "0.5.0-alpha.0",
3
+ "version": "0.7.0-alpha.0",
4
4
  "description": "cli utils",
5
5
  "private": false,
6
6
  "module": "es/index.mjs",
@@ -40,10 +40,12 @@
40
40
  "@types/json5": "^2.2.0",
41
41
  "@types/lodash.curry": "^4.1.8",
42
42
  "@types/lodash.get": "^4.4.9",
43
+ "@types/lodash.merge": "^4.6.9",
43
44
  "@types/lodash.set": "^4.3.9",
44
45
  "@types/node": "^18.0.0",
45
46
  "@types/pinyin": "^2.10.0",
46
47
  "@types/prompts": "^2.4.6",
48
+ "@types/semver": "^7.5.3",
47
49
  "@types/yargs": "^17.0.28",
48
50
  "rimraf": "^6.0.1",
49
51
  "typescript": "^5.2.2",
@@ -58,10 +60,12 @@
58
60
  "json5": "^2.2.3",
59
61
  "lodash.curry": "^4.1.1",
60
62
  "lodash.get": "^4.4.2",
63
+ "lodash.merge": "^4.6.2",
61
64
  "lodash.set": "^4.3.2",
62
65
  "pinyin": "^2.11.2",
63
66
  "prompts": "^2.4.2",
67
+ "semver": "^7.5.4",
64
68
  "yargs": "^17.7.2"
65
69
  },
66
- "gitHead": "86cdd3eaf8cc8be3e48a812b93fd7c2110fcc879"
70
+ "gitHead": "ff1616738586a268b50f46dce762774fa5fa6d52"
67
71
  }
@@ -0,0 +1,15 @@
1
+ /** 读取配置 */
2
+ export declare const readCliConfig: <R>({ moduleName, onSuccess, }: {
3
+ moduleName: string;
4
+ onSuccess: (params: {
5
+ repoUrl: string;
6
+ /** 配置文件相对路径 */
7
+ cliConfigFileRelativePath: string;
8
+ /** 配置文件目录相对路径 */
9
+ cliConfigDirRelativePath: string;
10
+ /** 配置文件内容 */
11
+ config: R;
12
+ /** 配置临时目录 */
13
+ configTemporaryDir: string;
14
+ }) => void | Promise<void>;
15
+ }) => Promise<R>;
@@ -0,0 +1,2 @@
1
+ /** 文件添加执行权限 */
2
+ export declare const fileAddX: (filePath: string) => void;
@@ -0,0 +1,2 @@
1
+ /** 获取git项目目录 */
2
+ export declare const getGitProjectDir: (rootDir: string) => string;
@@ -0,0 +1,2 @@
1
+ /** 获取当前分支名 */
2
+ export declare const getCurrentBranchName: () => string | undefined;
@@ -0,0 +1,5 @@
1
+ /** 解析checkoutInfo */
2
+ export declare const resolveCheckoutInfoByRefInfo: (message: string) => {
3
+ fromBranch: string;
4
+ toBranch: string;
5
+ } | undefined;
@@ -1,21 +1,13 @@
1
- /** 获取git最好提交信息参数 */
2
- export interface GetGitLastCommitParams {
3
- /**
4
- * 远程仓库别名
5
- */
6
- remoteAlias?: string;
7
- }
8
- /** 远程仓库信息 */
9
- export interface GitRemoteInfo {
10
- /**
11
- * 远程仓库别名
12
- */
13
- alias?: GetGitLastCommitParams["remoteAlias"];
14
- /**
15
- * 仓库地址
16
- */
17
- url?: string;
18
- }
1
+ import { HooksNameEnum } from '../husky';
2
+ import type { GitRemoteInfo } from "./remote-operate";
3
+ /** 支持通过提交钩子获取提交信息的 */
4
+ export declare const SUPPORT_GET_COMMIT_BY_HOOKS_NAMES: readonly [HooksNameEnum.PREPARE_COMMIT_MSG, HooksNameEnum.COMMIT_MSG];
5
+ export type SupportGetCommitByHookName = (typeof SUPPORT_GET_COMMIT_BY_HOOKS_NAMES)[number];
6
+ /** 根据hookName获取(将)提交的信息 */
7
+ export declare const getCommitByHookName: ({ hookName, rootDir, }: {
8
+ hookName: SupportGetCommitByHookName;
9
+ rootDir: string;
10
+ }) => string;
19
11
  /**
20
12
  * git最后提交信息
21
13
  */
@@ -59,13 +51,14 @@ export interface GitLastCommitInfo {
59
51
  /** 远程仓库信息 */
60
52
  remoteInfo?: GitRemoteInfo;
61
53
  }
54
+ /** 获取git最好提交信息参数 */
55
+ export interface GetGitLastCommitParams {
56
+ /**
57
+ * 远程仓库别名
58
+ */
59
+ remoteAlias?: GitRemoteInfo["alias"];
60
+ }
62
61
  /**
63
62
  * 获取git 最后提交信息
64
63
  */
65
64
  export declare const getGitLastCommitInfo: ({ remoteAlias, }?: GetGitLastCommitParams) => GitLastCommitInfo;
66
- /** 推送git发布信息到远程仓库 */
67
- export declare const pushGitPublishInfoToRemote: ({ branchName, version, remoteInfo, }: {
68
- branchName: string;
69
- version: string;
70
- remoteInfo?: GitRemoteInfo | undefined;
71
- }) => void;
@@ -0,0 +1,8 @@
1
+ export * from "./base-info-resolve";
2
+ export * from "./branch-resolve";
3
+ export * from "./checkout-resolve";
4
+ export * from "./commit-resolve";
5
+ export * from "./log-resolve";
6
+ export * from "./merge-resolve";
7
+ export * from "./rebase-resolve";
8
+ export * from "./remote-operate";
@@ -0,0 +1,91 @@
1
+ import { type GitMergeBranchInfo } from "./merge-resolve";
2
+ /** git checkout信息 */
3
+ export interface GitCheckoutInfo {
4
+ fromBranch: string;
5
+ toBranch: string;
6
+ }
7
+ /** git日志通用信息 */
8
+ export interface GitLogCommonInfo {
9
+ hash: string;
10
+ /** 提交信息 */
11
+ message: string;
12
+ /** 合并信息 */
13
+ mergeInfo?: GitMergeBranchInfo;
14
+ }
15
+ export interface GitLogItemInfo extends GitLogCommonInfo {
16
+ /** 作者 */
17
+ author: string;
18
+ /** 作者邮箱 */
19
+ authorEmail: string;
20
+ /** 创作日期 */
21
+ createDate: string;
22
+ /** 提交者 */
23
+ committer: string;
24
+ /** 提交者邮箱 */
25
+ committerEmail: string;
26
+ /** 提交时间 */
27
+ commitTime: string;
28
+ }
29
+ /** 提交日志信息 */
30
+ export interface GitReflogItemInfoRaw extends Omit<GitLogCommonInfo, "message"> {
31
+ hash: string;
32
+ /** 完整信息 */
33
+ fullMessage: string;
34
+ /** 提交者 */
35
+ committer: string;
36
+ /** 提交者邮箱 */
37
+ committerEmail: string;
38
+ /** 提交时间 */
39
+ commitTime: string;
40
+ }
41
+ /** reflog类型 */
42
+ export declare enum GitRefLogTypeEnum {
43
+ /** checkout */
44
+ CHECKOUT = "checkout",
45
+ /** merge $branch */
46
+ MERGE = "merge",
47
+ /** 提交 */
48
+ COMMIT = "commit",
49
+ /** 合并提交 */
50
+ COMMIT_MERGE = "commit (merge)",
51
+ /** pull $origin $branch */
52
+ PULL = "pull",
53
+ /** reset */
54
+ RESET = "reset",
55
+ /** rebase (start) */
56
+ REBASE_START = "rebase (start)",
57
+ /** rebase (finish) */
58
+ REBASE_FINISH = "rebase (finish)",
59
+ /** rebase (abort) */
60
+ REBASE_ABORT = "rebase (abort)",
61
+ /** rebase (continue) */
62
+ REBASE_CONTINUE = "rebase (continue)"
63
+ }
64
+ /** rebase的阶段 */
65
+ export type GitRefLogRebaseStage = GitRefLogTypeEnum.REBASE_START | GitRefLogTypeEnum.REBASE_FINISH | GitRefLogTypeEnum.REBASE_ABORT | GitRefLogTypeEnum.REBASE_CONTINUE;
66
+ export interface GitRebaseInfo {
67
+ /** rebase的阶段 */
68
+ stage?: GitRefLogRebaseStage;
69
+ /** 变基的原始分支 */
70
+ originBranch: string;
71
+ /** 变基的目标分支 */
72
+ targetBranch: string;
73
+ }
74
+ /** reflog信息 */
75
+ export interface GitReflogItemInfo extends Omit<GitReflogItemInfoRaw, "fullMessage">, Pick<GitLogCommonInfo, "message"> {
76
+ type: GitRefLogTypeEnum;
77
+ }
78
+ /** 获取当前分支最近提交列表 */
79
+ export declare const getCurrentBranchLastCommitList: ({ count, }?: {
80
+ count?: number | undefined;
81
+ /** 某个hash之后的提交 */
82
+ afterHash?: string | undefined;
83
+ }) => GitLogItemInfo[];
84
+ /** 获取最后的reflog */
85
+ export declare const getLastReflogList: ({ count, filterItem, }?: {
86
+ count?: number | undefined;
87
+ /** 某个hash之后的提交 */
88
+ afterHash?: string | undefined;
89
+ /** 过滤函数 */
90
+ filterItem?: ((item: GitReflogItemInfoRaw) => boolean) | undefined;
91
+ }) => GitReflogItemInfo[];
@@ -0,0 +1,13 @@
1
+ /** git合并分支信息 */
2
+ export interface GitMergeBranchInfo {
3
+ /** 合并的源分支 */
4
+ fromBranch: string;
5
+ /** 合并到该分支 */
6
+ toBranch?: string;
7
+ }
8
+ /** 解析合并信息-通过提交信息 */
9
+ export declare const resolveMergeInfoByCommitMsg: (commitMsg?: string) => GitMergeBranchInfo | undefined;
10
+ /** 从reflog type解析合并信息 */
11
+ export declare const resolveMergeInfoByRefType: (type: string) => GitMergeBranchInfo | undefined;
12
+ /** 从reflog action解析合并信息 */
13
+ export declare const resolveMergeInfoByGitReflogAction: () => GitMergeBranchInfo | undefined;
@@ -0,0 +1,2 @@
1
+ /** 检测当前正在变基 */
2
+ export declare const checkCurrentIsRebasing: (rootDir: string) => boolean;
@@ -0,0 +1,17 @@
1
+ /** 远程仓库信息 */
2
+ export interface GitRemoteInfo {
3
+ /**
4
+ * 远程仓库别名
5
+ */
6
+ alias?: string;
7
+ /**
8
+ * 仓库地址
9
+ */
10
+ url?: string;
11
+ }
12
+ /** 推送git发布信息到远程仓库 */
13
+ export declare const pushGitPublishInfoToRemote: ({ branchName, version, remoteInfo, }: {
14
+ branchName: string;
15
+ version: string;
16
+ remoteInfo?: GitRemoteInfo | undefined;
17
+ }) => void;
@@ -0,0 +1,26 @@
1
+ export declare enum HooksNameEnum {
2
+ /** 预提交 */
3
+ PRE_COMMIT = "pre-commit",
4
+ /** 预合并提交 */
5
+ PRE_MERGE_COMMIT = "pre-merge-commit",
6
+ /** 准备提交信息 */
7
+ PREPARE_COMMIT_MSG = "prepare-commit-msg",
8
+ /** 提交消息 */
9
+ COMMIT_MSG = "commit-msg",
10
+ /** 变基前 */
11
+ PRE_REBASE = "pre-rebase",
12
+ /** 提交后 */
13
+ POST_COMMIT = "post-commit",
14
+ /** 合并后 */
15
+ POST_MERGE = "post-merge",
16
+ /** 推送前 */
17
+ PRE_PUSH = "pre-push"
18
+ }
19
+ /** 添加 husky hooks */
20
+ export declare const addHuskyHooks: <H extends string>({ hookNames, rootDir, getCode, }: {
21
+ hookNames: H[];
22
+ /** 运行目录 */
23
+ rootDir: string;
24
+ /** 获取husky hooks 添加的代码 */
25
+ getCode: (hook: string) => string;
26
+ }) => void;
package/types/index.d.ts CHANGED
@@ -9,3 +9,6 @@ export * from "./json5";
9
9
  export * from "./lodash";
10
10
  export * from "./package-json";
11
11
  export * from "./git";
12
+ export * from "./husky";
13
+ export * from "./file-operate";
14
+ export * from "./cli-config";
@@ -1,7 +1,28 @@
1
+ /** package.json文件内容 */
1
2
  export interface PackageJson {
2
3
  name: string;
3
4
  version?: string;
5
+ bin?: Record<string, string> | string;
6
+ scripts?: Record<string, string>;
7
+ files?: string[];
8
+ dependencies?: Record<string, string>;
9
+ devDependencies?: Record<string, string>;
10
+ peerDependencies?: Record<string, string>;
4
11
  }
12
+ /** 获取package.json文件内容 */
5
13
  export declare const getPackageJson: <R extends PackageJson>({ rootDir, }: {
6
14
  rootDir: string;
7
15
  }) => R;
16
+ /** 获取依赖包版本 */
17
+ export declare const getRelyPkgVersion: <R extends PackageJson>({ rootDir, pkgJson, pkgName, isDevPkg, }: {
18
+ rootDir: string;
19
+ pkgJson?: R | undefined;
20
+ pkgName: string;
21
+ /** 是开发依赖包 */
22
+ isDevPkg: boolean;
23
+ }) => string | undefined;
24
+ /** 添加package.json配置 */
25
+ export declare const addPackageConfig: ({ patchConfig, rootDir, }: {
26
+ patchConfig?: Record<string, any> | undefined;
27
+ rootDir: string;
28
+ }) => void;