meocli 0.1.5 → 0.1.7
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 +65 -25
- package/dist/commands/env/apifox.d.ts +13 -0
- package/dist/commands/env/apifox.js +49 -0
- package/dist/commands/env/index.js +3 -2
- package/dist/commands/js/clash.d.ts +12 -0
- package/dist/commands/js/clash.js +491 -0
- package/dist/consts/prettierrc.js +84 -79
- package/dist/lib/ast.d.ts +8 -0
- package/dist/lib/ast.js +63 -0
- package/dist/tests/d3-test.js +1 -1
- package/oclif.manifest.json +79 -2
- package/package.json +18 -11
package/README.md
CHANGED
|
@@ -48,56 +48,48 @@ $ me prettier ./test.svg --verbose # 使用prettier格式化文件
|
|
|
48
48
|
3. 配置 `.vscode/settings.json` 添加 `"emeraldwalk.runonsave"` 节点,以下为参考配置⤵︎
|
|
49
49
|
|
|
50
50
|
```json
|
|
51
|
-
{
|
|
52
|
-
"emeraldwalk.runonsave": {
|
|
51
|
+
"emeraldwalk.runonsave": {
|
|
53
52
|
"commands": [
|
|
54
53
|
{
|
|
55
54
|
// prettier
|
|
56
|
-
"match": "\\.(ts|js|json|html|css|graphql|gql|yaml|yml|md)$",
|
|
55
|
+
"match": "\\.(txt|ts|js|jsx|tsx|json|html|css|graphql|gql|yaml|yml|md)$",
|
|
57
56
|
"notMatch": "node_modules/*$",
|
|
58
57
|
"isAsync": true,
|
|
59
|
-
"cmd": "me prettier ${file}"
|
|
58
|
+
"cmd": "me prettier \"${file}\""
|
|
60
59
|
},
|
|
61
60
|
{
|
|
62
61
|
// @prettier/plugin-xml
|
|
63
62
|
"match": "\\.(xml|svg)$",
|
|
64
63
|
"isAsync": true,
|
|
65
|
-
"cmd": "me prettier ${file}"
|
|
64
|
+
"cmd": "me prettier \"${file}\""
|
|
66
65
|
},
|
|
67
66
|
{
|
|
68
67
|
// prettier-plugin-toml
|
|
69
68
|
"match": "\\.(toml)$",
|
|
70
69
|
"isAsync": true,
|
|
71
|
-
"cmd": "me prettier ${file}"
|
|
70
|
+
"cmd": "me prettier \"${file}\""
|
|
72
71
|
},
|
|
73
72
|
{
|
|
74
73
|
// prettier-plugin-nginx
|
|
75
74
|
"match": "\\.(nginx)$",
|
|
76
75
|
"isAsync": true,
|
|
77
|
-
"cmd": "me prettier ${file}"
|
|
76
|
+
"cmd": "me prettier \"${file}\""
|
|
78
77
|
},
|
|
79
78
|
{
|
|
80
79
|
// prettier-plugin-sh
|
|
81
80
|
"match": "\\.(sh|env|Dockerfile|properties|gitignore|dockerignore|prettierignore)$",
|
|
82
81
|
"notMatch": "\\.(nu)$",
|
|
83
82
|
"isAsync": true,
|
|
84
|
-
"cmd": "me prettier ${file}"
|
|
83
|
+
"cmd": "me prettier \"${file}\""
|
|
85
84
|
},
|
|
86
85
|
{
|
|
87
86
|
// no-dot-ext
|
|
88
|
-
"match": "Dockerfile
|
|
87
|
+
"match": "Dockerfile$|web.config",
|
|
89
88
|
"isAsync": true,
|
|
90
|
-
"cmd": "me prettier ${file}"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
// nushell
|
|
94
|
-
"match": "\\.(nu)$",
|
|
95
|
-
"isAsync": true,
|
|
96
|
-
"cmd": "topiary format ${file}"
|
|
89
|
+
"cmd": "me prettier \"${file}\""
|
|
97
90
|
}
|
|
98
91
|
]
|
|
99
92
|
}
|
|
100
|
-
}
|
|
101
93
|
```
|
|
102
94
|
|
|
103
95
|
# Publish
|
|
@@ -116,7 +108,7 @@ $ npm install -g meocli
|
|
|
116
108
|
$ me COMMAND
|
|
117
109
|
running command...
|
|
118
110
|
$ me (--version)
|
|
119
|
-
meocli/0.1.
|
|
111
|
+
meocli/0.1.7 win32-x64 node-v24.14.0
|
|
120
112
|
$ me --help [COMMAND]
|
|
121
113
|
USAGE
|
|
122
114
|
$ me COMMAND
|
|
@@ -128,9 +120,11 @@ USAGE
|
|
|
128
120
|
|
|
129
121
|
<!-- commands -->
|
|
130
122
|
* [`me env [FILEPATH]`](#me-env-filepath)
|
|
123
|
+
* [`me env apifox [FILEPATH]`](#me-env-apifox-filepath)
|
|
131
124
|
* [`me hello PERSON`](#me-hello-person)
|
|
132
125
|
* [`me hello world`](#me-hello-world)
|
|
133
126
|
* [`me help [COMMAND]`](#me-help-command)
|
|
127
|
+
* [`me js clash FILEPATH`](#me-js-clash-filepath)
|
|
134
128
|
* [`me plugins`](#me-plugins)
|
|
135
129
|
* [`me plugins add PLUGIN`](#me-plugins-add-plugin)
|
|
136
130
|
* [`me plugins:inspect PLUGIN...`](#me-pluginsinspect-plugin)
|
|
@@ -146,7 +140,7 @@ USAGE
|
|
|
146
140
|
|
|
147
141
|
## `me env [FILEPATH]`
|
|
148
142
|
|
|
149
|
-
读取.env
|
|
143
|
+
读取.env环境变量并打印(json格式)
|
|
150
144
|
|
|
151
145
|
```
|
|
152
146
|
USAGE
|
|
@@ -159,13 +153,36 @@ FLAGS
|
|
|
159
153
|
-v, --verbose Show verbose output
|
|
160
154
|
|
|
161
155
|
DESCRIPTION
|
|
162
|
-
读取.env
|
|
156
|
+
读取.env环境变量并打印(json格式)
|
|
163
157
|
|
|
164
158
|
EXAMPLES
|
|
165
159
|
me env .env
|
|
166
160
|
```
|
|
167
161
|
|
|
168
|
-
_See code: [src/commands/env/index.ts](https://github.com/meme2046/meocli/blob/v0.1.
|
|
162
|
+
_See code: [src/commands/env/index.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/env/index.ts)_
|
|
163
|
+
|
|
164
|
+
## `me env apifox [FILEPATH]`
|
|
165
|
+
|
|
166
|
+
读取.env环境变量,输出apifox需要的csv格式
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
USAGE
|
|
170
|
+
$ me env apifox [FILEPATH] [-v]
|
|
171
|
+
|
|
172
|
+
ARGUMENTS
|
|
173
|
+
[FILEPATH] [default: .env] .env文件路径,不传默认值为.env
|
|
174
|
+
|
|
175
|
+
FLAGS
|
|
176
|
+
-v, --verbose Show verbose output
|
|
177
|
+
|
|
178
|
+
DESCRIPTION
|
|
179
|
+
读取.env环境变量,输出apifox需要的csv格式
|
|
180
|
+
|
|
181
|
+
EXAMPLES
|
|
182
|
+
me env apifox .env
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
_See code: [src/commands/env/apifox.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/env/apifox.ts)_
|
|
169
186
|
|
|
170
187
|
## `me hello PERSON`
|
|
171
188
|
|
|
@@ -189,7 +206,7 @@ EXAMPLES
|
|
|
189
206
|
hello friend --from oclif (./src/commands/hello/index.ts)
|
|
190
207
|
```
|
|
191
208
|
|
|
192
|
-
_See code: [src/commands/hello/index.ts](https://github.com/meme2046/meocli/blob/v0.1.
|
|
209
|
+
_See code: [src/commands/hello/index.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/hello/index.ts)_
|
|
193
210
|
|
|
194
211
|
## `me hello world`
|
|
195
212
|
|
|
@@ -207,7 +224,7 @@ EXAMPLES
|
|
|
207
224
|
hello world! (./src/commands/hello/world.ts)
|
|
208
225
|
```
|
|
209
226
|
|
|
210
|
-
_See code: [src/commands/hello/world.ts](https://github.com/meme2046/meocli/blob/v0.1.
|
|
227
|
+
_See code: [src/commands/hello/world.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/hello/world.ts)_
|
|
211
228
|
|
|
212
229
|
## `me help [COMMAND]`
|
|
213
230
|
|
|
@@ -229,6 +246,29 @@ DESCRIPTION
|
|
|
229
246
|
|
|
230
247
|
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.37/src/commands/help.ts)_
|
|
231
248
|
|
|
249
|
+
## `me js clash FILEPATH`
|
|
250
|
+
|
|
251
|
+
修改Clash脚本
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
USAGE
|
|
255
|
+
$ me js clash FILEPATH [-v]
|
|
256
|
+
|
|
257
|
+
ARGUMENTS
|
|
258
|
+
FILEPATH 目标js文件路径
|
|
259
|
+
|
|
260
|
+
FLAGS
|
|
261
|
+
-v, --verbose Show verbose output
|
|
262
|
+
|
|
263
|
+
DESCRIPTION
|
|
264
|
+
修改Clash脚本
|
|
265
|
+
|
|
266
|
+
EXAMPLES
|
|
267
|
+
$ me js clash ./tests/test.js
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
_See code: [src/commands/js/clash.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/js/clash.ts)_
|
|
271
|
+
|
|
232
272
|
## `me plugins`
|
|
233
273
|
|
|
234
274
|
List installed plugins.
|
|
@@ -547,7 +587,7 @@ EXAMPLES
|
|
|
547
587
|
$ me prettier ./src/file.ts --config ./.prettierrc.yaml
|
|
548
588
|
```
|
|
549
589
|
|
|
550
|
-
_See code: [src/commands/prettier/index.ts](https://github.com/meme2046/meocli/blob/v0.1.
|
|
590
|
+
_See code: [src/commands/prettier/index.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/prettier/index.ts)_
|
|
551
591
|
|
|
552
592
|
## `me prettier reset`
|
|
553
593
|
|
|
@@ -567,5 +607,5 @@ EXAMPLES
|
|
|
567
607
|
$ me prettier reset --verbose
|
|
568
608
|
```
|
|
569
609
|
|
|
570
|
-
_See code: [src/commands/prettier/reset.ts](https://github.com/meme2046/meocli/blob/v0.1.
|
|
610
|
+
_See code: [src/commands/prettier/reset.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/prettier/reset.ts)_
|
|
571
611
|
<!-- commandsstop -->
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
export default class Apifox extends Command {
|
|
4
|
+
static args: {
|
|
5
|
+
filePath: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
static flags: {
|
|
10
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<dotenv.DotenvParseOutput | undefined>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Args, Command, Flags } from "@oclif/core";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { require } from "../../lib/commonjs.js";
|
|
5
|
+
export default class Apifox extends Command {
|
|
6
|
+
static args = {
|
|
7
|
+
filePath: Args.string({
|
|
8
|
+
default: ".env",
|
|
9
|
+
description: ".env文件路径,不传默认值为.env",
|
|
10
|
+
required: false,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = "读取.env环境变量,输出apifox需要的csv格式";
|
|
14
|
+
static examples = [
|
|
15
|
+
`
|
|
16
|
+
<%= config.bin %> <%= command.id %> .env
|
|
17
|
+
`,
|
|
18
|
+
];
|
|
19
|
+
static flags = {
|
|
20
|
+
verbose: Flags.boolean({
|
|
21
|
+
char: "v",
|
|
22
|
+
default: false,
|
|
23
|
+
description: "Show verbose output",
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { args, flags } = await this.parse(Apifox);
|
|
28
|
+
const { filePath } = args;
|
|
29
|
+
const { verbose } = flags;
|
|
30
|
+
if (!existsSync(filePath)) {
|
|
31
|
+
this.log(`✘ 『${filePath}』 not found!`);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
if (verbose) {
|
|
35
|
+
process.env.DEBUG = "oclif:me:env:apifox";
|
|
36
|
+
require("debug").enable(process.env.DEBUG);
|
|
37
|
+
}
|
|
38
|
+
const envConfig = dotenv.config({
|
|
39
|
+
path: filePath,
|
|
40
|
+
}).parsed;
|
|
41
|
+
if (envConfig) {
|
|
42
|
+
this.debug(`✔ 『${filePath}』`);
|
|
43
|
+
for (const [key, value] of Object.entries(envConfig || {})) {
|
|
44
|
+
console.log(`${key},default,,false,${value},`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return envConfig;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -10,7 +10,7 @@ export default class Env extends Command {
|
|
|
10
10
|
required: false,
|
|
11
11
|
}),
|
|
12
12
|
};
|
|
13
|
-
static description = "读取.env
|
|
13
|
+
static description = "读取.env环境变量并打印(json格式)";
|
|
14
14
|
static examples = [
|
|
15
15
|
`
|
|
16
16
|
<%= config.bin %> <%= command.id %> .env
|
|
@@ -39,7 +39,8 @@ export default class Env extends Command {
|
|
|
39
39
|
path: filePath,
|
|
40
40
|
}).parsed;
|
|
41
41
|
if (envConfig) {
|
|
42
|
-
this.debug(
|
|
42
|
+
this.debug(`✔ 『${filePath}』\n`);
|
|
43
|
+
this.log(JSON.stringify(envConfig, null, 2));
|
|
43
44
|
}
|
|
44
45
|
return envConfig;
|
|
45
46
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class ClashModify extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
filePath: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import traverse from "@babel/traverse";
|
|
2
|
+
import { Args, Command, Flags } from "@oclif/core";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { extname } from "node:path";
|
|
5
|
+
import { objToAst, readJsAst, writeAst } from "../../lib/ast.js";
|
|
6
|
+
import { require } from "../../lib/commonjs.js";
|
|
7
|
+
export default class ClashModify extends Command {
|
|
8
|
+
static args = {
|
|
9
|
+
filePath: Args.string({
|
|
10
|
+
description: "目标js文件路径",
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static description = "修改Clash脚本";
|
|
15
|
+
static examples = ["<%= config.bin %> <%= command.id %> ./tests/test.js"];
|
|
16
|
+
static flags = {
|
|
17
|
+
verbose: Flags.boolean({
|
|
18
|
+
char: "v",
|
|
19
|
+
default: false,
|
|
20
|
+
description: "Show verbose output",
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
// https://github.com/IvanSolis1989/Smart-Config-Kit/tree/main/Clash%20Party
|
|
24
|
+
async run() {
|
|
25
|
+
// 目标 myCustomRules
|
|
26
|
+
const customRules = [
|
|
27
|
+
"RULE-SET,my-direct,DIRECT",
|
|
28
|
+
"RULE-SET,my-reject,REJECT",
|
|
29
|
+
"RULE-SET,my-proxy,🌍 全球节点",
|
|
30
|
+
];
|
|
31
|
+
// 目标 rule-providers 配置
|
|
32
|
+
const ruleProviders = {
|
|
33
|
+
"my-direct": {
|
|
34
|
+
behavior: "classical",
|
|
35
|
+
format: "yaml",
|
|
36
|
+
interval: 3600,
|
|
37
|
+
path: "./ruleset/my-direct.yaml",
|
|
38
|
+
type: "http",
|
|
39
|
+
url: "https://raw.githubusercontent.com/meme2046/data/main/clash/direct.yaml?_t={{timestamp}}",
|
|
40
|
+
},
|
|
41
|
+
"my-proxy": {
|
|
42
|
+
behavior: "classical",
|
|
43
|
+
format: "yaml",
|
|
44
|
+
interval: 3600,
|
|
45
|
+
path: "./ruleset/my-proxy.yaml",
|
|
46
|
+
type: "http",
|
|
47
|
+
url: "https://raw.githubusercontent.com/meme2046/data/main/clash/proxy.yaml?_t={{timestamp}}",
|
|
48
|
+
},
|
|
49
|
+
"my-reject": {
|
|
50
|
+
behavior: "classical",
|
|
51
|
+
format: "yaml",
|
|
52
|
+
interval: 3600,
|
|
53
|
+
path: "./ruleset/my-reject.yaml",
|
|
54
|
+
type: "http",
|
|
55
|
+
url: "https://raw.githubusercontent.com/meme2046/data/main/clash/reject.yaml?_t={{timestamp}}",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const { args, flags } = await this.parse(ClashModify);
|
|
59
|
+
const { filePath } = args;
|
|
60
|
+
const { verbose } = flags;
|
|
61
|
+
if (verbose) {
|
|
62
|
+
process.env.DEBUG = "oclif:me:js";
|
|
63
|
+
require("debug").enable(process.env.DEBUG);
|
|
64
|
+
}
|
|
65
|
+
// 检查文件是否存在
|
|
66
|
+
if (!existsSync(filePath)) {
|
|
67
|
+
this.error(`file『${filePath}』not found`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// 1. 读取并解析AST
|
|
71
|
+
const ast = await readJsAst(filePath);
|
|
72
|
+
traverse(ast, {
|
|
73
|
+
// 修改 injectRuleProviders、injectRules 和 overwriteGeneral 函数
|
|
74
|
+
FunctionDeclaration: (path) => {
|
|
75
|
+
// 修改 injectRuleProviders 函数内的 rule-providers
|
|
76
|
+
if (path.node.id?.name === "injectRuleProviders") {
|
|
77
|
+
// 找到 if (!config["rule-providers"]) config["rule-providers"] = {}; 的位置
|
|
78
|
+
let insertIndex = 0;
|
|
79
|
+
for (let i = 0; i < path.node.body.body.length; i++) {
|
|
80
|
+
const stmt = path.node.body.body[i];
|
|
81
|
+
// 匹配 if 语句
|
|
82
|
+
if (stmt.type === "IfStatement" &&
|
|
83
|
+
stmt.test.type === "UnaryExpression" &&
|
|
84
|
+
stmt.test.operator === "!" &&
|
|
85
|
+
stmt.test.argument.type === "MemberExpression" &&
|
|
86
|
+
stmt.test.argument.object.type === "Identifier" &&
|
|
87
|
+
stmt.test.argument.object.name === "config" &&
|
|
88
|
+
stmt.test.argument.property.type === "StringLiteral" &&
|
|
89
|
+
stmt.test.argument.property.value === "rule-providers") {
|
|
90
|
+
insertIndex = i + 1; // 在 if 语句之后插入
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 在找到的位置之后插入新的赋值语句
|
|
95
|
+
for (const [name, cfg] of Object.entries(ruleProviders)) {
|
|
96
|
+
const newAssignment = {
|
|
97
|
+
expression: {
|
|
98
|
+
left: {
|
|
99
|
+
computed: true,
|
|
100
|
+
object: {
|
|
101
|
+
computed: true,
|
|
102
|
+
object: { name: "config", type: "Identifier" },
|
|
103
|
+
property: {
|
|
104
|
+
type: "StringLiteral",
|
|
105
|
+
value: "rule-providers",
|
|
106
|
+
},
|
|
107
|
+
type: "MemberExpression",
|
|
108
|
+
},
|
|
109
|
+
property: { type: "StringLiteral", value: name },
|
|
110
|
+
type: "MemberExpression",
|
|
111
|
+
},
|
|
112
|
+
operator: "=",
|
|
113
|
+
right: objToAst(cfg),
|
|
114
|
+
type: "AssignmentExpression",
|
|
115
|
+
},
|
|
116
|
+
type: "ExpressionStatement",
|
|
117
|
+
};
|
|
118
|
+
// 使用 splice 在指定位置插入
|
|
119
|
+
path.node.body.body.splice(insertIndex, 0, newAssignment);
|
|
120
|
+
insertIndex++; // 下一个插入位置后移
|
|
121
|
+
this.log(`✔ rule-provider '${name}' 已添加/更新:`);
|
|
122
|
+
this.log(`${JSON.stringify(cfg, null, 2)}\n`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// 修改 injectRules 函数
|
|
126
|
+
if (path.node.id?.name === "injectRules") {
|
|
127
|
+
// 第一遍:删除已存在的 myCustomRules 声明
|
|
128
|
+
path.traverse({
|
|
129
|
+
VariableDeclarator: (innerPath) => {
|
|
130
|
+
const { id } = innerPath.node;
|
|
131
|
+
if (id.type === "Identifier" && id.name === "myCustomRules") {
|
|
132
|
+
innerPath.remove();
|
|
133
|
+
this.log("✔ 已删除原有的 myCustomRules\n");
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
// 添加新的 myCustomRules 到函数开头
|
|
138
|
+
const varDecl = {
|
|
139
|
+
declarations: [
|
|
140
|
+
{
|
|
141
|
+
id: { name: "myCustomRules", type: "Identifier" },
|
|
142
|
+
init: objToAst(customRules),
|
|
143
|
+
type: "VariableDeclarator",
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
kind: "const",
|
|
147
|
+
type: "VariableDeclaration",
|
|
148
|
+
};
|
|
149
|
+
path.node.body.body.unshift(varDecl);
|
|
150
|
+
this.log("✔ 已添加 myCustomRules:");
|
|
151
|
+
this.log(`${JSON.stringify(customRules, null, 2)}\n`);
|
|
152
|
+
// 在 config.rules 数组前面添加 ...myCustomRules
|
|
153
|
+
path.traverse({
|
|
154
|
+
AssignmentExpression: (innerPath) => {
|
|
155
|
+
const { left } = innerPath.node;
|
|
156
|
+
// 匹配 config.rules = [...] 赋值
|
|
157
|
+
if (left.type === "MemberExpression" &&
|
|
158
|
+
left.object.type === "Identifier" &&
|
|
159
|
+
left.object.name === "config" &&
|
|
160
|
+
left.property.type === "Identifier" &&
|
|
161
|
+
left.property.name === "rules" &&
|
|
162
|
+
innerPath.node.right.type === "ArrayExpression") {
|
|
163
|
+
const arrayExp = innerPath.node.right;
|
|
164
|
+
// 在数组开头插入展开表达式 ...myCustomRules
|
|
165
|
+
arrayExp.elements.unshift({
|
|
166
|
+
argument: { name: "myCustomRules", type: "Identifier" },
|
|
167
|
+
type: "SpreadElement",
|
|
168
|
+
});
|
|
169
|
+
this.log("✔ 已在 config.rules 前面添加 ...myCustomRules\n");
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// 修改 overwriteGeneral 函数
|
|
175
|
+
if (path.node.id?.name === "overwriteGeneral") {
|
|
176
|
+
const targetDomains = ["api.memeniu.xyz", "meme.us.kg"];
|
|
177
|
+
// 1. 声明 targetDomains 变量
|
|
178
|
+
const targetDomainsDecl = {
|
|
179
|
+
declarations: [
|
|
180
|
+
{
|
|
181
|
+
id: { name: "targetDomains", type: "Identifier" },
|
|
182
|
+
init: objToAst(targetDomains),
|
|
183
|
+
type: "VariableDeclarator",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
kind: "const",
|
|
187
|
+
type: "VariableDeclaration",
|
|
188
|
+
};
|
|
189
|
+
// 2. 设置 config.ipv6 = true
|
|
190
|
+
const ipv6Assign1 = {
|
|
191
|
+
expression: {
|
|
192
|
+
left: {
|
|
193
|
+
object: { name: "config", type: "Identifier" },
|
|
194
|
+
property: { name: "ipv6", type: "Identifier" },
|
|
195
|
+
type: "MemberExpression",
|
|
196
|
+
},
|
|
197
|
+
operator: "=",
|
|
198
|
+
right: { type: "BooleanLiteral", value: true },
|
|
199
|
+
type: "AssignmentExpression",
|
|
200
|
+
},
|
|
201
|
+
type: "ExpressionStatement",
|
|
202
|
+
};
|
|
203
|
+
// 3. 设置 config.dns.ipv6 = true
|
|
204
|
+
const ipv6Assign2 = {
|
|
205
|
+
expression: {
|
|
206
|
+
left: {
|
|
207
|
+
object: {
|
|
208
|
+
object: { name: "config", type: "Identifier" },
|
|
209
|
+
property: { name: "dns", type: "Identifier" },
|
|
210
|
+
type: "MemberExpression",
|
|
211
|
+
},
|
|
212
|
+
property: { name: "ipv6", type: "Identifier" },
|
|
213
|
+
type: "MemberExpression",
|
|
214
|
+
},
|
|
215
|
+
operator: "=",
|
|
216
|
+
right: { type: "BooleanLiteral", value: true },
|
|
217
|
+
type: "AssignmentExpression",
|
|
218
|
+
},
|
|
219
|
+
type: "ExpressionStatement",
|
|
220
|
+
};
|
|
221
|
+
// 4. 声明 ipv6Doh 数组
|
|
222
|
+
const ipv6DohDecl = {
|
|
223
|
+
declarations: [
|
|
224
|
+
{
|
|
225
|
+
id: { name: "ipv6Doh", type: "Identifier" },
|
|
226
|
+
init: {
|
|
227
|
+
elements: [
|
|
228
|
+
{
|
|
229
|
+
type: "StringLiteral",
|
|
230
|
+
value: "https://[2402:4e00::]/dns-query",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
type: "StringLiteral",
|
|
234
|
+
value: "https://[2400:3200::1]/dns-query",
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
type: "ArrayExpression",
|
|
238
|
+
},
|
|
239
|
+
type: "VariableDeclarator",
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
kind: "const",
|
|
243
|
+
type: "VariableDeclaration",
|
|
244
|
+
};
|
|
245
|
+
// 5. 声明 mixedDns 数组
|
|
246
|
+
const mixedDnsDecl = {
|
|
247
|
+
declarations: [
|
|
248
|
+
{
|
|
249
|
+
id: { name: "mixedDns", type: "Identifier" },
|
|
250
|
+
init: {
|
|
251
|
+
elements: [
|
|
252
|
+
{
|
|
253
|
+
argument: { name: "domesticDoH", type: "Identifier" },
|
|
254
|
+
type: "SpreadElement",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
argument: { name: "ipv6Doh", type: "Identifier" },
|
|
258
|
+
type: "SpreadElement",
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
type: "ArrayExpression",
|
|
262
|
+
},
|
|
263
|
+
type: "VariableDeclarator",
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
kind: "const",
|
|
267
|
+
type: "VariableDeclaration",
|
|
268
|
+
};
|
|
269
|
+
// 6. 循环给每个域名绑定混合DNS池
|
|
270
|
+
const forEachDnsPolicy = {
|
|
271
|
+
expression: {
|
|
272
|
+
arguments: [
|
|
273
|
+
{
|
|
274
|
+
body: {
|
|
275
|
+
body: [
|
|
276
|
+
{
|
|
277
|
+
consequent: {
|
|
278
|
+
body: [
|
|
279
|
+
{
|
|
280
|
+
expression: {
|
|
281
|
+
left: {
|
|
282
|
+
computed: true,
|
|
283
|
+
object: {
|
|
284
|
+
computed: true,
|
|
285
|
+
object: {
|
|
286
|
+
object: {
|
|
287
|
+
name: "config",
|
|
288
|
+
type: "Identifier",
|
|
289
|
+
},
|
|
290
|
+
property: {
|
|
291
|
+
name: "dns",
|
|
292
|
+
type: "Identifier",
|
|
293
|
+
},
|
|
294
|
+
type: "MemberExpression",
|
|
295
|
+
},
|
|
296
|
+
property: {
|
|
297
|
+
type: "StringLiteral",
|
|
298
|
+
value: "nameserver-policy",
|
|
299
|
+
},
|
|
300
|
+
type: "MemberExpression",
|
|
301
|
+
},
|
|
302
|
+
property: {
|
|
303
|
+
name: "host",
|
|
304
|
+
type: "Identifier",
|
|
305
|
+
},
|
|
306
|
+
type: "MemberExpression",
|
|
307
|
+
},
|
|
308
|
+
operator: "=",
|
|
309
|
+
right: {
|
|
310
|
+
arguments: [],
|
|
311
|
+
callee: {
|
|
312
|
+
object: {
|
|
313
|
+
name: "mixedDns",
|
|
314
|
+
type: "Identifier",
|
|
315
|
+
},
|
|
316
|
+
property: {
|
|
317
|
+
name: "slice",
|
|
318
|
+
type: "Identifier",
|
|
319
|
+
},
|
|
320
|
+
type: "MemberExpression",
|
|
321
|
+
},
|
|
322
|
+
type: "CallExpression",
|
|
323
|
+
},
|
|
324
|
+
type: "AssignmentExpression",
|
|
325
|
+
},
|
|
326
|
+
type: "ExpressionStatement",
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
type: "BlockStatement",
|
|
330
|
+
},
|
|
331
|
+
test: {
|
|
332
|
+
argument: {
|
|
333
|
+
computed: true,
|
|
334
|
+
object: {
|
|
335
|
+
computed: true,
|
|
336
|
+
object: {
|
|
337
|
+
object: { name: "config", type: "Identifier" },
|
|
338
|
+
property: { name: "dns", type: "Identifier" },
|
|
339
|
+
type: "MemberExpression",
|
|
340
|
+
},
|
|
341
|
+
property: {
|
|
342
|
+
type: "StringLiteral",
|
|
343
|
+
value: "nameserver-policy",
|
|
344
|
+
},
|
|
345
|
+
type: "MemberExpression",
|
|
346
|
+
},
|
|
347
|
+
property: { name: "host", type: "Identifier" },
|
|
348
|
+
type: "MemberExpression",
|
|
349
|
+
},
|
|
350
|
+
operator: "!",
|
|
351
|
+
type: "UnaryExpression",
|
|
352
|
+
},
|
|
353
|
+
type: "IfStatement",
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
type: "BlockStatement",
|
|
357
|
+
},
|
|
358
|
+
params: [{ name: "host", type: "Identifier" }],
|
|
359
|
+
type: "FunctionExpression",
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
callee: {
|
|
363
|
+
object: { name: "targetDomains", type: "Identifier" },
|
|
364
|
+
property: { name: "forEach", type: "Identifier" },
|
|
365
|
+
type: "MemberExpression",
|
|
366
|
+
},
|
|
367
|
+
type: "CallExpression",
|
|
368
|
+
},
|
|
369
|
+
type: "ExpressionStatement",
|
|
370
|
+
};
|
|
371
|
+
// 7. 加入fake-ip白名单
|
|
372
|
+
const forEachFakeIpFilter = {
|
|
373
|
+
expression: {
|
|
374
|
+
arguments: [
|
|
375
|
+
{
|
|
376
|
+
body: {
|
|
377
|
+
body: [
|
|
378
|
+
{
|
|
379
|
+
consequent: {
|
|
380
|
+
body: [
|
|
381
|
+
{
|
|
382
|
+
expression: {
|
|
383
|
+
arguments: [
|
|
384
|
+
{ name: "domain", type: "Identifier" },
|
|
385
|
+
],
|
|
386
|
+
callee: {
|
|
387
|
+
object: {
|
|
388
|
+
computed: true,
|
|
389
|
+
object: {
|
|
390
|
+
object: {
|
|
391
|
+
name: "config",
|
|
392
|
+
type: "Identifier",
|
|
393
|
+
},
|
|
394
|
+
property: {
|
|
395
|
+
name: "dns",
|
|
396
|
+
type: "Identifier",
|
|
397
|
+
},
|
|
398
|
+
type: "MemberExpression",
|
|
399
|
+
},
|
|
400
|
+
property: {
|
|
401
|
+
type: "StringLiteral",
|
|
402
|
+
value: "fake-ip-filter",
|
|
403
|
+
},
|
|
404
|
+
type: "MemberExpression",
|
|
405
|
+
},
|
|
406
|
+
property: {
|
|
407
|
+
name: "push",
|
|
408
|
+
type: "Identifier",
|
|
409
|
+
},
|
|
410
|
+
type: "MemberExpression",
|
|
411
|
+
},
|
|
412
|
+
type: "CallExpression",
|
|
413
|
+
},
|
|
414
|
+
type: "ExpressionStatement",
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
type: "BlockStatement",
|
|
418
|
+
},
|
|
419
|
+
test: {
|
|
420
|
+
argument: {
|
|
421
|
+
arguments: [{ name: "domain", type: "Identifier" }],
|
|
422
|
+
callee: {
|
|
423
|
+
object: {
|
|
424
|
+
computed: true,
|
|
425
|
+
object: {
|
|
426
|
+
object: {
|
|
427
|
+
name: "config",
|
|
428
|
+
type: "Identifier",
|
|
429
|
+
},
|
|
430
|
+
property: { name: "dns", type: "Identifier" },
|
|
431
|
+
type: "MemberExpression",
|
|
432
|
+
},
|
|
433
|
+
property: {
|
|
434
|
+
type: "StringLiteral",
|
|
435
|
+
value: "fake-ip-filter",
|
|
436
|
+
},
|
|
437
|
+
type: "MemberExpression",
|
|
438
|
+
},
|
|
439
|
+
property: {
|
|
440
|
+
name: "includes",
|
|
441
|
+
type: "Identifier",
|
|
442
|
+
},
|
|
443
|
+
type: "MemberExpression",
|
|
444
|
+
},
|
|
445
|
+
type: "CallExpression",
|
|
446
|
+
},
|
|
447
|
+
operator: "!",
|
|
448
|
+
type: "UnaryExpression",
|
|
449
|
+
},
|
|
450
|
+
type: "IfStatement",
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
type: "BlockStatement",
|
|
454
|
+
},
|
|
455
|
+
params: [{ name: "domain", type: "Identifier" }],
|
|
456
|
+
type: "FunctionExpression",
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
callee: {
|
|
460
|
+
object: { name: "targetDomains", type: "Identifier" },
|
|
461
|
+
property: { name: "forEach", type: "Identifier" },
|
|
462
|
+
type: "MemberExpression",
|
|
463
|
+
},
|
|
464
|
+
type: "CallExpression",
|
|
465
|
+
},
|
|
466
|
+
type: "ExpressionStatement",
|
|
467
|
+
};
|
|
468
|
+
// 将所有新语句插入到函数末尾
|
|
469
|
+
const newStatements = [
|
|
470
|
+
targetDomainsDecl,
|
|
471
|
+
ipv6Assign1,
|
|
472
|
+
ipv6Assign2,
|
|
473
|
+
ipv6DohDecl,
|
|
474
|
+
mixedDnsDecl,
|
|
475
|
+
forEachDnsPolicy,
|
|
476
|
+
forEachFakeIpFilter,
|
|
477
|
+
];
|
|
478
|
+
path.node.body.body.push(...newStatements);
|
|
479
|
+
this.log("✔ 已在 overwriteGeneral 函数末尾添加 IPv6 配置代码\n");
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
// 生成新文件名
|
|
484
|
+
const ext = extname(filePath); // 获取扩展名(如 .js)
|
|
485
|
+
const baseName = filePath.slice(0, -ext.length); // 获取去掉扩展名的文件名
|
|
486
|
+
const outputPath = `${baseName}_update${ext}`; // 拼接新文件名
|
|
487
|
+
await writeAst(ast, outputPath); // 保存到新文件
|
|
488
|
+
// 3. 写回文件
|
|
489
|
+
this.log("✔ 自定义clash配置添加完成");
|
|
490
|
+
}
|
|
491
|
+
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
export const DEFAULT_ARGS = [
|
|
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
|
-
|
|
2
|
+
"--arrow-parens",
|
|
3
|
+
"always",
|
|
4
|
+
"--bracket-same-line",
|
|
5
|
+
"false",
|
|
6
|
+
"--object-wrap",
|
|
7
|
+
"preserve",
|
|
8
|
+
"--experimental-operator-position",
|
|
9
|
+
"end",
|
|
10
|
+
"--no-experimental-ternaries",
|
|
11
|
+
"--single-quote",
|
|
12
|
+
"false",
|
|
13
|
+
"--jsx-single-quote",
|
|
14
|
+
"false",
|
|
15
|
+
"--quote-props",
|
|
16
|
+
"as-needed",
|
|
17
|
+
"--trailing-comma",
|
|
18
|
+
"all",
|
|
19
|
+
"--single-attribute-per-line",
|
|
20
|
+
"false",
|
|
21
|
+
"--html-whitespace-sensitivity",
|
|
22
|
+
"css",
|
|
23
|
+
"--vue-indent-script-and-style",
|
|
24
|
+
"false",
|
|
25
|
+
"--prose-wrap",
|
|
26
|
+
"preserve",
|
|
27
|
+
"--end-of-line",
|
|
28
|
+
"lf",
|
|
29
|
+
"--insert-pragma",
|
|
30
|
+
"false",
|
|
31
|
+
"--print-width",
|
|
32
|
+
"80",
|
|
33
|
+
"--require-pragma",
|
|
34
|
+
"false",
|
|
35
|
+
"--tab-width",
|
|
36
|
+
"2",
|
|
37
|
+
"--use-tabs",
|
|
38
|
+
"false",
|
|
39
|
+
"--embedded-language-formatting",
|
|
40
|
+
"auto",
|
|
41
41
|
// plugins
|
|
42
42
|
// '--plugin',
|
|
43
43
|
// '@prettier/plugin-xml',
|
|
@@ -48,74 +48,79 @@ export const DEFAULT_ARGS = [
|
|
|
48
48
|
// '--plugin',
|
|
49
49
|
// 'prettier-plugin-nginx',
|
|
50
50
|
// xml
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
"--xml-whitespace-sensitivity",
|
|
52
|
+
"strict",
|
|
53
|
+
"--xml-sort-attributes-by-key",
|
|
54
|
+
"true",
|
|
55
|
+
"--xml-self-closing-space",
|
|
56
|
+
"true",
|
|
57
57
|
// toml
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
"--indent-entries",
|
|
59
|
+
"true",
|
|
60
|
+
"--reorder-keys",
|
|
61
|
+
"true",
|
|
62
62
|
// nginx
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
"--wrap-parameters",
|
|
64
|
+
"false",
|
|
65
|
+
"--continuation-indent",
|
|
66
|
+
"2",
|
|
67
67
|
];
|
|
68
68
|
export const DEFAULT_CONFIG = {
|
|
69
|
-
arrowParens:
|
|
70
|
-
bracketSameLine:
|
|
69
|
+
arrowParens: "always",
|
|
70
|
+
bracketSameLine: true,
|
|
71
71
|
bracketSpacing: true,
|
|
72
72
|
continuationIndent: 2, // nginx
|
|
73
|
-
embeddedLanguageFormatting:
|
|
74
|
-
endOfLine:
|
|
75
|
-
experimentalOperatorPosition:
|
|
73
|
+
embeddedLanguageFormatting: "auto",
|
|
74
|
+
endOfLine: "lf",
|
|
75
|
+
experimentalOperatorPosition: "end",
|
|
76
76
|
experimentalTernaries: false,
|
|
77
|
-
htmlWhitespaceSensitivity:
|
|
77
|
+
htmlWhitespaceSensitivity: "css",
|
|
78
78
|
indentEntries: true, // toml
|
|
79
79
|
insertPragma: false,
|
|
80
80
|
jsxSingleQuote: false,
|
|
81
|
-
objectWrap:
|
|
81
|
+
objectWrap: "preserve",
|
|
82
82
|
overrides: [
|
|
83
|
-
{ files: [
|
|
84
|
-
{ files: [
|
|
83
|
+
{ files: ["*.env"], options: { parser: "sh" } },
|
|
84
|
+
{ files: ["*.txt"], options: { parser: "markdown" } },
|
|
85
|
+
],
|
|
86
|
+
plugins: [
|
|
87
|
+
"@prettier/plugin-xml",
|
|
88
|
+
"prettier-plugin-toml",
|
|
89
|
+
"prettier-plugin-sh",
|
|
90
|
+
"prettier-plugin-nginx",
|
|
85
91
|
],
|
|
86
|
-
plugins: ['@prettier/plugin-xml', 'prettier-plugin-toml', 'prettier-plugin-sh', 'prettier-plugin-nginx'],
|
|
87
92
|
printWidth: 80,
|
|
88
|
-
proseWrap:
|
|
89
|
-
quoteProps:
|
|
93
|
+
proseWrap: "preserve",
|
|
94
|
+
quoteProps: "as-needed",
|
|
90
95
|
reorderKeys: true, // toml
|
|
91
96
|
requirePragma: false,
|
|
92
97
|
semi: true,
|
|
93
98
|
singleAttributePerLine: false,
|
|
94
99
|
singleQuote: false,
|
|
95
100
|
tabWidth: 2,
|
|
96
|
-
trailingComma:
|
|
101
|
+
trailingComma: "all",
|
|
97
102
|
useTabs: false, // useTabs 和 tabWidth 不能同时使用
|
|
98
103
|
vueIndentScriptAndStyle: false,
|
|
99
104
|
wrapParameters: false, // nginx
|
|
100
105
|
xmlSelfClosingSpace: true, // xml
|
|
101
106
|
xmlSortAttributesByKey: true, // xml
|
|
102
|
-
xmlWhitespaceSensitivity:
|
|
107
|
+
xmlWhitespaceSensitivity: "ignore", // xml
|
|
103
108
|
};
|
|
104
109
|
// 默认的 Prettier 插件列表
|
|
105
110
|
export const DEFAULT_PLUGINS = [
|
|
106
|
-
{ main:
|
|
107
|
-
{ main:
|
|
108
|
-
{ main:
|
|
109
|
-
{ main:
|
|
111
|
+
{ main: "src/plugin.js", name: "@prettier/plugin-xml" },
|
|
112
|
+
{ main: "lib/index.cjs", name: "prettier-plugin-toml" },
|
|
113
|
+
{ main: "lib/index.cjs", name: "prettier-plugin-sh" },
|
|
114
|
+
{ main: "dist/index.js", name: "prettier-plugin-nginx" },
|
|
110
115
|
];
|
|
111
116
|
// 默认的忽略模式
|
|
112
117
|
export const DEFAULT_IGNORE_PATTERNS = [
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
"node_modules/",
|
|
119
|
+
"dist/",
|
|
120
|
+
"build/",
|
|
121
|
+
".nyc_output/",
|
|
122
|
+
"coverage/",
|
|
123
|
+
".next/",
|
|
124
|
+
"out/",
|
|
125
|
+
"*.nu",
|
|
121
126
|
];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
/** JS对象转babel ObjectExpression AST节点 */
|
|
3
|
+
/** JS值转babel AST节点(支持对象和数组) */
|
|
4
|
+
export declare function objToAst(value: Record<string, unknown> | unknown[]): t.Expression;
|
|
5
|
+
/** 读取JS文件并返回AST */
|
|
6
|
+
export declare function readJsAst(filePath: string): Promise<import("@babel/parser").ParseResult<t.File>>;
|
|
7
|
+
/** AST 生成并覆盖写入文件 */
|
|
8
|
+
export declare function writeAst(ast: t.Node, filePath: string): Promise<void>;
|
package/dist/lib/ast.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { generate } from "@babel/generator";
|
|
2
|
+
import { parse } from "@babel/parser";
|
|
3
|
+
import * as t from "@babel/types";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
/** 创建字面量节点 */
|
|
6
|
+
function createLiteralNode(value) {
|
|
7
|
+
if (typeof value === "string")
|
|
8
|
+
return t.stringLiteral(value);
|
|
9
|
+
if (typeof value === "number")
|
|
10
|
+
return t.numericLiteral(value);
|
|
11
|
+
if (typeof value === "boolean")
|
|
12
|
+
return t.booleanLiteral(value);
|
|
13
|
+
return t.stringLiteral(String(value));
|
|
14
|
+
}
|
|
15
|
+
/** JS对象转babel ObjectExpression AST节点 */
|
|
16
|
+
/** JS值转babel AST节点(支持对象和数组) */
|
|
17
|
+
export function objToAst(value) {
|
|
18
|
+
// 如果是数组
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
const elements = value.map((item) => {
|
|
21
|
+
if (typeof item === "string" ||
|
|
22
|
+
typeof item === "number" ||
|
|
23
|
+
typeof item === "boolean") {
|
|
24
|
+
return createLiteralNode(item);
|
|
25
|
+
}
|
|
26
|
+
// 递归处理嵌套对象/数组
|
|
27
|
+
return objToAst(item);
|
|
28
|
+
});
|
|
29
|
+
return t.arrayExpression(elements);
|
|
30
|
+
}
|
|
31
|
+
// 如果是对象
|
|
32
|
+
const props = [];
|
|
33
|
+
for (const [k, v] of Object.entries(value)) {
|
|
34
|
+
let valNode;
|
|
35
|
+
if (typeof v === "string" ||
|
|
36
|
+
typeof v === "number" ||
|
|
37
|
+
typeof v === "boolean") {
|
|
38
|
+
valNode = createLiteralNode(v);
|
|
39
|
+
}
|
|
40
|
+
else if (Array.isArray(v)) {
|
|
41
|
+
// 递归处理数组
|
|
42
|
+
valNode = objToAst(v);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// 递归处理嵌套对象
|
|
46
|
+
valNode = objToAst(v);
|
|
47
|
+
}
|
|
48
|
+
props.push(t.objectProperty(t.identifier(k), valNode));
|
|
49
|
+
}
|
|
50
|
+
return t.objectExpression(props);
|
|
51
|
+
}
|
|
52
|
+
/** 读取JS文件并返回AST */
|
|
53
|
+
export async function readJsAst(filePath) {
|
|
54
|
+
const source = await fs.readFile(filePath, "utf8");
|
|
55
|
+
return parse(source, {
|
|
56
|
+
sourceType: "script",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** AST 生成并覆盖写入文件 */
|
|
60
|
+
export async function writeAst(ast, filePath) {
|
|
61
|
+
const output = generate(ast, { compact: false, retainLines: true }).code;
|
|
62
|
+
await fs.writeFile(filePath, output, "utf8");
|
|
63
|
+
}
|
package/dist/tests/d3-test.js
CHANGED
|
@@ -12,4 +12,4 @@ console.log(formatNumberWithUnit(1));
|
|
|
12
12
|
console.log(formatNumberWithUnit(150_123)); // 输出: 150.1k
|
|
13
13
|
console.log(formatNumberWithUnit(23_200_000)); // 输出: 23.2M
|
|
14
14
|
console.log(formatNumberWithUnit(1_600_000_000)); // 输出: 1.6B
|
|
15
|
-
console.log(formatNumberWithUnit(123_456, 2)); // 输出:
|
|
15
|
+
console.log(formatNumberWithUnit(123_456, 2)); // 输出: 124.46k(自定义精度)
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
|
+
"env:apifox": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {
|
|
6
|
+
"filePath": {
|
|
7
|
+
"default": ".env",
|
|
8
|
+
"description": ".env文件路径,不传默认值为.env",
|
|
9
|
+
"name": "filePath",
|
|
10
|
+
"required": false
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"description": "读取.env环境变量,输出apifox需要的csv格式",
|
|
14
|
+
"examples": [
|
|
15
|
+
"\n <%= config.bin %> <%= command.id %> .env\n "
|
|
16
|
+
],
|
|
17
|
+
"flags": {
|
|
18
|
+
"verbose": {
|
|
19
|
+
"char": "v",
|
|
20
|
+
"description": "Show verbose output",
|
|
21
|
+
"name": "verbose",
|
|
22
|
+
"allowNo": false,
|
|
23
|
+
"type": "boolean"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"hasDynamicHelp": false,
|
|
27
|
+
"hiddenAliases": [],
|
|
28
|
+
"id": "env:apifox",
|
|
29
|
+
"pluginAlias": "meocli",
|
|
30
|
+
"pluginName": "meocli",
|
|
31
|
+
"pluginType": "core",
|
|
32
|
+
"strict": true,
|
|
33
|
+
"enableJsonFlag": false,
|
|
34
|
+
"isESM": true,
|
|
35
|
+
"relativePath": [
|
|
36
|
+
"dist",
|
|
37
|
+
"commands",
|
|
38
|
+
"env",
|
|
39
|
+
"apifox.js"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
3
42
|
"env": {
|
|
4
43
|
"aliases": [],
|
|
5
44
|
"args": {
|
|
@@ -10,7 +49,7 @@
|
|
|
10
49
|
"required": false
|
|
11
50
|
}
|
|
12
51
|
},
|
|
13
|
-
"description": "读取.env
|
|
52
|
+
"description": "读取.env环境变量并打印(json格式)",
|
|
14
53
|
"examples": [
|
|
15
54
|
"\n <%= config.bin %> <%= command.id %> .env\n "
|
|
16
55
|
],
|
|
@@ -194,7 +233,45 @@
|
|
|
194
233
|
"prettier",
|
|
195
234
|
"reset.js"
|
|
196
235
|
]
|
|
236
|
+
},
|
|
237
|
+
"js:clash": {
|
|
238
|
+
"aliases": [],
|
|
239
|
+
"args": {
|
|
240
|
+
"filePath": {
|
|
241
|
+
"description": "目标js文件路径",
|
|
242
|
+
"name": "filePath",
|
|
243
|
+
"required": true
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
"description": "修改Clash脚本",
|
|
247
|
+
"examples": [
|
|
248
|
+
"<%= config.bin %> <%= command.id %> ./tests/test.js"
|
|
249
|
+
],
|
|
250
|
+
"flags": {
|
|
251
|
+
"verbose": {
|
|
252
|
+
"char": "v",
|
|
253
|
+
"description": "Show verbose output",
|
|
254
|
+
"name": "verbose",
|
|
255
|
+
"allowNo": false,
|
|
256
|
+
"type": "boolean"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"hasDynamicHelp": false,
|
|
260
|
+
"hiddenAliases": [],
|
|
261
|
+
"id": "js:clash",
|
|
262
|
+
"pluginAlias": "meocli",
|
|
263
|
+
"pluginName": "meocli",
|
|
264
|
+
"pluginType": "core",
|
|
265
|
+
"strict": true,
|
|
266
|
+
"enableJsonFlag": false,
|
|
267
|
+
"isESM": true,
|
|
268
|
+
"relativePath": [
|
|
269
|
+
"dist",
|
|
270
|
+
"commands",
|
|
271
|
+
"js",
|
|
272
|
+
"clash.js"
|
|
273
|
+
]
|
|
197
274
|
}
|
|
198
275
|
},
|
|
199
|
-
"version": "0.1.
|
|
276
|
+
"version": "0.1.7"
|
|
200
277
|
}
|
package/package.json
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meocli",
|
|
3
3
|
"description": "Node CLI generated with oclif, Integrate Prettier",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7",
|
|
5
5
|
"author": "meme2046",
|
|
6
6
|
"bin": {
|
|
7
7
|
"me": "./bin/run.js"
|
|
8
8
|
},
|
|
9
9
|
"bugs": "https://github.com/meme2046/meocli/issues",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@
|
|
11
|
+
"@babel/generator": "^8.0.0",
|
|
12
|
+
"@babel/parser": "^8.0.0",
|
|
13
|
+
"@babel/traverse": "^8.0.0",
|
|
14
|
+
"@babel/types": "^8.0.0",
|
|
15
|
+
"@oclif/core": "^4.11.14",
|
|
12
16
|
"@oclif/plugin-help": "^6",
|
|
13
17
|
"@oclif/plugin-plugins": "^5",
|
|
14
18
|
"@prettier/plugin-xml": "^3.4.2",
|
|
15
19
|
"d3-format": "^3.1.2",
|
|
16
|
-
"dayjs": "^1.11.
|
|
20
|
+
"dayjs": "^1.11.21",
|
|
17
21
|
"debug": "^4.4.3",
|
|
18
|
-
"dotenv": "^17.2
|
|
22
|
+
"dotenv": "^17.4.2",
|
|
19
23
|
"execa": "^9.6.1",
|
|
20
|
-
"js-yaml": "^4.
|
|
21
|
-
"lodash": "^4.
|
|
22
|
-
"prettier": "^3.
|
|
24
|
+
"js-yaml": "^4.3.0",
|
|
25
|
+
"lodash": "^4.18.1",
|
|
26
|
+
"prettier": "^3.9.4",
|
|
23
27
|
"prettier-plugin-nginx": "^1.0.3",
|
|
24
|
-
"prettier-plugin-sh": "^0.18.
|
|
28
|
+
"prettier-plugin-sh": "^0.18.1",
|
|
25
29
|
"prettier-plugin-toml": "^2.0.6",
|
|
26
30
|
"trading-signals": "^7.4.3"
|
|
27
31
|
},
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
"@types/chai": "^4",
|
|
33
37
|
"@types/d3-format": "^3.0.4",
|
|
34
38
|
"@types/js-yaml": "^4.0.9",
|
|
35
|
-
"@types/lodash": "^4.17.
|
|
39
|
+
"@types/lodash": "^4.17.24",
|
|
36
40
|
"@types/mocha": "^10",
|
|
37
41
|
"@types/node": "^18",
|
|
38
42
|
"chai": "^4",
|
|
@@ -40,7 +44,7 @@
|
|
|
40
44
|
"eslint-config-oclif": "^6",
|
|
41
45
|
"eslint-config-prettier": "^10",
|
|
42
46
|
"mocha": "^10",
|
|
43
|
-
"npm-check-updates": "^19.
|
|
47
|
+
"npm-check-updates": "^19.6.6",
|
|
44
48
|
"oclif": "^4",
|
|
45
49
|
"shx": "^0.3.3",
|
|
46
50
|
"ts-node": "^10",
|
|
@@ -78,7 +82,10 @@
|
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
},
|
|
81
|
-
"repository":
|
|
85
|
+
"repository": {
|
|
86
|
+
"type": "git",
|
|
87
|
+
"url": "meme2046/meocli"
|
|
88
|
+
},
|
|
82
89
|
"types": "dist/index.d.ts",
|
|
83
90
|
"scripts": {
|
|
84
91
|
"ncu": "ncu --target minor --reject webpack,shx",
|