@done-coding/cli-utils 0.2.2-alpha.0 → 0.3.1-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 +202 -57
- package/package.json +11 -4
- package/types/cli.d.ts +43 -0
- package/types/config-file.d.ts +31 -0
- package/types/editor.d.ts +13 -0
- package/types/index.d.ts +5 -0
- package/types/json5.d.ts +3 -0
- package/types/lodash.d.ts +4 -0
package/es/index.mjs
CHANGED
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import { default as
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import D from "chalk";
|
|
3
|
+
import { default as ce } from "chalk";
|
|
4
|
+
import a from "node:path";
|
|
5
|
+
import O, { existsSync as h, mkdirSync as k, writeFileSync as g, readFileSync as m } from "node:fs";
|
|
6
|
+
import l from "crypto";
|
|
7
|
+
import H from "prompts";
|
|
8
|
+
import E from "yargs";
|
|
9
|
+
import { hideBin as F } from "yargs/helpers";
|
|
10
|
+
import { execSync as y } from "node:child_process";
|
|
11
|
+
import v from "json5";
|
|
12
|
+
export * from "json5";
|
|
13
|
+
import { default as ue } from "json5";
|
|
14
|
+
import { default as pe } from "lodash.get";
|
|
15
|
+
import { default as ge } from "lodash.set";
|
|
16
|
+
import { default as ye } from "lodash.curry";
|
|
17
|
+
const i = Object.assign(
|
|
18
|
+
(e, ...o) => console.log(...o.map((r) => D[e](r))),
|
|
10
19
|
{
|
|
11
20
|
/** 成功 */
|
|
12
|
-
success: (...
|
|
21
|
+
success: (...e) => i("green", ...e),
|
|
13
22
|
/** /步骤 */
|
|
14
|
-
stage: (...
|
|
23
|
+
stage: (...e) => i("blue", ...e),
|
|
15
24
|
/** 提示信息 */
|
|
16
|
-
info: (...
|
|
25
|
+
info: (...e) => i("cyan", ...e),
|
|
17
26
|
/** 警告 */
|
|
18
|
-
warn: (...
|
|
27
|
+
warn: (...e) => i("yellow", ...e),
|
|
19
28
|
/** 错误 */
|
|
20
|
-
error: (...
|
|
29
|
+
error: (...e) => i("red", ...e),
|
|
21
30
|
/** 跳过 */
|
|
22
|
-
skip: (...
|
|
31
|
+
skip: (...e) => i("gray", ...e)
|
|
23
32
|
}
|
|
24
|
-
),
|
|
25
|
-
const
|
|
26
|
-
for (;
|
|
27
|
-
const t =
|
|
28
|
-
if (
|
|
33
|
+
), G = (e, o = process.cwd()) => {
|
|
34
|
+
const r = a.resolve(o).split(a.sep).map((t, n, c) => n ? a.join(c.slice(0, n).join(a.sep), t) : t);
|
|
35
|
+
for (; r.length; ) {
|
|
36
|
+
const t = r.pop(), n = a.join(t, e);
|
|
37
|
+
if (O.existsSync(n))
|
|
29
38
|
return t;
|
|
30
39
|
}
|
|
31
|
-
},
|
|
32
|
-
function
|
|
33
|
-
return
|
|
34
|
-
|
|
40
|
+
}, C = "aes-256-cbc", S = 16, p = "hex", d = ":";
|
|
41
|
+
function $(e) {
|
|
42
|
+
return l.pbkdf2Sync(
|
|
43
|
+
e,
|
|
35
44
|
"done-coding-cli-salt",
|
|
36
45
|
// 使用固定的盐值
|
|
37
46
|
1e4,
|
|
@@ -41,55 +50,191 @@ function g(r) {
|
|
|
41
50
|
"sha256"
|
|
42
51
|
);
|
|
43
52
|
}
|
|
44
|
-
function
|
|
45
|
-
text:
|
|
46
|
-
secretKey:
|
|
53
|
+
function Q({
|
|
54
|
+
text: e,
|
|
55
|
+
secretKey: o
|
|
47
56
|
}) {
|
|
48
57
|
try {
|
|
49
|
-
const
|
|
50
|
-
let
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
return `${
|
|
54
|
-
} catch (
|
|
55
|
-
return
|
|
56
|
-
`加密失败: ${
|
|
58
|
+
const r = $(o), t = l.randomBytes(S), n = l.createCipheriv(C, r, t);
|
|
59
|
+
let c = n.update(e);
|
|
60
|
+
c = Buffer.concat([c, n.final()]);
|
|
61
|
+
const u = t.toString(p), s = c.toString(p);
|
|
62
|
+
return `${u}${d}${s}`;
|
|
63
|
+
} catch (r) {
|
|
64
|
+
return i.error(
|
|
65
|
+
`加密失败: ${r instanceof Error ? r.message : String(r)}`
|
|
57
66
|
), "";
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
|
-
function
|
|
61
|
-
encryptedText:
|
|
62
|
-
secretKey:
|
|
69
|
+
function X({
|
|
70
|
+
encryptedText: e,
|
|
71
|
+
secretKey: o
|
|
63
72
|
}) {
|
|
64
73
|
try {
|
|
65
|
-
if (!
|
|
74
|
+
if (!e.includes(d))
|
|
66
75
|
return "";
|
|
67
|
-
const
|
|
68
|
-
if (t.length !==
|
|
76
|
+
const r = $(o), [t, n] = e.split(d);
|
|
77
|
+
if (t.length !== S * 2)
|
|
69
78
|
return "";
|
|
70
|
-
const
|
|
71
|
-
let
|
|
72
|
-
return
|
|
73
|
-
} catch (
|
|
74
|
-
return
|
|
75
|
-
`解密失败: ${
|
|
79
|
+
const c = Buffer.from(t, p), u = Buffer.from(n, p), s = l.createDecipheriv(C, r, c);
|
|
80
|
+
let f = s.update(u);
|
|
81
|
+
return f = Buffer.concat([f, s.final()]), f.toString();
|
|
82
|
+
} catch (r) {
|
|
83
|
+
return i.error(
|
|
84
|
+
`解密失败: ${r instanceof Error ? r.message : String(r)}`
|
|
76
85
|
), "";
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
|
-
const
|
|
80
|
-
const [
|
|
81
|
-
return
|
|
88
|
+
const x = (...e) => {
|
|
89
|
+
const [o, r = {}] = e;
|
|
90
|
+
return H(o, {
|
|
82
91
|
onCancel(t) {
|
|
83
|
-
return
|
|
92
|
+
return i.error(`退出${t == null ? void 0 : t.name}输入`), process.exit(1);
|
|
84
93
|
},
|
|
85
|
-
...
|
|
94
|
+
...r
|
|
86
95
|
});
|
|
96
|
+
}, R = (e, o) => {
|
|
97
|
+
e ? i.error(e) : i.error(o.message), o != null && o.stack && i.error(o.stack), process.exit(1);
|
|
98
|
+
}, T = () => {
|
|
99
|
+
const e = F(process.argv);
|
|
100
|
+
return E(e);
|
|
101
|
+
}, j = (e, {
|
|
102
|
+
usage: o,
|
|
103
|
+
version: r,
|
|
104
|
+
demandCommandCount: t,
|
|
105
|
+
options: n,
|
|
106
|
+
positionals: c,
|
|
107
|
+
subcommands: u
|
|
108
|
+
}) => {
|
|
109
|
+
let s = e.strict();
|
|
110
|
+
o && (s = s.usage(`Usage: ${o}`)), t && (s = s.demandCommand(t));
|
|
111
|
+
const f = "help";
|
|
112
|
+
return s = s.help(f), r ? s = s.version(r).alias("h", f).alias("v", "version") : s = s.alias("h", f), n && (s = s.options(n)), c && (s = Object.entries(c).reduce((w, [P, b]) => w.positional(P, b), s)), u && (s = s.command(u)), s;
|
|
113
|
+
}, Z = async ({ handler: e, ...o }) => {
|
|
114
|
+
const r = await j(T(), o).fail(R).argv;
|
|
115
|
+
return e ? e(r) : r;
|
|
116
|
+
}, ee = (e) => {
|
|
117
|
+
const { command: o, describe: r, handler: t = () => {
|
|
118
|
+
}, ...n } = e;
|
|
119
|
+
return {
|
|
120
|
+
command: o,
|
|
121
|
+
describe: r,
|
|
122
|
+
builder(c) {
|
|
123
|
+
return j(c, n);
|
|
124
|
+
},
|
|
125
|
+
handler: t
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
var _ = /* @__PURE__ */ ((e) => (e.VSCODE = "VsCode", e.CURSOR = "Cursor", e.OTHER = "其他", e))(_ || {});
|
|
129
|
+
const A = async () => {
|
|
130
|
+
const { editorType: e } = await x([
|
|
131
|
+
{
|
|
132
|
+
name: "editorType",
|
|
133
|
+
type: "select",
|
|
134
|
+
message: "编辑器类型",
|
|
135
|
+
choices: [
|
|
136
|
+
"Cursor",
|
|
137
|
+
"VsCode",
|
|
138
|
+
"其他"
|
|
139
|
+
/* OTHER */
|
|
140
|
+
].map((o) => ({
|
|
141
|
+
title: o,
|
|
142
|
+
value: o
|
|
143
|
+
}))
|
|
144
|
+
}
|
|
145
|
+
]);
|
|
146
|
+
return e;
|
|
147
|
+
}, B = {
|
|
148
|
+
Cursor: "cursor",
|
|
149
|
+
VsCode: "code"
|
|
150
|
+
}, N = (e, o, r) => {
|
|
151
|
+
try {
|
|
152
|
+
y(`${e} -v`, { stdio: "ignore" }), y(`${e} ${o}`);
|
|
153
|
+
} catch {
|
|
154
|
+
r();
|
|
155
|
+
}
|
|
156
|
+
}, V = (e, o) => {
|
|
157
|
+
const r = (t) => i.info(`
|
|
158
|
+
${t}, 请用编辑器打开 ${e} 进行编辑
|
|
159
|
+
`);
|
|
160
|
+
switch (o) {
|
|
161
|
+
case "Cursor":
|
|
162
|
+
case "VsCode": {
|
|
163
|
+
const t = B[o];
|
|
164
|
+
N(t, e, () => {
|
|
165
|
+
r(`${t}命令未安装`);
|
|
166
|
+
});
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
default:
|
|
170
|
+
r("其他编辑器");
|
|
171
|
+
}
|
|
172
|
+
}, re = ({
|
|
173
|
+
configPathDefault: e
|
|
174
|
+
}) => ({
|
|
175
|
+
/** 必须保留 */
|
|
176
|
+
rootDir: {
|
|
177
|
+
type: "string",
|
|
178
|
+
alias: "r",
|
|
179
|
+
describe: "运行目录",
|
|
180
|
+
/** 必须设置默认值 */
|
|
181
|
+
default: process.cwd()
|
|
182
|
+
},
|
|
183
|
+
/** 必须保留 */
|
|
184
|
+
configPath: {
|
|
185
|
+
type: "string",
|
|
186
|
+
alias: "c",
|
|
187
|
+
describe: "配置文件相对路径",
|
|
188
|
+
/** 必须设置默认值 */
|
|
189
|
+
default: e
|
|
190
|
+
}
|
|
191
|
+
}), L = async (e, o) => {
|
|
192
|
+
const { configPath: r, rootDir: t } = o, n = a.resolve(t, r), c = a.dirname(n);
|
|
193
|
+
return h(c) || k(c, {
|
|
194
|
+
recursive: !0
|
|
195
|
+
}), n.endsWith(".json5") ? (i.info(`json5模式写入 ${n}`), g(n, v.stringify(e, null, 2)), n) : (i.info(`json模式写入 ${n}`), g(n, JSON.stringify(e, null, 2)), n);
|
|
196
|
+
}, te = async (e, o, {
|
|
197
|
+
onFileGenerated: r
|
|
198
|
+
} = {}) => {
|
|
199
|
+
const t = await L(e, o);
|
|
200
|
+
r == null || r(t);
|
|
201
|
+
const n = await A();
|
|
202
|
+
V(o.configPath, n);
|
|
203
|
+
}, oe = async (e) => {
|
|
204
|
+
const { configPath: o, rootDir: r } = e, t = a.resolve(r, o);
|
|
205
|
+
if (!h(t)) {
|
|
206
|
+
i.warn(`配置文件不存在 ${t}`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
return t.endsWith(".json5") ? (i.info(`json5模式解析 ${t}`), v.parse(m(t, "utf8"))) : (i.info(`json模式解析 ${t}`), JSON.parse(m(t, "utf8")));
|
|
210
|
+
}, ne = async () => {
|
|
211
|
+
const { useDefaultConfig: e } = await x({
|
|
212
|
+
name: "useDefaultConfig",
|
|
213
|
+
type: "confirm",
|
|
214
|
+
message: "使用默认模板配置",
|
|
215
|
+
initial: !0
|
|
216
|
+
});
|
|
217
|
+
return e;
|
|
87
218
|
};
|
|
88
219
|
export {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
220
|
+
_ as EditorTypeEnum,
|
|
221
|
+
ye as _curry,
|
|
222
|
+
pe as _get,
|
|
223
|
+
ge as _set,
|
|
224
|
+
ce as chalk,
|
|
225
|
+
Z as createMainCommand,
|
|
226
|
+
ee as createSubcommand,
|
|
227
|
+
X as decryptAES,
|
|
228
|
+
Q as encryptAES,
|
|
229
|
+
re as getConfigFileCommonOptions,
|
|
230
|
+
A as getEditorType,
|
|
231
|
+
ne as getUseDefaultConfig,
|
|
232
|
+
L as initConfigFile,
|
|
233
|
+
te as initHandlerCommon,
|
|
234
|
+
ue as json5,
|
|
235
|
+
i as log,
|
|
236
|
+
G as lookForParentTarget,
|
|
237
|
+
V as openFileInEditor,
|
|
238
|
+
oe as readConfigFile,
|
|
239
|
+
x as xPrompts
|
|
95
240
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@done-coding/cli-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1-alpha.0",
|
|
4
4
|
"description": "cli utils",
|
|
5
5
|
"private": false,
|
|
6
6
|
"module": "es/index.mjs",
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"es",
|
|
16
16
|
"lib",
|
|
17
|
-
"types"
|
|
18
|
-
"gif"
|
|
17
|
+
"types"
|
|
19
18
|
],
|
|
20
19
|
"scripts": {
|
|
21
20
|
"clean": "rimraf es lib types",
|
|
@@ -38,6 +37,10 @@
|
|
|
38
37
|
"license": "MIT",
|
|
39
38
|
"sideEffects": false,
|
|
40
39
|
"devDependencies": {
|
|
40
|
+
"@types/json5": "^2.2.0",
|
|
41
|
+
"@types/lodash.curry": "^4.1.8",
|
|
42
|
+
"@types/lodash.get": "^4.4.9",
|
|
43
|
+
"@types/lodash.set": "^4.3.9",
|
|
41
44
|
"@types/node": "^18.0.0",
|
|
42
45
|
"@types/prompts": "^2.4.6",
|
|
43
46
|
"@types/yargs": "^17.0.28",
|
|
@@ -51,8 +54,12 @@
|
|
|
51
54
|
},
|
|
52
55
|
"dependencies": {
|
|
53
56
|
"chalk": "^5.3.0",
|
|
57
|
+
"json5": "^2.2.3",
|
|
58
|
+
"lodash.curry": "^4.1.1",
|
|
59
|
+
"lodash.get": "^4.4.2",
|
|
60
|
+
"lodash.set": "^4.3.2",
|
|
54
61
|
"prompts": "^2.4.2",
|
|
55
62
|
"yargs": "^17.7.2"
|
|
56
63
|
},
|
|
57
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "ec6957606bbae68d7268159b38b9d36dab4a2731"
|
|
58
65
|
}
|
package/types/cli.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ArgumentsCamelCase, CommandModule, Options as YargsOptions, Argv as YargsArgv } from "yargs";
|
|
2
|
+
import yargs from "yargs";
|
|
3
|
+
export { ArgumentsCamelCase, CommandModule, YargsOptions, YargsArgv };
|
|
4
|
+
/** cli 信息 */
|
|
5
|
+
export interface CliInfo {
|
|
6
|
+
/** 命令 */
|
|
7
|
+
command?: string;
|
|
8
|
+
/** 用法 */
|
|
9
|
+
usage?: string;
|
|
10
|
+
/** 描述信息 */
|
|
11
|
+
describe?: string;
|
|
12
|
+
/** 版本号 */
|
|
13
|
+
version?: string;
|
|
14
|
+
/** 必传命令数 */
|
|
15
|
+
demandCommandCount?: number;
|
|
16
|
+
/** 选项 */
|
|
17
|
+
options?: {
|
|
18
|
+
[key in string]: YargsOptions;
|
|
19
|
+
};
|
|
20
|
+
/** 子命令 */
|
|
21
|
+
subcommands?: CommandModule[];
|
|
22
|
+
/** 位置信息 */
|
|
23
|
+
positionals?: {
|
|
24
|
+
[key in string]: Parameters<typeof yargs.positional>[1];
|
|
25
|
+
};
|
|
26
|
+
/** 处理函数 */
|
|
27
|
+
handler?: CommandModule["handler"];
|
|
28
|
+
}
|
|
29
|
+
/** 子cli信息 */
|
|
30
|
+
export interface SubCliInfo extends CliInfo {
|
|
31
|
+
/** 命令 */
|
|
32
|
+
command: string;
|
|
33
|
+
}
|
|
34
|
+
/** 处理函数参数类型 */
|
|
35
|
+
export type CliHandlerArgv<O> = ArgumentsCamelCase<O> | O;
|
|
36
|
+
/** 创建主命令 */
|
|
37
|
+
export declare const createMainCommand: ({ handler, ...config }: CliInfo) => Promise<void | {
|
|
38
|
+
[x: string]: unknown;
|
|
39
|
+
_: (string | number)[];
|
|
40
|
+
$0: string;
|
|
41
|
+
}>;
|
|
42
|
+
/** 创建子命令模块 */
|
|
43
|
+
export declare const createSubcommand: (cliInfo: SubCliInfo) => CommandModule;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CliHandlerArgv, YargsOptions } from "./cli";
|
|
2
|
+
/** 配置文件通用选项 */
|
|
3
|
+
export interface ConfigFileCommonOptions {
|
|
4
|
+
/**
|
|
5
|
+
* 相对于路径
|
|
6
|
+
* ---
|
|
7
|
+
* 绝对路径 path.resolve(rootDir, configPath)
|
|
8
|
+
*/
|
|
9
|
+
configPath: string;
|
|
10
|
+
/** 项目根目录 */
|
|
11
|
+
rootDir: string;
|
|
12
|
+
}
|
|
13
|
+
/** 初始化文件选项 */
|
|
14
|
+
export type InitConfigFileOptions = ConfigFileCommonOptions;
|
|
15
|
+
/** 读取配置文件选项 */
|
|
16
|
+
export type ReadConfigFileOptions = ConfigFileCommonOptions;
|
|
17
|
+
/** 获取配置文件通用选项 */
|
|
18
|
+
export declare const getConfigFileCommonOptions: ({ configPathDefault, }: {
|
|
19
|
+
configPathDefault: string;
|
|
20
|
+
}) => Record<keyof ConfigFileCommonOptions, YargsOptions>;
|
|
21
|
+
/** 初始化配置文件 */
|
|
22
|
+
export declare const initConfigFile: <T>(content: T, argv: CliHandlerArgv<InitConfigFileOptions>) => Promise<string>;
|
|
23
|
+
/** 初始化配置文件通用处理器 */
|
|
24
|
+
export declare const initHandlerCommon: <T>(content: T, argv: CliHandlerArgv<InitConfigFileOptions>, { onFileGenerated, }?: {
|
|
25
|
+
/** 文件已生成 */
|
|
26
|
+
onFileGenerated?: ((path: string) => void) | undefined;
|
|
27
|
+
}) => Promise<void>;
|
|
28
|
+
/** 读取配置文件 */
|
|
29
|
+
export declare const readConfigFile: <T>(argv: CliHandlerArgv<ReadConfigFileOptions>) => Promise<T | undefined>;
|
|
30
|
+
/** 获取是否使用默认配置 */
|
|
31
|
+
export declare const getUseDefaultConfig: () => Promise<any>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** 编辑器类型枚举 */
|
|
2
|
+
export declare enum EditorTypeEnum {
|
|
3
|
+
/** vscode */
|
|
4
|
+
VSCODE = "VsCode",
|
|
5
|
+
/** cursor */
|
|
6
|
+
CURSOR = "Cursor",
|
|
7
|
+
/** 其他编辑器 */
|
|
8
|
+
OTHER = "\u5176\u4ED6"
|
|
9
|
+
}
|
|
10
|
+
/** 获取编辑器类型 */
|
|
11
|
+
export declare const getEditorType: () => Promise<any>;
|
|
12
|
+
/** 用编辑器打开文件 */
|
|
13
|
+
export declare const openFileInEditor: (path: string, editorType: EditorTypeEnum) => void;
|
package/types/index.d.ts
CHANGED
package/types/json5.d.ts
ADDED