@kevisual/router 0.0.56 → 0.0.57
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/dist/opencode.d.ts +331 -0
- package/dist/opencode.js +969 -0
- package/package.json +9 -5
- package/src/opencode.ts +72 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { Plugin } from '@opencode-ai/plugin';
|
|
2
|
+
|
|
3
|
+
type RouterContextT = {
|
|
4
|
+
code?: number;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
};
|
|
7
|
+
type RouteContext<T = {
|
|
8
|
+
code?: number;
|
|
9
|
+
}, S = any> = {
|
|
10
|
+
/**
|
|
11
|
+
* 本地自己调用的时候使用,可以标识为当前自调用,那么 auth 就不许重复的校验
|
|
12
|
+
* 或者不需要登录的,直接调用
|
|
13
|
+
*/
|
|
14
|
+
appId?: string;
|
|
15
|
+
query?: {
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
};
|
|
18
|
+
/** return body */
|
|
19
|
+
body?: number | string | Object;
|
|
20
|
+
forward?: (response: {
|
|
21
|
+
code: number;
|
|
22
|
+
data?: any;
|
|
23
|
+
message?: any;
|
|
24
|
+
}) => void;
|
|
25
|
+
/** return code */
|
|
26
|
+
code?: number;
|
|
27
|
+
/** return msg */
|
|
28
|
+
message?: string;
|
|
29
|
+
state?: S;
|
|
30
|
+
/**
|
|
31
|
+
* 当前路径
|
|
32
|
+
*/
|
|
33
|
+
currentPath?: string;
|
|
34
|
+
/**
|
|
35
|
+
* 当前key
|
|
36
|
+
*/
|
|
37
|
+
currentKey?: string;
|
|
38
|
+
/**
|
|
39
|
+
* 当前route
|
|
40
|
+
*/
|
|
41
|
+
currentRoute?: Route;
|
|
42
|
+
/**
|
|
43
|
+
* 进度
|
|
44
|
+
*/
|
|
45
|
+
progress?: [string, string][];
|
|
46
|
+
nextQuery?: {
|
|
47
|
+
[key: string]: any;
|
|
48
|
+
};
|
|
49
|
+
end?: boolean;
|
|
50
|
+
app?: QueryRouter;
|
|
51
|
+
error?: any;
|
|
52
|
+
/** 请求 route的返回结果,不解析body为data */
|
|
53
|
+
call?: (message: {
|
|
54
|
+
path: string;
|
|
55
|
+
key?: string;
|
|
56
|
+
payload?: any;
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
} | {
|
|
59
|
+
id: string;
|
|
60
|
+
apyload?: any;
|
|
61
|
+
[key: string]: any;
|
|
62
|
+
}, ctx?: RouteContext & {
|
|
63
|
+
[key: string]: any;
|
|
64
|
+
}) => Promise<any>;
|
|
65
|
+
/** 请求 route的返回结果,解析了body为data,就类同于 query.post获取的数据*/
|
|
66
|
+
run?: (message: {
|
|
67
|
+
path: string;
|
|
68
|
+
key?: string;
|
|
69
|
+
payload?: any;
|
|
70
|
+
}, ctx?: RouteContext & {
|
|
71
|
+
[key: string]: any;
|
|
72
|
+
}) => Promise<any>;
|
|
73
|
+
index?: number;
|
|
74
|
+
throw?: (code?: number | string, message?: string, tips?: string) => void;
|
|
75
|
+
/** 是否需要序列化, 使用JSON.stringify和JSON.parse */
|
|
76
|
+
needSerialize?: boolean;
|
|
77
|
+
} & T;
|
|
78
|
+
type SimpleObject = Record<string, any>;
|
|
79
|
+
type Run<T extends SimpleObject = {}> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
|
|
80
|
+
type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
|
|
81
|
+
type RouteMiddleware = {
|
|
82
|
+
path: string;
|
|
83
|
+
key?: string;
|
|
84
|
+
id?: string;
|
|
85
|
+
} | string;
|
|
86
|
+
type RouteOpts<U = {}, T = SimpleObject> = {
|
|
87
|
+
path?: string;
|
|
88
|
+
key?: string;
|
|
89
|
+
id?: string;
|
|
90
|
+
run?: Run<U>;
|
|
91
|
+
nextRoute?: NextRoute;
|
|
92
|
+
description?: string;
|
|
93
|
+
metadata?: T;
|
|
94
|
+
middleware?: RouteMiddleware[];
|
|
95
|
+
type?: 'route' | 'middleware';
|
|
96
|
+
/**
|
|
97
|
+
* $#$ will be used to split path and key
|
|
98
|
+
*/
|
|
99
|
+
idUsePath?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* id 合并的分隔符,默认为 $#$
|
|
102
|
+
*/
|
|
103
|
+
delimiter?: string;
|
|
104
|
+
isDebug?: boolean;
|
|
105
|
+
};
|
|
106
|
+
type DefineRouteOpts = Omit<RouteOpts, 'idUsePath' | 'nextRoute'>;
|
|
107
|
+
declare const pickValue: readonly ["path", "key", "id", "description", "type", "middleware", "metadata"];
|
|
108
|
+
type RouteInfo = Pick<Route, (typeof pickValue)[number]>;
|
|
109
|
+
declare class Route<U = {
|
|
110
|
+
[key: string]: any;
|
|
111
|
+
}, T extends SimpleObject = SimpleObject> {
|
|
112
|
+
/**
|
|
113
|
+
* 一级路径
|
|
114
|
+
*/
|
|
115
|
+
path?: string;
|
|
116
|
+
/**
|
|
117
|
+
* 二级路径
|
|
118
|
+
*/
|
|
119
|
+
key?: string;
|
|
120
|
+
id?: string;
|
|
121
|
+
run?: Run;
|
|
122
|
+
nextRoute?: NextRoute;
|
|
123
|
+
description?: string;
|
|
124
|
+
metadata?: T;
|
|
125
|
+
middleware?: RouteMiddleware[];
|
|
126
|
+
type?: string;
|
|
127
|
+
data?: any;
|
|
128
|
+
/**
|
|
129
|
+
* 是否开启debug,开启后会打印错误信息
|
|
130
|
+
*/
|
|
131
|
+
isDebug?: boolean;
|
|
132
|
+
constructor(path?: string, key?: string, opts?: RouteOpts);
|
|
133
|
+
prompt(description: string): this;
|
|
134
|
+
prompt(description: Function): this;
|
|
135
|
+
define<T extends {
|
|
136
|
+
[key: string]: any;
|
|
137
|
+
} = RouterContextT>(opts: DefineRouteOpts): this;
|
|
138
|
+
define<T extends {
|
|
139
|
+
[key: string]: any;
|
|
140
|
+
} = RouterContextT>(fn: Run<T & U>): this;
|
|
141
|
+
define<T extends {
|
|
142
|
+
[key: string]: any;
|
|
143
|
+
} = RouterContextT>(key: string, fn: Run<T & U>): this;
|
|
144
|
+
define<T extends {
|
|
145
|
+
[key: string]: any;
|
|
146
|
+
} = RouterContextT>(path: string, key: string, fn: Run<T & U>): this;
|
|
147
|
+
update(opts: DefineRouteOpts, checkList?: string[]): this;
|
|
148
|
+
addTo(router: QueryRouter | {
|
|
149
|
+
add: (route: Route) => void;
|
|
150
|
+
[key: string]: any;
|
|
151
|
+
}): void;
|
|
152
|
+
setData(data: any): this;
|
|
153
|
+
throw(code?: number | string, message?: string, tips?: string): void;
|
|
154
|
+
}
|
|
155
|
+
declare class QueryRouter {
|
|
156
|
+
appId: string;
|
|
157
|
+
routes: Route[];
|
|
158
|
+
maxNextRoute: number;
|
|
159
|
+
context?: RouteContext;
|
|
160
|
+
constructor();
|
|
161
|
+
add(route: Route): void;
|
|
162
|
+
/**
|
|
163
|
+
* remove route by path and key
|
|
164
|
+
* @param route
|
|
165
|
+
*/
|
|
166
|
+
remove(route: Route | {
|
|
167
|
+
path: string;
|
|
168
|
+
key?: string;
|
|
169
|
+
}): void;
|
|
170
|
+
/**
|
|
171
|
+
* remove route by id
|
|
172
|
+
* @param uniqueId
|
|
173
|
+
*/
|
|
174
|
+
removeById(unique: string): void;
|
|
175
|
+
/**
|
|
176
|
+
* 执行route
|
|
177
|
+
* @param path
|
|
178
|
+
* @param key
|
|
179
|
+
* @param ctx
|
|
180
|
+
* @returns
|
|
181
|
+
*/
|
|
182
|
+
runRoute(path: string, key: string, ctx?: RouteContext): any;
|
|
183
|
+
/**
|
|
184
|
+
* 第一次执行
|
|
185
|
+
* @param message
|
|
186
|
+
* @param ctx
|
|
187
|
+
* @returns
|
|
188
|
+
*/
|
|
189
|
+
parse(message: {
|
|
190
|
+
path: string;
|
|
191
|
+
key?: string;
|
|
192
|
+
payload?: any;
|
|
193
|
+
}, ctx?: RouteContext & {
|
|
194
|
+
[key: string]: any;
|
|
195
|
+
}): Promise<any>;
|
|
196
|
+
/**
|
|
197
|
+
* 返回的数据包含所有的context的请求返回的内容,可做其他处理
|
|
198
|
+
* @param message
|
|
199
|
+
* @param ctx
|
|
200
|
+
* @returns
|
|
201
|
+
*/
|
|
202
|
+
call(message: {
|
|
203
|
+
id?: string;
|
|
204
|
+
path?: string;
|
|
205
|
+
key?: string;
|
|
206
|
+
payload?: any;
|
|
207
|
+
}, ctx?: RouteContext & {
|
|
208
|
+
[key: string]: any;
|
|
209
|
+
}): Promise<any>;
|
|
210
|
+
/**
|
|
211
|
+
* 请求 result 的数据
|
|
212
|
+
* @param message
|
|
213
|
+
* @param ctx
|
|
214
|
+
* @deprecated use run or call instead
|
|
215
|
+
* @returns
|
|
216
|
+
*/
|
|
217
|
+
queryRoute(message: {
|
|
218
|
+
id?: string;
|
|
219
|
+
path: string;
|
|
220
|
+
key?: string;
|
|
221
|
+
payload?: any;
|
|
222
|
+
}, ctx?: RouteContext & {
|
|
223
|
+
[key: string]: any;
|
|
224
|
+
}): Promise<{
|
|
225
|
+
code: any;
|
|
226
|
+
data: any;
|
|
227
|
+
message: any;
|
|
228
|
+
}>;
|
|
229
|
+
/**
|
|
230
|
+
* Router Run获取数据
|
|
231
|
+
* @param message
|
|
232
|
+
* @param ctx
|
|
233
|
+
* @returns
|
|
234
|
+
*/
|
|
235
|
+
run(message: {
|
|
236
|
+
id?: string;
|
|
237
|
+
path?: string;
|
|
238
|
+
key?: string;
|
|
239
|
+
payload?: any;
|
|
240
|
+
}, ctx?: RouteContext & {
|
|
241
|
+
[key: string]: any;
|
|
242
|
+
}): Promise<{
|
|
243
|
+
code: any;
|
|
244
|
+
data: any;
|
|
245
|
+
message: any;
|
|
246
|
+
}>;
|
|
247
|
+
/**
|
|
248
|
+
* 设置上下文
|
|
249
|
+
* @description 这里的上下文是为了在handle函数中使用
|
|
250
|
+
* @param ctx
|
|
251
|
+
*/
|
|
252
|
+
setContext(ctx: RouteContext): void;
|
|
253
|
+
getList(filter?: (route: Route) => boolean): RouteInfo[];
|
|
254
|
+
/**
|
|
255
|
+
* 获取handle函数, 这里会去执行parse函数
|
|
256
|
+
*/
|
|
257
|
+
getHandle<T = any>(router: QueryRouter, wrapperFn?: HandleFn<T>, ctx?: RouteContext): (msg: {
|
|
258
|
+
id?: string;
|
|
259
|
+
path?: string;
|
|
260
|
+
key?: string;
|
|
261
|
+
[key: string]: any;
|
|
262
|
+
}, handleContext?: RouteContext) => Promise<{
|
|
263
|
+
[key: string]: any;
|
|
264
|
+
code: string;
|
|
265
|
+
data?: any;
|
|
266
|
+
message?: string;
|
|
267
|
+
} | {
|
|
268
|
+
code: any;
|
|
269
|
+
data: any;
|
|
270
|
+
message: any;
|
|
271
|
+
} | {
|
|
272
|
+
code: number;
|
|
273
|
+
message: any;
|
|
274
|
+
data?: undefined;
|
|
275
|
+
}>;
|
|
276
|
+
exportRoutes(): Route<{
|
|
277
|
+
[key: string]: any;
|
|
278
|
+
}, SimpleObject>[];
|
|
279
|
+
importRoutes(routes: Route[]): void;
|
|
280
|
+
importRouter(router: QueryRouter): void;
|
|
281
|
+
throw(code?: number | string, message?: string, tips?: string): void;
|
|
282
|
+
hasRoute(path: string, key?: string): Route<{
|
|
283
|
+
[key: string]: any;
|
|
284
|
+
}, SimpleObject>;
|
|
285
|
+
findRoute(opts?: {
|
|
286
|
+
path?: string;
|
|
287
|
+
key?: string;
|
|
288
|
+
id?: string;
|
|
289
|
+
}): Route<{
|
|
290
|
+
[key: string]: any;
|
|
291
|
+
}, SimpleObject>;
|
|
292
|
+
createRouteList(force?: boolean, filter?: (route: Route) => boolean): void;
|
|
293
|
+
/**
|
|
294
|
+
* 等待程序运行, 获取到message的数据,就执行
|
|
295
|
+
*
|
|
296
|
+
* emitter = process
|
|
297
|
+
* -- .exit
|
|
298
|
+
* -- .on
|
|
299
|
+
* -- .send
|
|
300
|
+
*/
|
|
301
|
+
wait(params?: {
|
|
302
|
+
path?: string;
|
|
303
|
+
key?: string;
|
|
304
|
+
payload?: any;
|
|
305
|
+
}, opts?: {
|
|
306
|
+
emitter?: any;
|
|
307
|
+
timeout?: number;
|
|
308
|
+
getList?: boolean;
|
|
309
|
+
force?: boolean;
|
|
310
|
+
filter?: (route: Route) => boolean;
|
|
311
|
+
}): Promise<void>;
|
|
312
|
+
}
|
|
313
|
+
interface HandleFn<T = any> {
|
|
314
|
+
(msg: {
|
|
315
|
+
path: string;
|
|
316
|
+
[key: string]: any;
|
|
317
|
+
}, ctx?: any): {
|
|
318
|
+
code: string;
|
|
319
|
+
data?: any;
|
|
320
|
+
message?: string;
|
|
321
|
+
[key: string]: any;
|
|
322
|
+
};
|
|
323
|
+
(res: RouteContext<T>): any;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
declare const createRouterAgentPluginFn: (opts?: {
|
|
327
|
+
router?: QueryRouter;
|
|
328
|
+
query?: string;
|
|
329
|
+
}) => Plugin;
|
|
330
|
+
|
|
331
|
+
export { createRouterAgentPluginFn };
|
package/dist/opencode.js
ADDED
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
// src/utils/path-key.ts
|
|
2
|
+
|
|
3
|
+
// ../../node_modules/.pnpm/@kevisual+load@0.0.6/node_modules/@kevisual/load/dist/load.js
|
|
4
|
+
function getDefaultExportFromCjs(x) {
|
|
5
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
6
|
+
}
|
|
7
|
+
var eventemitter3 = { exports: {} };
|
|
8
|
+
var hasRequiredEventemitter3;
|
|
9
|
+
function requireEventemitter3() {
|
|
10
|
+
if (hasRequiredEventemitter3)
|
|
11
|
+
return eventemitter3.exports;
|
|
12
|
+
hasRequiredEventemitter3 = 1;
|
|
13
|
+
(function(module) {
|
|
14
|
+
var has = Object.prototype.hasOwnProperty, prefix = "~";
|
|
15
|
+
function Events() {}
|
|
16
|
+
if (Object.create) {
|
|
17
|
+
Events.prototype = Object.create(null);
|
|
18
|
+
if (!new Events().__proto__)
|
|
19
|
+
prefix = false;
|
|
20
|
+
}
|
|
21
|
+
function EE(fn, context, once) {
|
|
22
|
+
this.fn = fn;
|
|
23
|
+
this.context = context;
|
|
24
|
+
this.once = once || false;
|
|
25
|
+
}
|
|
26
|
+
function addListener(emitter, event, fn, context, once) {
|
|
27
|
+
if (typeof fn !== "function") {
|
|
28
|
+
throw new TypeError("The listener must be a function");
|
|
29
|
+
}
|
|
30
|
+
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
|
|
31
|
+
if (!emitter._events[evt])
|
|
32
|
+
emitter._events[evt] = listener, emitter._eventsCount++;
|
|
33
|
+
else if (!emitter._events[evt].fn)
|
|
34
|
+
emitter._events[evt].push(listener);
|
|
35
|
+
else
|
|
36
|
+
emitter._events[evt] = [emitter._events[evt], listener];
|
|
37
|
+
return emitter;
|
|
38
|
+
}
|
|
39
|
+
function clearEvent(emitter, evt) {
|
|
40
|
+
if (--emitter._eventsCount === 0)
|
|
41
|
+
emitter._events = new Events;
|
|
42
|
+
else
|
|
43
|
+
delete emitter._events[evt];
|
|
44
|
+
}
|
|
45
|
+
function EventEmitter() {
|
|
46
|
+
this._events = new Events;
|
|
47
|
+
this._eventsCount = 0;
|
|
48
|
+
}
|
|
49
|
+
EventEmitter.prototype.eventNames = function eventNames() {
|
|
50
|
+
var names = [], events, name;
|
|
51
|
+
if (this._eventsCount === 0)
|
|
52
|
+
return names;
|
|
53
|
+
for (name in events = this._events) {
|
|
54
|
+
if (has.call(events, name))
|
|
55
|
+
names.push(prefix ? name.slice(1) : name);
|
|
56
|
+
}
|
|
57
|
+
if (Object.getOwnPropertySymbols) {
|
|
58
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
59
|
+
}
|
|
60
|
+
return names;
|
|
61
|
+
};
|
|
62
|
+
EventEmitter.prototype.listeners = function listeners(event) {
|
|
63
|
+
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
|
|
64
|
+
if (!handlers)
|
|
65
|
+
return [];
|
|
66
|
+
if (handlers.fn)
|
|
67
|
+
return [handlers.fn];
|
|
68
|
+
for (var i = 0, l = handlers.length, ee = new Array(l);i < l; i++) {
|
|
69
|
+
ee[i] = handlers[i].fn;
|
|
70
|
+
}
|
|
71
|
+
return ee;
|
|
72
|
+
};
|
|
73
|
+
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
|
74
|
+
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
|
|
75
|
+
if (!listeners)
|
|
76
|
+
return 0;
|
|
77
|
+
if (listeners.fn)
|
|
78
|
+
return 1;
|
|
79
|
+
return listeners.length;
|
|
80
|
+
};
|
|
81
|
+
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
82
|
+
var evt = prefix ? prefix + event : event;
|
|
83
|
+
if (!this._events[evt])
|
|
84
|
+
return false;
|
|
85
|
+
var listeners = this._events[evt], len = arguments.length, args, i;
|
|
86
|
+
if (listeners.fn) {
|
|
87
|
+
if (listeners.once)
|
|
88
|
+
this.removeListener(event, listeners.fn, undefined, true);
|
|
89
|
+
switch (len) {
|
|
90
|
+
case 1:
|
|
91
|
+
return listeners.fn.call(listeners.context), true;
|
|
92
|
+
case 2:
|
|
93
|
+
return listeners.fn.call(listeners.context, a1), true;
|
|
94
|
+
case 3:
|
|
95
|
+
return listeners.fn.call(listeners.context, a1, a2), true;
|
|
96
|
+
case 4:
|
|
97
|
+
return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
98
|
+
case 5:
|
|
99
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
100
|
+
case 6:
|
|
101
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
102
|
+
}
|
|
103
|
+
for (i = 1, args = new Array(len - 1);i < len; i++) {
|
|
104
|
+
args[i - 1] = arguments[i];
|
|
105
|
+
}
|
|
106
|
+
listeners.fn.apply(listeners.context, args);
|
|
107
|
+
} else {
|
|
108
|
+
var length = listeners.length, j;
|
|
109
|
+
for (i = 0;i < length; i++) {
|
|
110
|
+
if (listeners[i].once)
|
|
111
|
+
this.removeListener(event, listeners[i].fn, undefined, true);
|
|
112
|
+
switch (len) {
|
|
113
|
+
case 1:
|
|
114
|
+
listeners[i].fn.call(listeners[i].context);
|
|
115
|
+
break;
|
|
116
|
+
case 2:
|
|
117
|
+
listeners[i].fn.call(listeners[i].context, a1);
|
|
118
|
+
break;
|
|
119
|
+
case 3:
|
|
120
|
+
listeners[i].fn.call(listeners[i].context, a1, a2);
|
|
121
|
+
break;
|
|
122
|
+
case 4:
|
|
123
|
+
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
if (!args)
|
|
127
|
+
for (j = 1, args = new Array(len - 1);j < len; j++) {
|
|
128
|
+
args[j - 1] = arguments[j];
|
|
129
|
+
}
|
|
130
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
};
|
|
136
|
+
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
137
|
+
return addListener(this, event, fn, context, false);
|
|
138
|
+
};
|
|
139
|
+
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
140
|
+
return addListener(this, event, fn, context, true);
|
|
141
|
+
};
|
|
142
|
+
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
143
|
+
var evt = prefix ? prefix + event : event;
|
|
144
|
+
if (!this._events[evt])
|
|
145
|
+
return this;
|
|
146
|
+
if (!fn) {
|
|
147
|
+
clearEvent(this, evt);
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
var listeners = this._events[evt];
|
|
151
|
+
if (listeners.fn) {
|
|
152
|
+
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
|
|
153
|
+
clearEvent(this, evt);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
for (var i = 0, events = [], length = listeners.length;i < length; i++) {
|
|
157
|
+
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
|
|
158
|
+
events.push(listeners[i]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (events.length)
|
|
162
|
+
this._events[evt] = events.length === 1 ? events[0] : events;
|
|
163
|
+
else
|
|
164
|
+
clearEvent(this, evt);
|
|
165
|
+
}
|
|
166
|
+
return this;
|
|
167
|
+
};
|
|
168
|
+
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
169
|
+
var evt;
|
|
170
|
+
if (event) {
|
|
171
|
+
evt = prefix ? prefix + event : event;
|
|
172
|
+
if (this._events[evt])
|
|
173
|
+
clearEvent(this, evt);
|
|
174
|
+
} else {
|
|
175
|
+
this._events = new Events;
|
|
176
|
+
this._eventsCount = 0;
|
|
177
|
+
}
|
|
178
|
+
return this;
|
|
179
|
+
};
|
|
180
|
+
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
181
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
182
|
+
EventEmitter.prefixed = prefix;
|
|
183
|
+
EventEmitter.EventEmitter = EventEmitter;
|
|
184
|
+
{
|
|
185
|
+
module.exports = EventEmitter;
|
|
186
|
+
}
|
|
187
|
+
})(eventemitter3);
|
|
188
|
+
return eventemitter3.exports;
|
|
189
|
+
}
|
|
190
|
+
var eventemitter3Exports = requireEventemitter3();
|
|
191
|
+
var EventEmitter = /* @__PURE__ */ getDefaultExportFromCjs(eventemitter3Exports);
|
|
192
|
+
var reRunFn = (promiseOpts) => {
|
|
193
|
+
const timeout = promiseOpts.timeout || 5 * 60 * 1000;
|
|
194
|
+
const interval = promiseOpts.interval || 1000;
|
|
195
|
+
const checkSuccess = promiseOpts?.checkSuccess || (() => true);
|
|
196
|
+
const signal = promiseOpts.signal;
|
|
197
|
+
return new Promise(async (resolve, reject) => {
|
|
198
|
+
let intervalId;
|
|
199
|
+
let timeoutId = setTimeout(() => {
|
|
200
|
+
clearTimeout(intervalId);
|
|
201
|
+
resolve({
|
|
202
|
+
code: 500,
|
|
203
|
+
message: "timeout"
|
|
204
|
+
});
|
|
205
|
+
}, timeout);
|
|
206
|
+
const fn = promiseOpts.fn || (() => true);
|
|
207
|
+
const runFn = async () => {
|
|
208
|
+
if (signal?.aborted) {
|
|
209
|
+
clearInterval(intervalId);
|
|
210
|
+
clearTimeout(timeoutId);
|
|
211
|
+
return resolve({
|
|
212
|
+
code: 499,
|
|
213
|
+
message: "operation cancelled"
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const res = await fn();
|
|
217
|
+
if (!!checkSuccess(res)) {
|
|
218
|
+
clearInterval(intervalId);
|
|
219
|
+
clearTimeout(timeoutId);
|
|
220
|
+
resolve({
|
|
221
|
+
code: 200,
|
|
222
|
+
data: res
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
runFn();
|
|
227
|
+
}, interval);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
if (signal) {
|
|
231
|
+
signal.addEventListener("abort", () => {
|
|
232
|
+
clearInterval(intervalId);
|
|
233
|
+
clearTimeout(timeoutId);
|
|
234
|
+
resolve({
|
|
235
|
+
code: 499,
|
|
236
|
+
message: "operation cancelled"
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
runFn();
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
class BaseLoad {
|
|
245
|
+
modules = new Map;
|
|
246
|
+
event;
|
|
247
|
+
loading;
|
|
248
|
+
static reRunFn = reRunFn;
|
|
249
|
+
timeout = 5 * 60 * 1000;
|
|
250
|
+
constructor() {
|
|
251
|
+
this.event = new EventEmitter;
|
|
252
|
+
this.loading = false;
|
|
253
|
+
}
|
|
254
|
+
listenKey(key, listenOpts) {
|
|
255
|
+
const timeout = listenOpts?.timeout ?? this.timeout;
|
|
256
|
+
return new Promise((resolve) => {
|
|
257
|
+
const timeoutId = setTimeout(() => {
|
|
258
|
+
this.event.removeListener(key, onEvent);
|
|
259
|
+
resolve({
|
|
260
|
+
code: 500,
|
|
261
|
+
message: "timeout"
|
|
262
|
+
});
|
|
263
|
+
}, timeout);
|
|
264
|
+
const onEvent = (error) => {
|
|
265
|
+
clearTimeout(timeoutId);
|
|
266
|
+
if (error) {
|
|
267
|
+
return resolve({
|
|
268
|
+
code: 500,
|
|
269
|
+
message: error
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
const data = this.modules.get(key);
|
|
273
|
+
if (data?.loadSuccessClear) {
|
|
274
|
+
this.remove(key);
|
|
275
|
+
}
|
|
276
|
+
resolve({
|
|
277
|
+
code: 200,
|
|
278
|
+
data: data?.modules
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
this.event.once(key, onEvent);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
async hasLoaded(key, hasLoadOpts) {
|
|
285
|
+
if (!key) {
|
|
286
|
+
return {
|
|
287
|
+
code: 404,
|
|
288
|
+
message: "key is required"
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const has = this.modules.has(key);
|
|
292
|
+
if (!has) {
|
|
293
|
+
const isExist = hasLoadOpts?.isExist ?? true;
|
|
294
|
+
const timeout = hasLoadOpts?.timeout ?? this.timeout;
|
|
295
|
+
if (isExist) {
|
|
296
|
+
return await this.listenKey(key, { timeout });
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
code: 404
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const data = this.modules.get(key);
|
|
303
|
+
if (data?.status === "loaded") {
|
|
304
|
+
return {
|
|
305
|
+
code: 200,
|
|
306
|
+
data: data.modules
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
if (data?.status === "loading") {
|
|
310
|
+
return await this.listenKey(key, { timeout: hasLoadOpts?.timeout ?? this.timeout });
|
|
311
|
+
}
|
|
312
|
+
if (data?.status === "error") {
|
|
313
|
+
return {
|
|
314
|
+
code: 500,
|
|
315
|
+
message: "load error"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
if (data?.status === "cancel") {
|
|
319
|
+
return {
|
|
320
|
+
code: 499,
|
|
321
|
+
message: "operation cancelled"
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
code: 404
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
async loadFn(loadContent, opts) {
|
|
329
|
+
const key = opts.key;
|
|
330
|
+
if (!key) {
|
|
331
|
+
return {
|
|
332
|
+
code: 404,
|
|
333
|
+
message: "key is required"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
const newModule = {
|
|
337
|
+
key: opts.key,
|
|
338
|
+
status: "loading",
|
|
339
|
+
loading: true,
|
|
340
|
+
loadSuccessClear: opts.loadSuccessClear ?? true
|
|
341
|
+
};
|
|
342
|
+
let errorMessage = "";
|
|
343
|
+
try {
|
|
344
|
+
const isReRun = opts.isReRun ?? false;
|
|
345
|
+
let res;
|
|
346
|
+
if (!isReRun) {
|
|
347
|
+
this.modules.set(key, newModule);
|
|
348
|
+
res = await loadContent();
|
|
349
|
+
} else {
|
|
350
|
+
newModule.controller = new AbortController;
|
|
351
|
+
const signal = newModule.controller.signal;
|
|
352
|
+
this.modules.set(key, newModule);
|
|
353
|
+
const data = await reRunFn({
|
|
354
|
+
timeout: opts.timeout,
|
|
355
|
+
interval: opts.interval,
|
|
356
|
+
checkSuccess: opts.checkSuccess,
|
|
357
|
+
fn: loadContent,
|
|
358
|
+
signal
|
|
359
|
+
});
|
|
360
|
+
newModule.controller = null;
|
|
361
|
+
if (data.code === 499) {
|
|
362
|
+
newModule.status = "cancel";
|
|
363
|
+
return {
|
|
364
|
+
code: 499,
|
|
365
|
+
message: "operation cancelled"
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
if (data.code !== 200) {
|
|
369
|
+
throw new Error(data.message);
|
|
370
|
+
}
|
|
371
|
+
res = data.data;
|
|
372
|
+
}
|
|
373
|
+
newModule.modules = res;
|
|
374
|
+
newModule.status = "loaded";
|
|
375
|
+
return {
|
|
376
|
+
code: 200,
|
|
377
|
+
data: res
|
|
378
|
+
};
|
|
379
|
+
} catch (error) {
|
|
380
|
+
errorMessage = error.message;
|
|
381
|
+
newModule.status = "error";
|
|
382
|
+
return {
|
|
383
|
+
code: 500,
|
|
384
|
+
message: error
|
|
385
|
+
};
|
|
386
|
+
} finally {
|
|
387
|
+
newModule.loading = false;
|
|
388
|
+
this.modules.set(opts.key, newModule);
|
|
389
|
+
if (!errorMessage) {
|
|
390
|
+
this.event.emit(opts.key);
|
|
391
|
+
} else {
|
|
392
|
+
this.event.emit(opts.key, errorMessage);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async load(loadContent, opts) {
|
|
397
|
+
this.loading = true;
|
|
398
|
+
const key = opts.key;
|
|
399
|
+
if (!key) {
|
|
400
|
+
return {
|
|
401
|
+
code: 404,
|
|
402
|
+
message: "key is required"
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
if (opts?.force) {
|
|
406
|
+
this.remove(key);
|
|
407
|
+
}
|
|
408
|
+
const has = this.modules.has(key);
|
|
409
|
+
if (has) {
|
|
410
|
+
return await this.hasLoaded(key);
|
|
411
|
+
}
|
|
412
|
+
if (typeof loadContent === "function") {
|
|
413
|
+
return this.loadFn(loadContent, opts);
|
|
414
|
+
}
|
|
415
|
+
console.error("loadContent is not a function and not has loaded");
|
|
416
|
+
}
|
|
417
|
+
remove(key) {
|
|
418
|
+
const has = this.modules.has(key);
|
|
419
|
+
if (has) {
|
|
420
|
+
this.checkRemoveController(key);
|
|
421
|
+
this.modules.delete(key);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
emitLoaded(key) {
|
|
425
|
+
this.checkRemoveController(key);
|
|
426
|
+
this.event.emit(key);
|
|
427
|
+
}
|
|
428
|
+
setModule(key, data, loadData) {
|
|
429
|
+
const newModule = {
|
|
430
|
+
key,
|
|
431
|
+
status: "loaded",
|
|
432
|
+
loading: false,
|
|
433
|
+
modules: data || {},
|
|
434
|
+
...loadData
|
|
435
|
+
};
|
|
436
|
+
this.modules.set(key, newModule);
|
|
437
|
+
this.emitLoaded(key);
|
|
438
|
+
return newModule;
|
|
439
|
+
}
|
|
440
|
+
cancel(key) {
|
|
441
|
+
this.checkRemoveController(key);
|
|
442
|
+
}
|
|
443
|
+
checkRemoveController(key) {
|
|
444
|
+
const data = this.modules.get(key);
|
|
445
|
+
if (data?.controller) {
|
|
446
|
+
data.controller?.abort?.();
|
|
447
|
+
delete data.controller;
|
|
448
|
+
this.modules.set(key, data);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/index.ts
|
|
454
|
+
var gt = globalThis || window || self;
|
|
455
|
+
var useEnv = (initEnv, initKey = "config", isOverwrite) => {
|
|
456
|
+
const env = gt[initKey];
|
|
457
|
+
const _env = env || initEnv;
|
|
458
|
+
if (!env) {
|
|
459
|
+
if (_env) {
|
|
460
|
+
gt[initKey] = _env;
|
|
461
|
+
} else {
|
|
462
|
+
gt[initKey] = {};
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return gt[initKey];
|
|
466
|
+
};
|
|
467
|
+
var useEnvKey = (key, init, initKey = "config") => {
|
|
468
|
+
const _env = useEnv({}, initKey);
|
|
469
|
+
if (key && typeof _env[key] !== "undefined") {
|
|
470
|
+
return _env[key];
|
|
471
|
+
}
|
|
472
|
+
if (key && init) {
|
|
473
|
+
if (typeof init !== "function") {
|
|
474
|
+
_env[key] = init;
|
|
475
|
+
}
|
|
476
|
+
if (typeof init === "function") {
|
|
477
|
+
const result = init();
|
|
478
|
+
if (result instanceof Promise) {
|
|
479
|
+
return result.then((res) => {
|
|
480
|
+
_env[key] = res;
|
|
481
|
+
return res;
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
_env[key] = result;
|
|
485
|
+
}
|
|
486
|
+
return _env[key];
|
|
487
|
+
}
|
|
488
|
+
if (key) {
|
|
489
|
+
const baseLoad = new BaseLoad;
|
|
490
|
+
const voidFn = async () => {
|
|
491
|
+
return _env[key];
|
|
492
|
+
};
|
|
493
|
+
const checkFn = async () => {
|
|
494
|
+
const loadRes = await baseLoad.load(voidFn, {
|
|
495
|
+
key,
|
|
496
|
+
isReRun: true,
|
|
497
|
+
checkSuccess: () => _env[key],
|
|
498
|
+
timeout: 5 * 60 * 1000,
|
|
499
|
+
interval: 1000
|
|
500
|
+
});
|
|
501
|
+
if (loadRes.code !== 200) {
|
|
502
|
+
console.error("load key error");
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
return _env[key];
|
|
506
|
+
};
|
|
507
|
+
return checkFn();
|
|
508
|
+
}
|
|
509
|
+
console.error("key is empty ");
|
|
510
|
+
return null;
|
|
511
|
+
};
|
|
512
|
+
var useEnvKeyNew = (key, initKey = "config", opts) => {
|
|
513
|
+
const _env = useEnv({}, initKey);
|
|
514
|
+
if (key) {
|
|
515
|
+
delete _env[key];
|
|
516
|
+
}
|
|
517
|
+
if (opts?.getNew && opts.init) {
|
|
518
|
+
return useEnvKey(key, opts.init, initKey);
|
|
519
|
+
} else if (opts?.getNew) {
|
|
520
|
+
return useEnvKey(key, null, initKey);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
var useContextKey = (key, init, isNew) => {
|
|
524
|
+
if (isNew) {
|
|
525
|
+
return useEnvKeyNew(key, "context", { getNew: true, init });
|
|
526
|
+
}
|
|
527
|
+
return useEnvKey(key, init, "context");
|
|
528
|
+
};
|
|
529
|
+
var use = useContextKey;
|
|
530
|
+
var useConfigKey = (key, init, isNew) => {
|
|
531
|
+
if (isNew) {
|
|
532
|
+
return useEnvKeyNew(key, "config", { getNew: true, init });
|
|
533
|
+
}
|
|
534
|
+
return useEnvKey(key, init, "config");
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
class InitEnv {
|
|
538
|
+
static isInit = false;
|
|
539
|
+
static init(opts) {
|
|
540
|
+
if (InitEnv.isInit) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const { load = true, page = false } = opts || {};
|
|
544
|
+
InitEnv.isInit = true;
|
|
545
|
+
gt.useConfigKey = useConfigKey;
|
|
546
|
+
gt.useContextKey = useContextKey;
|
|
547
|
+
gt.use = use;
|
|
548
|
+
gt.webEnv = { useConfigKey, useContextKey, use };
|
|
549
|
+
load && (gt.Load = BaseLoad);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
InitEnv.init();
|
|
553
|
+
|
|
554
|
+
class Lexer {
|
|
555
|
+
constructor(input) {
|
|
556
|
+
this.pos = 0;
|
|
557
|
+
this.input = input.trim();
|
|
558
|
+
}
|
|
559
|
+
skipWhitespace() {
|
|
560
|
+
while (this.pos < this.input.length && /\s/.test(this.input[this.pos])) {
|
|
561
|
+
this.pos++;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
readString(quote) {
|
|
565
|
+
this.pos++;
|
|
566
|
+
let result = '';
|
|
567
|
+
while (this.pos < this.input.length && this.input[this.pos] !== quote) {
|
|
568
|
+
result += this.input[this.pos];
|
|
569
|
+
this.pos++;
|
|
570
|
+
}
|
|
571
|
+
this.pos++;
|
|
572
|
+
return result;
|
|
573
|
+
}
|
|
574
|
+
readNumber() {
|
|
575
|
+
let result = '';
|
|
576
|
+
while (this.pos < this.input.length && /[\d.]/.test(this.input[this.pos])) {
|
|
577
|
+
result += this.input[this.pos];
|
|
578
|
+
this.pos++;
|
|
579
|
+
}
|
|
580
|
+
return result;
|
|
581
|
+
}
|
|
582
|
+
readIdentifier() {
|
|
583
|
+
let result = '';
|
|
584
|
+
while (this.pos < this.input.length && /[\w.]/.test(this.input[this.pos])) {
|
|
585
|
+
result += this.input[this.pos];
|
|
586
|
+
this.pos++;
|
|
587
|
+
}
|
|
588
|
+
return result;
|
|
589
|
+
}
|
|
590
|
+
isKeyword(value) {
|
|
591
|
+
const keywords = ['WHERE', 'AND', 'OR', 'ORDER', 'BY', 'ASC', 'DESC', 'LIMIT', 'IN', 'CONTAINS', 'LIKE', 'NOT', 'IS', 'NULL'];
|
|
592
|
+
return keywords.includes(value.toUpperCase());
|
|
593
|
+
}
|
|
594
|
+
nextToken() {
|
|
595
|
+
this.skipWhitespace();
|
|
596
|
+
if (this.pos >= this.input.length) {
|
|
597
|
+
return { type: 'EOF', value: '', pos: this.pos };
|
|
598
|
+
}
|
|
599
|
+
const char = this.input[this.pos];
|
|
600
|
+
if (char === "'" || char === '"') {
|
|
601
|
+
return { type: 'STRING', value: this.readString(char), pos: this.pos };
|
|
602
|
+
}
|
|
603
|
+
if (/\d/.test(char)) {
|
|
604
|
+
return { type: 'NUMBER', value: this.readNumber(), pos: this.pos };
|
|
605
|
+
}
|
|
606
|
+
if (char === ',') {
|
|
607
|
+
this.pos++;
|
|
608
|
+
return { type: 'COMMA', value: ',', pos: this.pos };
|
|
609
|
+
}
|
|
610
|
+
if (char === '[') {
|
|
611
|
+
this.pos++;
|
|
612
|
+
return { type: 'LBRACKET', value: '[', pos: this.pos };
|
|
613
|
+
}
|
|
614
|
+
if (char === ']') {
|
|
615
|
+
this.pos++;
|
|
616
|
+
return { type: 'RBRACKET', value: ']', pos: this.pos };
|
|
617
|
+
}
|
|
618
|
+
if (/[=<>!]/.test(char)) {
|
|
619
|
+
this.pos++;
|
|
620
|
+
if (char === '=' && this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
621
|
+
this.pos++;
|
|
622
|
+
return { type: 'EQ', value: '==', pos: this.pos };
|
|
623
|
+
}
|
|
624
|
+
if (char === '!' && this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
625
|
+
this.pos++;
|
|
626
|
+
return { type: 'NEQ', value: '!=', pos: this.pos };
|
|
627
|
+
}
|
|
628
|
+
if (char === '>') {
|
|
629
|
+
if (this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
630
|
+
this.pos++;
|
|
631
|
+
return { type: 'GTE', value: '>=', pos: this.pos };
|
|
632
|
+
}
|
|
633
|
+
return { type: 'GT', value: '>', pos: this.pos };
|
|
634
|
+
}
|
|
635
|
+
if (char === '<') {
|
|
636
|
+
if (this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
637
|
+
this.pos++;
|
|
638
|
+
return { type: 'LTE', value: '<=', pos: this.pos };
|
|
639
|
+
}
|
|
640
|
+
return { type: 'LT', value: '<', pos: this.pos };
|
|
641
|
+
}
|
|
642
|
+
return { type: 'EQ', value: char, pos: this.pos };
|
|
643
|
+
}
|
|
644
|
+
const identifier = this.readIdentifier();
|
|
645
|
+
const upperIdentifier = identifier.toUpperCase();
|
|
646
|
+
const keywords = {
|
|
647
|
+
'WHERE': 'WHERE',
|
|
648
|
+
'AND': 'AND',
|
|
649
|
+
'OR': 'OR',
|
|
650
|
+
'ORDER': 'ORDER',
|
|
651
|
+
'BY': 'BY',
|
|
652
|
+
'ASC': 'ASC',
|
|
653
|
+
'DESC': 'DESC',
|
|
654
|
+
'LIMIT': 'LIMIT',
|
|
655
|
+
'IN': 'IN',
|
|
656
|
+
'CONTAINS': 'CONTAINS',
|
|
657
|
+
'LIKE': 'LIKE',
|
|
658
|
+
'NOT': 'NOT',
|
|
659
|
+
'IS': 'IS',
|
|
660
|
+
'NULL': 'NULL'
|
|
661
|
+
};
|
|
662
|
+
if (keywords[upperIdentifier]) {
|
|
663
|
+
return { type: keywords[upperIdentifier], value: upperIdentifier, pos: this.pos };
|
|
664
|
+
}
|
|
665
|
+
return { type: 'IDENTIFIER', value: identifier, pos: this.pos };
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
class Parser {
|
|
669
|
+
constructor(lexer) {
|
|
670
|
+
this.lexer = lexer;
|
|
671
|
+
this.currentToken = this.lexer.nextToken();
|
|
672
|
+
}
|
|
673
|
+
eat(type) {
|
|
674
|
+
if (this.currentToken.type === type) {
|
|
675
|
+
this.currentToken = this.lexer.nextToken();
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
throw new Error(`Expected ${type}, got ${this.currentToken.type}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
parse() {
|
|
682
|
+
const statements = [];
|
|
683
|
+
if (this.currentToken.type === 'WHERE') {
|
|
684
|
+
statements.push(this.parseWhere());
|
|
685
|
+
}
|
|
686
|
+
if (this.currentToken.type === 'ORDER') {
|
|
687
|
+
statements.push(this.parseOrder());
|
|
688
|
+
}
|
|
689
|
+
if (this.currentToken.type === 'LIMIT') {
|
|
690
|
+
statements.push(this.parseLimit());
|
|
691
|
+
}
|
|
692
|
+
return statements;
|
|
693
|
+
}
|
|
694
|
+
parseWhere() {
|
|
695
|
+
this.eat('WHERE');
|
|
696
|
+
return { type: 'WhereClause', left: this.parseCondition() };
|
|
697
|
+
}
|
|
698
|
+
parseCondition() {
|
|
699
|
+
let left = this.parseExpression();
|
|
700
|
+
while (this.currentToken.type === 'AND' || this.currentToken.type === 'OR') {
|
|
701
|
+
const op = this.currentToken.type;
|
|
702
|
+
this.eat(op);
|
|
703
|
+
const right = this.parseExpression();
|
|
704
|
+
left = { type: 'LogicalOp', left, right, operator: op };
|
|
705
|
+
}
|
|
706
|
+
return left;
|
|
707
|
+
}
|
|
708
|
+
parseExpression() {
|
|
709
|
+
const field = this.currentToken.value;
|
|
710
|
+
this.eat('IDENTIFIER');
|
|
711
|
+
let operator;
|
|
712
|
+
let value;
|
|
713
|
+
if (this.currentToken.type === 'NOT') {
|
|
714
|
+
this.eat('NOT');
|
|
715
|
+
operator = 'NOT LIKE';
|
|
716
|
+
this.eat('LIKE');
|
|
717
|
+
value = this.parseValue();
|
|
718
|
+
}
|
|
719
|
+
else if (this.currentToken.type === 'LIKE') {
|
|
720
|
+
operator = 'LIKE';
|
|
721
|
+
this.eat('LIKE');
|
|
722
|
+
value = this.parseValue();
|
|
723
|
+
}
|
|
724
|
+
else if (this.currentToken.type === 'IS') {
|
|
725
|
+
this.eat('IS');
|
|
726
|
+
if (this.currentToken.type === 'NOT') {
|
|
727
|
+
operator = 'IS NOT NULL';
|
|
728
|
+
this.eat('NOT');
|
|
729
|
+
this.eat('NULL');
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
operator = 'IS NULL';
|
|
733
|
+
this.eat('NULL');
|
|
734
|
+
}
|
|
735
|
+
value = null;
|
|
736
|
+
}
|
|
737
|
+
else if (this.currentToken.type === 'CONTAINS') {
|
|
738
|
+
operator = 'CONTAINS';
|
|
739
|
+
this.eat('CONTAINS');
|
|
740
|
+
value = this.parseValue();
|
|
741
|
+
}
|
|
742
|
+
else if (this.currentToken.type === 'IN') {
|
|
743
|
+
operator = 'IN';
|
|
744
|
+
this.eat('IN');
|
|
745
|
+
value = this.parseInList();
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
const opType = this.currentToken.type;
|
|
749
|
+
this.eat(opType);
|
|
750
|
+
operator = opType;
|
|
751
|
+
value = this.parseValue();
|
|
752
|
+
}
|
|
753
|
+
return { type: 'Condition', field, operator, value };
|
|
754
|
+
}
|
|
755
|
+
parseInList() {
|
|
756
|
+
this.eat('LBRACKET');
|
|
757
|
+
const values = [];
|
|
758
|
+
while (this.currentToken.type !== 'RBRACKET') {
|
|
759
|
+
const node = this.parseValue();
|
|
760
|
+
values.push(node.value);
|
|
761
|
+
if (this.currentToken.type === 'COMMA') {
|
|
762
|
+
this.eat('COMMA');
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
this.eat('RBRACKET');
|
|
766
|
+
return values;
|
|
767
|
+
}
|
|
768
|
+
parseValue() {
|
|
769
|
+
if (this.currentToken.type === 'STRING') {
|
|
770
|
+
const value = this.currentToken.value;
|
|
771
|
+
this.eat('STRING');
|
|
772
|
+
return { type: 'Value', value };
|
|
773
|
+
}
|
|
774
|
+
if (this.currentToken.type === 'NUMBER') {
|
|
775
|
+
const value = parseFloat(this.currentToken.value);
|
|
776
|
+
this.eat('NUMBER');
|
|
777
|
+
return { type: 'Value', value };
|
|
778
|
+
}
|
|
779
|
+
throw new Error(`Expected value, got ${this.currentToken.type}`);
|
|
780
|
+
}
|
|
781
|
+
parseOrder() {
|
|
782
|
+
this.eat('ORDER');
|
|
783
|
+
this.eat('BY');
|
|
784
|
+
const field = this.currentToken.value;
|
|
785
|
+
this.eat('IDENTIFIER');
|
|
786
|
+
let direction = 'ASC';
|
|
787
|
+
if (this.currentToken.type === 'ASC' || this.currentToken.type === 'DESC') {
|
|
788
|
+
direction = this.currentToken.value;
|
|
789
|
+
this.eat(this.currentToken.type);
|
|
790
|
+
}
|
|
791
|
+
return { type: 'OrderClause', field, value: direction };
|
|
792
|
+
}
|
|
793
|
+
parseLimit() {
|
|
794
|
+
this.eat('LIMIT');
|
|
795
|
+
const value = parseFloat(this.currentToken.value);
|
|
796
|
+
this.eat('NUMBER');
|
|
797
|
+
return { type: 'LimitClause', value };
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
class Executor {
|
|
801
|
+
getValueByPath(obj, path) {
|
|
802
|
+
return path.split('.').reduce((acc, part) => acc?.[part], obj);
|
|
803
|
+
}
|
|
804
|
+
likeToRegex(pattern) {
|
|
805
|
+
let regex = '';
|
|
806
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
807
|
+
const char = pattern[i];
|
|
808
|
+
if (char === '%') {
|
|
809
|
+
regex += '.*';
|
|
810
|
+
}
|
|
811
|
+
else if (char === '_') {
|
|
812
|
+
regex += '.';
|
|
813
|
+
}
|
|
814
|
+
else if (/[.*+?^${}()|[\]\\]/.test(char)) {
|
|
815
|
+
regex += '\\' + char;
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
regex += char;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return new RegExp(`^${regex}$`, 'i');
|
|
822
|
+
}
|
|
823
|
+
evaluateCondition(node, item) {
|
|
824
|
+
if (node.type === 'Condition') {
|
|
825
|
+
const fieldValue = this.getValueByPath(item, node.field);
|
|
826
|
+
const { operator, value } = node;
|
|
827
|
+
const actualValue = value?.type === 'Value' ? value.value : value;
|
|
828
|
+
switch (operator) {
|
|
829
|
+
case 'EQ':
|
|
830
|
+
return fieldValue === actualValue;
|
|
831
|
+
case 'NEQ':
|
|
832
|
+
return fieldValue !== actualValue;
|
|
833
|
+
case 'GT':
|
|
834
|
+
return fieldValue > actualValue;
|
|
835
|
+
case 'LT':
|
|
836
|
+
return fieldValue < actualValue;
|
|
837
|
+
case 'GTE':
|
|
838
|
+
return fieldValue >= actualValue;
|
|
839
|
+
case 'LTE':
|
|
840
|
+
return fieldValue <= actualValue;
|
|
841
|
+
case 'IN':
|
|
842
|
+
return Array.isArray(actualValue) && actualValue.includes(fieldValue);
|
|
843
|
+
case 'CONTAINS':
|
|
844
|
+
return Array.isArray(fieldValue) && fieldValue.includes(actualValue);
|
|
845
|
+
case 'LIKE':
|
|
846
|
+
if (typeof fieldValue !== 'string' || typeof actualValue !== 'string') {
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
return this.likeToRegex(actualValue).test(fieldValue);
|
|
850
|
+
case 'NOT LIKE':
|
|
851
|
+
if (typeof fieldValue !== 'string' || typeof actualValue !== 'string') {
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
return !this.likeToRegex(actualValue).test(fieldValue);
|
|
855
|
+
case 'IS NULL':
|
|
856
|
+
return fieldValue === null || fieldValue === undefined;
|
|
857
|
+
case 'IS NOT NULL':
|
|
858
|
+
return fieldValue !== null && fieldValue !== undefined;
|
|
859
|
+
default:
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (node.type === 'LogicalOp') {
|
|
864
|
+
const leftResult = this.evaluateCondition(node.left, item);
|
|
865
|
+
const rightResult = this.evaluateCondition(node.right, item);
|
|
866
|
+
return node.operator === 'AND'
|
|
867
|
+
? leftResult && rightResult
|
|
868
|
+
: leftResult || rightResult;
|
|
869
|
+
}
|
|
870
|
+
return true;
|
|
871
|
+
}
|
|
872
|
+
execute(statements, data) {
|
|
873
|
+
let result = [...data];
|
|
874
|
+
for (const stmt of statements) {
|
|
875
|
+
if (stmt.type === 'WhereClause') {
|
|
876
|
+
result = result.filter(item => this.evaluateCondition(stmt.left, item));
|
|
877
|
+
}
|
|
878
|
+
else if (stmt.type === 'OrderClause') {
|
|
879
|
+
const field = stmt.field;
|
|
880
|
+
const direction = stmt.value;
|
|
881
|
+
result.sort((a, b) => {
|
|
882
|
+
const aVal = this.getValueByPath(a, field);
|
|
883
|
+
const bVal = this.getValueByPath(b, field);
|
|
884
|
+
if (aVal === bVal)
|
|
885
|
+
return 0;
|
|
886
|
+
const cmp = aVal > bVal ? 1 : -1;
|
|
887
|
+
return direction === 'ASC' ? cmp : -cmp;
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
else if (stmt.type === 'LimitClause') {
|
|
891
|
+
result = result.slice(0, stmt.value);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return result;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function filter(data, query) {
|
|
898
|
+
if (!query || query.trim() === '') {
|
|
899
|
+
return data;
|
|
900
|
+
}
|
|
901
|
+
const lexer = new Lexer(query);
|
|
902
|
+
const parser = new Parser(lexer);
|
|
903
|
+
const ast = parser.parse();
|
|
904
|
+
const executor = new Executor();
|
|
905
|
+
return executor.execute(ast, data);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
const createRouterAgentPluginFn = (opts) => {
|
|
909
|
+
let router = opts?.router;
|
|
910
|
+
if (!router) {
|
|
911
|
+
const app = useContextKey('app');
|
|
912
|
+
router = app.router;
|
|
913
|
+
}
|
|
914
|
+
if (!router) {
|
|
915
|
+
throw new Error('Router 参数缺失');
|
|
916
|
+
}
|
|
917
|
+
const _routes = filter(router.routes, opts?.query || '');
|
|
918
|
+
const routes = _routes.filter(r => {
|
|
919
|
+
const metadata = r.metadata;
|
|
920
|
+
if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
|
|
921
|
+
return !!metadata.skill;
|
|
922
|
+
}
|
|
923
|
+
return false;
|
|
924
|
+
});
|
|
925
|
+
// opencode run "查看系统信息"
|
|
926
|
+
const AgentPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
927
|
+
return {
|
|
928
|
+
'tool': {
|
|
929
|
+
...routes.reduce((acc, route) => {
|
|
930
|
+
const metadata = route.metadata;
|
|
931
|
+
acc[metadata.skill] = {
|
|
932
|
+
name: metadata.title || metadata.skill,
|
|
933
|
+
description: metadata.summary || '',
|
|
934
|
+
args: metadata.args || {},
|
|
935
|
+
async execute(args) {
|
|
936
|
+
const res = await router.run({
|
|
937
|
+
path: route.path,
|
|
938
|
+
key: route.key,
|
|
939
|
+
payload: args
|
|
940
|
+
}, { appId: router.appId });
|
|
941
|
+
if (res.code === 200) {
|
|
942
|
+
if (res.data?.content) {
|
|
943
|
+
return res.data.content;
|
|
944
|
+
}
|
|
945
|
+
if (res.data?.final) {
|
|
946
|
+
return '调用程序成功';
|
|
947
|
+
}
|
|
948
|
+
const str = JSON.stringify(res.data || res, null, 2);
|
|
949
|
+
if (str.length > 10000) {
|
|
950
|
+
return str.slice(0, 10000) + '... (truncated)';
|
|
951
|
+
}
|
|
952
|
+
return str;
|
|
953
|
+
}
|
|
954
|
+
return `Error: ${res?.message || '无法获取结果'}`;
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
return acc;
|
|
958
|
+
}, {})
|
|
959
|
+
},
|
|
960
|
+
'tool.execute.before': async (opts) => {
|
|
961
|
+
// console.log('CnbPlugin: tool.execute.before', opts.tool);
|
|
962
|
+
// delete toolSkills['cnb-login-verify']
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
};
|
|
966
|
+
return AgentPlugin;
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
export { createRouterAgentPluginFn };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@kevisual/router",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.57",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/router.js",
|
|
@@ -21,11 +21,14 @@
|
|
|
21
21
|
"keywords": [],
|
|
22
22
|
"author": "abearxiong",
|
|
23
23
|
"license": "MIT",
|
|
24
|
-
"packageManager": "pnpm@10.28.
|
|
24
|
+
"packageManager": "pnpm@10.28.1",
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@kevisual/
|
|
26
|
+
"@kevisual/context": "^0.0.4",
|
|
27
|
+
"@kevisual/js-filter": "^0.0.5",
|
|
27
28
|
"@kevisual/local-proxy": "^0.0.8",
|
|
28
29
|
"@kevisual/query": "^0.0.35",
|
|
30
|
+
"@kevisual/use-config": "^1.0.28",
|
|
31
|
+
"@opencode-ai/plugin": "^1.1.26",
|
|
29
32
|
"@rollup/plugin-alias": "^6.0.0",
|
|
30
33
|
"@rollup/plugin-commonjs": "29.0.0",
|
|
31
34
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
@@ -35,10 +38,10 @@
|
|
|
35
38
|
"@types/send": "^1.2.1",
|
|
36
39
|
"@types/ws": "^8.18.1",
|
|
37
40
|
"@types/xml2js": "^0.4.14",
|
|
38
|
-
"eventemitter3": "^5.0.
|
|
41
|
+
"eventemitter3": "^5.0.4",
|
|
39
42
|
"nanoid": "^5.1.6",
|
|
40
43
|
"path-to-regexp": "^8.3.0",
|
|
41
|
-
"rollup": "^4.55.
|
|
44
|
+
"rollup": "^4.55.2",
|
|
42
45
|
"rollup-plugin-dts": "^6.3.0",
|
|
43
46
|
"send": "^1.2.1",
|
|
44
47
|
"ts-loader": "^9.5.4",
|
|
@@ -76,6 +79,7 @@
|
|
|
76
79
|
"require": "./dist/router-simple.js",
|
|
77
80
|
"types": "./dist/router-simple.d.ts"
|
|
78
81
|
},
|
|
82
|
+
"./opencode": "./dist/opencode.js",
|
|
79
83
|
"./define": {
|
|
80
84
|
"import": "./dist/router-define.js",
|
|
81
85
|
"require": "./dist/router-define.js",
|
package/src/opencode.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useContextKey } from '@kevisual/context'
|
|
2
|
+
import { type QueryRouter, type Skill } from './route.ts'
|
|
3
|
+
import { type App } from './app.ts'
|
|
4
|
+
import { type Plugin } from "@opencode-ai/plugin"
|
|
5
|
+
|
|
6
|
+
import { filter } from '@kevisual/js-filter';
|
|
7
|
+
|
|
8
|
+
export const createRouterAgentPluginFn = (opts?: {
|
|
9
|
+
router?: QueryRouter,
|
|
10
|
+
//** 过滤比如,WHERE metadata.tags includes 'opencode' */
|
|
11
|
+
query?: string
|
|
12
|
+
}) => {
|
|
13
|
+
let router = opts?.router
|
|
14
|
+
if (!router) {
|
|
15
|
+
const app = useContextKey<App>('app')
|
|
16
|
+
router = app.router
|
|
17
|
+
}
|
|
18
|
+
if (!router) {
|
|
19
|
+
throw new Error('Router 参数缺失')
|
|
20
|
+
}
|
|
21
|
+
const _routes = filter(router.routes, opts?.query || '')
|
|
22
|
+
const routes = _routes.filter(r => {
|
|
23
|
+
const metadata = r.metadata as Skill
|
|
24
|
+
if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
|
|
25
|
+
return !!metadata.skill
|
|
26
|
+
}
|
|
27
|
+
return false
|
|
28
|
+
})
|
|
29
|
+
// opencode run "查看系统信息"
|
|
30
|
+
const AgentPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
|
|
31
|
+
return {
|
|
32
|
+
'tool': {
|
|
33
|
+
...routes.reduce((acc, route) => {
|
|
34
|
+
const metadata = route.metadata as Skill
|
|
35
|
+
acc[metadata.skill!] = {
|
|
36
|
+
name: metadata.title || metadata.skill,
|
|
37
|
+
description: metadata.summary || '',
|
|
38
|
+
args: metadata.args || {},
|
|
39
|
+
async execute(args: Record<string, any>) {
|
|
40
|
+
const res = await router.run({
|
|
41
|
+
path: route.path,
|
|
42
|
+
key: route.key,
|
|
43
|
+
payload: args
|
|
44
|
+
},
|
|
45
|
+
{ appId: router.appId! });
|
|
46
|
+
if (res.code === 200) {
|
|
47
|
+
if (res.data?.content) {
|
|
48
|
+
return res.data.content;
|
|
49
|
+
}
|
|
50
|
+
if (res.data?.final) {
|
|
51
|
+
return '调用程序成功';
|
|
52
|
+
}
|
|
53
|
+
const str = JSON.stringify(res.data || res, null, 2);
|
|
54
|
+
if (str.length > 10000) {
|
|
55
|
+
return str.slice(0, 10000) + '... (truncated)';
|
|
56
|
+
}
|
|
57
|
+
return str;
|
|
58
|
+
}
|
|
59
|
+
return `Error: ${res?.message || '无法获取结果'}`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return acc;
|
|
63
|
+
}, {} as Record<string, any>)
|
|
64
|
+
},
|
|
65
|
+
'tool.execute.before': async (opts) => {
|
|
66
|
+
// console.log('CnbPlugin: tool.execute.before', opts.tool);
|
|
67
|
+
// delete toolSkills['cnb-login-verify']
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return AgentPlugin
|
|
72
|
+
}
|