@fraqjs/fraq 0.7.0 → 0.8.1
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 +5 -5
- package/dist/index.d.mts +26 -19
- package/dist/index.mjs +117 -101
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,15 +27,15 @@ const ctx = Context.fromUrl('<替换成你的 Milky 协议端地址>', {
|
|
|
27
27
|
// accessToken: '<如果你的 Milky 协议端配置了 token,请在这里添加>',
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
ctx.router.command(
|
|
31
|
-
'echo',
|
|
32
|
-
{
|
|
30
|
+
ctx.router.command({
|
|
31
|
+
name: 'echo',
|
|
32
|
+
pattern: {
|
|
33
33
|
content: param.greedy(),
|
|
34
34
|
},
|
|
35
|
-
(session, { content })
|
|
35
|
+
execute(session, { content }) {
|
|
36
36
|
session.reply(msg`You said: ${content}`);
|
|
37
37
|
},
|
|
38
|
-
);
|
|
38
|
+
});
|
|
39
39
|
|
|
40
40
|
ctx.start();
|
|
41
41
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -5444,12 +5444,14 @@ declare class Tokenizer {
|
|
|
5444
5444
|
next(): Token | undefined;
|
|
5445
5445
|
isGreedyAvailable(): boolean;
|
|
5446
5446
|
greedy(): string;
|
|
5447
|
+
isCatchAllAvailable(): boolean;
|
|
5448
|
+
catchAll(): IncomingSegment[];
|
|
5447
5449
|
private findNextPosition;
|
|
5448
5450
|
private findTextTokenStart;
|
|
5449
5451
|
private readTextToken;
|
|
5450
5452
|
}
|
|
5451
5453
|
//#endregion
|
|
5452
|
-
//#region src/routing/
|
|
5454
|
+
//#region src/routing/parameter.d.ts
|
|
5453
5455
|
interface Capturer<T> {
|
|
5454
5456
|
typeInstruction: TypeInstruction;
|
|
5455
5457
|
capture(tokenizer: Tokenizer): T | undefined;
|
|
@@ -5468,6 +5470,9 @@ type TypeInstruction =
|
|
|
5468
5470
|
| {
|
|
5469
5471
|
type: 'greedy';
|
|
5470
5472
|
}
|
|
5473
|
+
| {
|
|
5474
|
+
type: 'catchAll';
|
|
5475
|
+
}
|
|
5471
5476
|
| {
|
|
5472
5477
|
type: 'union';
|
|
5473
5478
|
members: string[];
|
|
@@ -5476,8 +5481,6 @@ type TypeInstruction =
|
|
|
5476
5481
|
type: 'segment';
|
|
5477
5482
|
segmentType: Exclude<Token, string>['type'];
|
|
5478
5483
|
};
|
|
5479
|
-
//#endregion
|
|
5480
|
-
//#region src/routing/parameter.d.ts
|
|
5481
5484
|
declare class Parameter<T> {
|
|
5482
5485
|
readonly capturer: Capturer<T>;
|
|
5483
5486
|
description?: string;
|
|
@@ -5489,6 +5492,7 @@ declare namespace param {
|
|
|
5489
5492
|
function num(): Parameter<number>;
|
|
5490
5493
|
function str(): Parameter<string>;
|
|
5491
5494
|
function greedy(): Parameter<string>;
|
|
5495
|
+
function catchAll(): Parameter<IncomingSegment[]>;
|
|
5492
5496
|
function union<T extends string>(...literals: T[]): Parameter<T>;
|
|
5493
5497
|
function segment<T extends Exclude<Token, string>['type']>(
|
|
5494
5498
|
type: T,
|
|
@@ -5505,21 +5509,21 @@ declare namespace param {
|
|
|
5505
5509
|
//#region src/routing/router.d.ts
|
|
5506
5510
|
type Pattern = Record<string, Parameter<any>>;
|
|
5507
5511
|
type ParamsOf<P extends Pattern> = { [K in keyof P]: P[K] extends Parameter<infer T> ? T : never };
|
|
5508
|
-
type
|
|
5512
|
+
type Executor<P extends Pattern> = (session: Session, params: ParamsOf<P>) => void | Promise<void>;
|
|
5509
5513
|
type SessionPredicate = (session: Session) => boolean;
|
|
5510
|
-
interface Command {
|
|
5514
|
+
interface Command<P extends Pattern> {
|
|
5511
5515
|
name: string;
|
|
5512
|
-
pattern:
|
|
5513
|
-
|
|
5516
|
+
pattern: P;
|
|
5517
|
+
execute: Executor<P>;
|
|
5514
5518
|
}
|
|
5515
|
-
interface RawPattern {
|
|
5516
|
-
pattern:
|
|
5517
|
-
|
|
5519
|
+
interface RawPattern<P extends Pattern> {
|
|
5520
|
+
pattern: P;
|
|
5521
|
+
execute: Executor<P>;
|
|
5518
5522
|
}
|
|
5519
5523
|
type RouteEntry =
|
|
5520
5524
|
| {
|
|
5521
5525
|
type: 'command';
|
|
5522
|
-
command: Command
|
|
5526
|
+
command: Command<Pattern>;
|
|
5523
5527
|
}
|
|
5524
5528
|
| {
|
|
5525
5529
|
type: 'group';
|
|
@@ -5533,30 +5537,30 @@ type RouteEntry =
|
|
|
5533
5537
|
}
|
|
5534
5538
|
| {
|
|
5535
5539
|
type: 'rawPattern';
|
|
5536
|
-
rawPattern: RawPattern
|
|
5540
|
+
rawPattern: RawPattern<Pattern>;
|
|
5537
5541
|
};
|
|
5538
5542
|
type RouteBranch =
|
|
5539
5543
|
| {
|
|
5540
5544
|
type: 'command';
|
|
5541
5545
|
path: string[];
|
|
5542
|
-
command: Command
|
|
5546
|
+
command: Command<Pattern>;
|
|
5543
5547
|
}
|
|
5544
5548
|
| {
|
|
5545
5549
|
type: 'rawPattern';
|
|
5546
5550
|
path: string[];
|
|
5547
|
-
rawPattern: RawPattern
|
|
5551
|
+
rawPattern: RawPattern<Pattern>;
|
|
5548
5552
|
};
|
|
5549
5553
|
type RouteMatchResult =
|
|
5550
5554
|
| {
|
|
5551
5555
|
type: 'command';
|
|
5552
5556
|
path: string[];
|
|
5553
|
-
command: Command
|
|
5557
|
+
command: Command<Pattern>;
|
|
5554
5558
|
params: any;
|
|
5555
5559
|
}
|
|
5556
5560
|
| {
|
|
5557
5561
|
type: 'rawPattern';
|
|
5558
5562
|
path: string[];
|
|
5559
|
-
rawPattern: RawPattern
|
|
5563
|
+
rawPattern: RawPattern<Pattern>;
|
|
5560
5564
|
params: any;
|
|
5561
5565
|
};
|
|
5562
5566
|
interface Session {
|
|
@@ -5566,8 +5570,8 @@ interface Session {
|
|
|
5566
5570
|
declare class Router {
|
|
5567
5571
|
private readonly entries;
|
|
5568
5572
|
private readonly groups;
|
|
5569
|
-
command<P extends Pattern>(
|
|
5570
|
-
rawPattern<P extends Pattern>(
|
|
5573
|
+
command<P extends Pattern>(command: Command<P>): this;
|
|
5574
|
+
rawPattern<P extends Pattern>(rawPattern: RawPattern<P>): this;
|
|
5571
5575
|
group(name: string): Router;
|
|
5572
5576
|
filter(predicate: SessionPredicate): Router;
|
|
5573
5577
|
routes(): RouteEntry[];
|
|
@@ -5580,6 +5584,7 @@ declare class Router {
|
|
|
5580
5584
|
private matchGroup;
|
|
5581
5585
|
private matchRawPattern;
|
|
5582
5586
|
private branchesFrom;
|
|
5587
|
+
private validatePattern;
|
|
5583
5588
|
private capturePattern;
|
|
5584
5589
|
}
|
|
5585
5590
|
//#endregion
|
|
@@ -5775,14 +5780,15 @@ declare namespace seg {
|
|
|
5775
5780
|
//#endregion
|
|
5776
5781
|
export {
|
|
5777
5782
|
ApiEndpoints,
|
|
5783
|
+
Capturer,
|
|
5778
5784
|
Command,
|
|
5779
5785
|
Context,
|
|
5780
5786
|
ContextOptions,
|
|
5781
5787
|
ContextUrlOptions,
|
|
5782
5788
|
Disposable,
|
|
5783
5789
|
EventMap,
|
|
5790
|
+
Executor,
|
|
5784
5791
|
Filter,
|
|
5785
|
-
Handler,
|
|
5786
5792
|
Injection,
|
|
5787
5793
|
LogHandler,
|
|
5788
5794
|
LogLevel,
|
|
@@ -5803,6 +5809,7 @@ export {
|
|
|
5803
5809
|
ServiceClass,
|
|
5804
5810
|
Session,
|
|
5805
5811
|
SessionPredicate,
|
|
5812
|
+
TypeInstruction,
|
|
5806
5813
|
combineLogHandlers,
|
|
5807
5814
|
createMilkyClient,
|
|
5808
5815
|
definePlugin,
|
package/dist/index.mjs
CHANGED
|
@@ -115,21 +115,48 @@ var Tokenizer = class {
|
|
|
115
115
|
return token;
|
|
116
116
|
}
|
|
117
117
|
isGreedyAvailable() {
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
const position = this.findNextPosition();
|
|
119
|
+
if (position === void 0) return false;
|
|
120
|
+
const segment = this.segments[position.offset];
|
|
120
121
|
if (segment?.type !== "text") return false;
|
|
121
|
-
return this.findTextTokenStart(segment.data.text,
|
|
122
|
+
return this.findTextTokenStart(segment.data.text, position.subOffset ?? 0) < segment.data.text.length;
|
|
122
123
|
}
|
|
123
124
|
greedy() {
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
const position = this.findNextPosition();
|
|
126
|
+
if (position === void 0) throw new Error("Greedy token is not available");
|
|
127
|
+
const segment = this.segments[position.offset];
|
|
126
128
|
if (segment.type !== "text") throw new Error("Greedy token is not available");
|
|
127
|
-
const tokenStart = this.findTextTokenStart(segment.data.text,
|
|
129
|
+
const tokenStart = this.findTextTokenStart(segment.data.text, position.subOffset ?? 0);
|
|
130
|
+
if (tokenStart >= segment.data.text.length) throw new Error("Greedy token is not available");
|
|
128
131
|
const token = segment.data.text.slice(tokenStart);
|
|
129
|
-
this.offset =
|
|
132
|
+
this.offset = position.offset + 1;
|
|
130
133
|
this.subOffset = void 0;
|
|
131
134
|
return token;
|
|
132
135
|
}
|
|
136
|
+
isCatchAllAvailable() {
|
|
137
|
+
return this.findNextPosition() !== void 0;
|
|
138
|
+
}
|
|
139
|
+
catchAll() {
|
|
140
|
+
const position = this.findNextPosition();
|
|
141
|
+
if (position === void 0) throw new Error("Catch-all token is not available");
|
|
142
|
+
const segment = this.segments[position.offset];
|
|
143
|
+
const segments = [];
|
|
144
|
+
if (segment.type === "text") {
|
|
145
|
+
const textStart = this.findTextTokenStart(segment.data.text, position.subOffset ?? 0);
|
|
146
|
+
const text = segment.data.text.slice(textStart);
|
|
147
|
+
if (text.length > 0) segments.push({
|
|
148
|
+
...segment,
|
|
149
|
+
data: {
|
|
150
|
+
...segment.data,
|
|
151
|
+
text
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
segments.push(...this.segments.slice(position.offset + 1));
|
|
155
|
+
} else segments.push(...this.segments.slice(position.offset));
|
|
156
|
+
this.offset = this.segments.length;
|
|
157
|
+
this.subOffset = void 0;
|
|
158
|
+
return segments;
|
|
159
|
+
}
|
|
133
160
|
findNextPosition() {
|
|
134
161
|
let offset = this.offset;
|
|
135
162
|
let subOffset = this.subOffset;
|
|
@@ -164,25 +191,16 @@ var Tokenizer = class {
|
|
|
164
191
|
var Router = class Router {
|
|
165
192
|
entries = [];
|
|
166
193
|
groups = /* @__PURE__ */ new Map();
|
|
167
|
-
command(
|
|
168
|
-
|
|
169
|
-
name,
|
|
170
|
-
pattern,
|
|
171
|
-
handler
|
|
172
|
-
};
|
|
194
|
+
command(command) {
|
|
195
|
+
this.validatePattern(command.pattern);
|
|
173
196
|
this.entries.push({
|
|
174
197
|
type: "command",
|
|
175
198
|
command
|
|
176
199
|
});
|
|
177
200
|
return this;
|
|
178
201
|
}
|
|
179
|
-
rawPattern(
|
|
180
|
-
|
|
181
|
-
if (pattern[Object.keys(pattern)[0]].capturer.typeInstruction.type === "literal") throw new Error("The first parameter of a raw pattern cannot be a literal, as it would conflict with command patterns.");
|
|
182
|
-
const rawPattern = {
|
|
183
|
-
pattern,
|
|
184
|
-
handler
|
|
185
|
-
};
|
|
202
|
+
rawPattern(rawPattern) {
|
|
203
|
+
this.validatePattern(rawPattern.pattern, { rawPattern: true });
|
|
186
204
|
this.entries.push({
|
|
187
205
|
type: "rawPattern",
|
|
188
206
|
rawPattern
|
|
@@ -226,10 +244,10 @@ var Router = class Router {
|
|
|
226
244
|
if (match === void 0) return false;
|
|
227
245
|
switch (match.type) {
|
|
228
246
|
case "command":
|
|
229
|
-
await match.command.
|
|
247
|
+
await match.command.execute(session, match.params);
|
|
230
248
|
break;
|
|
231
249
|
case "rawPattern":
|
|
232
|
-
await match.rawPattern.
|
|
250
|
+
await match.rawPattern.execute(session, match.params);
|
|
233
251
|
break;
|
|
234
252
|
}
|
|
235
253
|
return true;
|
|
@@ -308,6 +326,15 @@ var Router = class Router {
|
|
|
308
326
|
}
|
|
309
327
|
return branches;
|
|
310
328
|
}
|
|
329
|
+
validatePattern(pattern, options) {
|
|
330
|
+
const entries = Object.entries(pattern);
|
|
331
|
+
if (options?.rawPattern && entries.length === 0) throw new Error("Raw pattern must have at least one parameter.");
|
|
332
|
+
if (options?.rawPattern && entries[0]?.[1].capturer.typeInstruction.type === "literal") throw new Error("The first parameter of a raw pattern cannot be a literal, as it would conflict with command patterns.");
|
|
333
|
+
const catchAllEntryIndex = entries.findIndex(([, parameter]) => {
|
|
334
|
+
return parameter.capturer.typeInstruction.type === "catchAll";
|
|
335
|
+
});
|
|
336
|
+
if (catchAllEntryIndex !== -1 && catchAllEntryIndex !== entries.length - 1) throw new Error("Catch-all parameters must be the last parameter in a pattern.");
|
|
337
|
+
}
|
|
311
338
|
capturePattern(pattern, tokenizer) {
|
|
312
339
|
const initialState = tokenizer.getState();
|
|
313
340
|
const params = {};
|
|
@@ -1060,11 +1087,22 @@ let seg;
|
|
|
1060
1087
|
const milkyVersion = "1.3";
|
|
1061
1088
|
const milkyPackageVersion = "1.3.0-rc.1";
|
|
1062
1089
|
//#endregion
|
|
1063
|
-
//#region src/routing/
|
|
1064
|
-
|
|
1065
|
-
|
|
1090
|
+
//#region src/routing/parameter.ts
|
|
1091
|
+
var Parameter = class {
|
|
1092
|
+
capturer;
|
|
1093
|
+
description;
|
|
1094
|
+
constructor(capturer) {
|
|
1095
|
+
this.capturer = capturer;
|
|
1096
|
+
}
|
|
1097
|
+
describe(description) {
|
|
1098
|
+
this.description = description;
|
|
1099
|
+
return this;
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
let param;
|
|
1103
|
+
(function(_param) {
|
|
1066
1104
|
function literal(literal) {
|
|
1067
|
-
return {
|
|
1105
|
+
return new Parameter({
|
|
1068
1106
|
typeInstruction: {
|
|
1069
1107
|
type: "literal",
|
|
1070
1108
|
literal
|
|
@@ -1076,44 +1114,62 @@ let capturer;
|
|
|
1076
1114
|
return token;
|
|
1077
1115
|
}
|
|
1078
1116
|
}
|
|
1079
|
-
};
|
|
1117
|
+
});
|
|
1080
1118
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1119
|
+
_param.literal = literal;
|
|
1120
|
+
function num() {
|
|
1121
|
+
return new Parameter({
|
|
1122
|
+
typeInstruction: { type: "number" },
|
|
1123
|
+
capture(tokenizer) {
|
|
1124
|
+
const token = tokenizer.peek();
|
|
1125
|
+
if (typeof token === "string") {
|
|
1126
|
+
const parsed = Number(token);
|
|
1127
|
+
if (!Number.isNaN(parsed)) {
|
|
1128
|
+
tokenizer.next();
|
|
1129
|
+
return parsed;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
_param.num = num;
|
|
1136
|
+
function str() {
|
|
1137
|
+
return new Parameter({
|
|
1138
|
+
typeInstruction: { type: "string" },
|
|
1139
|
+
capture(tokenizer) {
|
|
1140
|
+
const token = tokenizer.peek();
|
|
1141
|
+
if (typeof token === "string") {
|
|
1089
1142
|
tokenizer.next();
|
|
1090
|
-
return
|
|
1143
|
+
return token;
|
|
1091
1144
|
}
|
|
1092
1145
|
}
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
tokenizer.
|
|
1101
|
-
return token;
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
_param.str = str;
|
|
1149
|
+
function greedy() {
|
|
1150
|
+
return new Parameter({
|
|
1151
|
+
typeInstruction: { type: "greedy" },
|
|
1152
|
+
capture(tokenizer) {
|
|
1153
|
+
if (tokenizer.isGreedyAvailable()) return tokenizer.greedy();
|
|
1102
1154
|
}
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
_param.greedy = greedy;
|
|
1158
|
+
function catchAll() {
|
|
1159
|
+
return new Parameter({
|
|
1160
|
+
typeInstruction: { type: "catchAll" },
|
|
1161
|
+
capture(tokenizer) {
|
|
1162
|
+
if (tokenizer.isCatchAllAvailable()) return tokenizer.catchAll();
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
_param.catchAll = catchAll;
|
|
1167
|
+
function union(...literals) {
|
|
1168
|
+
const literalSet = new Set(literals);
|
|
1169
|
+
return new Parameter({
|
|
1114
1170
|
typeInstruction: {
|
|
1115
1171
|
type: "union",
|
|
1116
|
-
members
|
|
1172
|
+
members: literals
|
|
1117
1173
|
},
|
|
1118
1174
|
capture(tokenizer) {
|
|
1119
1175
|
const token = tokenizer.peek();
|
|
@@ -1122,11 +1178,11 @@ let capturer;
|
|
|
1122
1178
|
return token;
|
|
1123
1179
|
}
|
|
1124
1180
|
}
|
|
1125
|
-
};
|
|
1181
|
+
});
|
|
1126
1182
|
}
|
|
1127
|
-
|
|
1183
|
+
_param.union = union;
|
|
1128
1184
|
function segment(type) {
|
|
1129
|
-
return {
|
|
1185
|
+
return new Parameter({
|
|
1130
1186
|
typeInstruction: {
|
|
1131
1187
|
type: "segment",
|
|
1132
1188
|
segmentType: type
|
|
@@ -1138,47 +1194,7 @@ let capturer;
|
|
|
1138
1194
|
return token;
|
|
1139
1195
|
}
|
|
1140
1196
|
}
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
_capturer.segment = segment;
|
|
1144
|
-
})(capturer || (capturer = {}));
|
|
1145
|
-
//#endregion
|
|
1146
|
-
//#region src/routing/parameter.ts
|
|
1147
|
-
var Parameter = class {
|
|
1148
|
-
capturer;
|
|
1149
|
-
description;
|
|
1150
|
-
constructor(capturer) {
|
|
1151
|
-
this.capturer = capturer;
|
|
1152
|
-
}
|
|
1153
|
-
describe(description) {
|
|
1154
|
-
this.description = description;
|
|
1155
|
-
return this;
|
|
1156
|
-
}
|
|
1157
|
-
};
|
|
1158
|
-
let param;
|
|
1159
|
-
(function(_param) {
|
|
1160
|
-
function literal(literal) {
|
|
1161
|
-
return new Parameter(capturer.literal(literal));
|
|
1162
|
-
}
|
|
1163
|
-
_param.literal = literal;
|
|
1164
|
-
function num() {
|
|
1165
|
-
return new Parameter(capturer.num);
|
|
1166
|
-
}
|
|
1167
|
-
_param.num = num;
|
|
1168
|
-
function str() {
|
|
1169
|
-
return new Parameter(capturer.str);
|
|
1170
|
-
}
|
|
1171
|
-
_param.str = str;
|
|
1172
|
-
function greedy() {
|
|
1173
|
-
return new Parameter(capturer.greedy);
|
|
1174
|
-
}
|
|
1175
|
-
_param.greedy = greedy;
|
|
1176
|
-
function union(...literals) {
|
|
1177
|
-
return new Parameter(capturer.union(...literals));
|
|
1178
|
-
}
|
|
1179
|
-
_param.union = union;
|
|
1180
|
-
function segment(type) {
|
|
1181
|
-
return new Parameter(capturer.segment(type));
|
|
1197
|
+
});
|
|
1182
1198
|
}
|
|
1183
1199
|
_param.segment = segment;
|
|
1184
1200
|
})(param || (param = {}));
|