@fraqjs/fraq 0.8.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/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/capturer.d.ts
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,
@@ -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,6 +5780,7 @@ declare namespace seg {
5775
5780
  //#endregion
5776
5781
  export {
5777
5782
  ApiEndpoints,
5783
+ Capturer,
5778
5784
  Command,
5779
5785
  Context,
5780
5786
  ContextOptions,
@@ -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
- if (this.offset !== this.segments.length - 1) return false;
119
- const segment = this.segments[this.offset];
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, this.subOffset ?? 0) < segment.data.text.length;
122
+ return this.findTextTokenStart(segment.data.text, position.subOffset ?? 0) < segment.data.text.length;
122
123
  }
123
124
  greedy() {
124
- if (!this.isGreedyAvailable()) throw new Error("Greedy token is not available");
125
- const segment = this.segments[this.offset];
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, this.subOffset ?? 0);
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 = this.segments.length;
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;
@@ -165,6 +192,7 @@ var Router = class Router {
165
192
  entries = [];
166
193
  groups = /* @__PURE__ */ new Map();
167
194
  command(command) {
195
+ this.validatePattern(command.pattern);
168
196
  this.entries.push({
169
197
  type: "command",
170
198
  command
@@ -172,9 +200,7 @@ var Router = class Router {
172
200
  return this;
173
201
  }
174
202
  rawPattern(rawPattern) {
175
- if (Object.keys(rawPattern.pattern).length === 0) throw new Error("Raw pattern must have at least one parameter.");
176
- const firstKey = Object.keys(rawPattern.pattern)[0];
177
- if (rawPattern.pattern[firstKey].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.");
203
+ this.validatePattern(rawPattern.pattern, { rawPattern: true });
178
204
  this.entries.push({
179
205
  type: "rawPattern",
180
206
  rawPattern
@@ -300,6 +326,15 @@ var Router = class Router {
300
326
  }
301
327
  return branches;
302
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
+ }
303
338
  capturePattern(pattern, tokenizer) {
304
339
  const initialState = tokenizer.getState();
305
340
  const params = {};
@@ -1052,11 +1087,22 @@ let seg;
1052
1087
  const milkyVersion = "1.3";
1053
1088
  const milkyPackageVersion = "1.3.0-rc.1";
1054
1089
  //#endregion
1055
- //#region src/routing/capturer.ts
1056
- let capturer;
1057
- (function(_capturer) {
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) {
1058
1104
  function literal(literal) {
1059
- return {
1105
+ return new Parameter({
1060
1106
  typeInstruction: {
1061
1107
  type: "literal",
1062
1108
  literal
@@ -1068,44 +1114,62 @@ let capturer;
1068
1114
  return token;
1069
1115
  }
1070
1116
  }
1071
- };
1117
+ });
1118
+ }
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
+ });
1072
1134
  }
1073
- _capturer.literal = literal;
1074
- _capturer.num = {
1075
- typeInstruction: { type: "number" },
1076
- capture(tokenizer) {
1077
- const token = tokenizer.peek();
1078
- if (typeof token === "string") {
1079
- const parsed = Number(token);
1080
- if (!Number.isNaN(parsed)) {
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") {
1081
1142
  tokenizer.next();
1082
- return parsed;
1143
+ return token;
1083
1144
  }
1084
1145
  }
1085
- }
1086
- };
1087
- _capturer.str = {
1088
- typeInstruction: { type: "string" },
1089
- capture(tokenizer) {
1090
- const token = tokenizer.peek();
1091
- if (typeof token === "string") {
1092
- tokenizer.next();
1093
- 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();
1094
1154
  }
1095
- }
1096
- };
1097
- _capturer.greedy = {
1098
- typeInstruction: { type: "greedy" },
1099
- capture(tokenizer) {
1100
- if (tokenizer.isGreedyAvailable()) return tokenizer.greedy();
1101
- }
1102
- };
1103
- function union(...members) {
1104
- const literalSet = new Set(members);
1105
- return {
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({
1106
1170
  typeInstruction: {
1107
1171
  type: "union",
1108
- members
1172
+ members: literals
1109
1173
  },
1110
1174
  capture(tokenizer) {
1111
1175
  const token = tokenizer.peek();
@@ -1114,11 +1178,11 @@ let capturer;
1114
1178
  return token;
1115
1179
  }
1116
1180
  }
1117
- };
1181
+ });
1118
1182
  }
1119
- _capturer.union = union;
1183
+ _param.union = union;
1120
1184
  function segment(type) {
1121
- return {
1185
+ return new Parameter({
1122
1186
  typeInstruction: {
1123
1187
  type: "segment",
1124
1188
  segmentType: type
@@ -1130,47 +1194,7 @@ let capturer;
1130
1194
  return token;
1131
1195
  }
1132
1196
  }
1133
- };
1134
- }
1135
- _capturer.segment = segment;
1136
- })(capturer || (capturer = {}));
1137
- //#endregion
1138
- //#region src/routing/parameter.ts
1139
- var Parameter = class {
1140
- capturer;
1141
- description;
1142
- constructor(capturer) {
1143
- this.capturer = capturer;
1144
- }
1145
- describe(description) {
1146
- this.description = description;
1147
- return this;
1148
- }
1149
- };
1150
- let param;
1151
- (function(_param) {
1152
- function literal(literal) {
1153
- return new Parameter(capturer.literal(literal));
1154
- }
1155
- _param.literal = literal;
1156
- function num() {
1157
- return new Parameter(capturer.num);
1158
- }
1159
- _param.num = num;
1160
- function str() {
1161
- return new Parameter(capturer.str);
1162
- }
1163
- _param.str = str;
1164
- function greedy() {
1165
- return new Parameter(capturer.greedy);
1166
- }
1167
- _param.greedy = greedy;
1168
- function union(...literals) {
1169
- return new Parameter(capturer.union(...literals));
1170
- }
1171
- _param.union = union;
1172
- function segment(type) {
1173
- return new Parameter(capturer.segment(type));
1197
+ });
1174
1198
  }
1175
1199
  _param.segment = segment;
1176
1200
  })(param || (param = {}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fraqjs/fraq",
3
3
  "type": "module",
4
- "version": "0.8.0",
4
+ "version": "0.8.1",
5
5
  "description": "Milky Bot framework",
6
6
  "files": [
7
7
  "dist"