meocli 0.1.6 → 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 +40 -24
- package/dist/commands/js/clash.d.ts +12 -0
- package/dist/commands/js/clash.js +491 -0
- 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 +39 -1
- 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
|
|
@@ -132,6 +124,7 @@ USAGE
|
|
|
132
124
|
* [`me hello PERSON`](#me-hello-person)
|
|
133
125
|
* [`me hello world`](#me-hello-world)
|
|
134
126
|
* [`me help [COMMAND]`](#me-help-command)
|
|
127
|
+
* [`me js clash FILEPATH`](#me-js-clash-filepath)
|
|
135
128
|
* [`me plugins`](#me-plugins)
|
|
136
129
|
* [`me plugins add PLUGIN`](#me-plugins-add-plugin)
|
|
137
130
|
* [`me plugins:inspect PLUGIN...`](#me-pluginsinspect-plugin)
|
|
@@ -166,7 +159,7 @@ EXAMPLES
|
|
|
166
159
|
me env .env
|
|
167
160
|
```
|
|
168
161
|
|
|
169
|
-
_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)_
|
|
170
163
|
|
|
171
164
|
## `me env apifox [FILEPATH]`
|
|
172
165
|
|
|
@@ -189,7 +182,7 @@ EXAMPLES
|
|
|
189
182
|
me env apifox .env
|
|
190
183
|
```
|
|
191
184
|
|
|
192
|
-
_See code: [src/commands/env/apifox.ts](https://github.com/meme2046/meocli/blob/v0.1.
|
|
185
|
+
_See code: [src/commands/env/apifox.ts](https://github.com/meme2046/meocli/blob/v0.1.7/src/commands/env/apifox.ts)_
|
|
193
186
|
|
|
194
187
|
## `me hello PERSON`
|
|
195
188
|
|
|
@@ -213,7 +206,7 @@ EXAMPLES
|
|
|
213
206
|
hello friend --from oclif (./src/commands/hello/index.ts)
|
|
214
207
|
```
|
|
215
208
|
|
|
216
|
-
_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)_
|
|
217
210
|
|
|
218
211
|
## `me hello world`
|
|
219
212
|
|
|
@@ -231,7 +224,7 @@ EXAMPLES
|
|
|
231
224
|
hello world! (./src/commands/hello/world.ts)
|
|
232
225
|
```
|
|
233
226
|
|
|
234
|
-
_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)_
|
|
235
228
|
|
|
236
229
|
## `me help [COMMAND]`
|
|
237
230
|
|
|
@@ -253,6 +246,29 @@ DESCRIPTION
|
|
|
253
246
|
|
|
254
247
|
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.37/src/commands/help.ts)_
|
|
255
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
|
+
|
|
256
272
|
## `me plugins`
|
|
257
273
|
|
|
258
274
|
List installed plugins.
|
|
@@ -571,7 +587,7 @@ EXAMPLES
|
|
|
571
587
|
$ me prettier ./src/file.ts --config ./.prettierrc.yaml
|
|
572
588
|
```
|
|
573
589
|
|
|
574
|
-
_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)_
|
|
575
591
|
|
|
576
592
|
## `me prettier reset`
|
|
577
593
|
|
|
@@ -591,5 +607,5 @@ EXAMPLES
|
|
|
591
607
|
$ me prettier reset --verbose
|
|
592
608
|
```
|
|
593
609
|
|
|
594
|
-
_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)_
|
|
595
611
|
<!-- commandsstop -->
|
|
@@ -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
|
+
}
|
|
@@ -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
|
@@ -233,7 +233,45 @@
|
|
|
233
233
|
"prettier",
|
|
234
234
|
"reset.js"
|
|
235
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
|
+
]
|
|
236
274
|
}
|
|
237
275
|
},
|
|
238
|
-
"version": "0.1.
|
|
276
|
+
"version": "0.1.7"
|
|
239
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",
|