@bool-ts/core 2.1.2 → 2.2.0

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.
@@ -1,5 +1,3 @@
1
- "use strict";
2
-
3
1
  import type { TArgumentsMetadataCollection } from "../decorators/arguments";
4
2
  import type { THttpMethods } from "../http";
5
3
 
@@ -10,16 +8,25 @@ export type THttpRouteModel<T = unknown> = Readonly<{
10
8
  argumentsMetadata: TArgumentsMetadataCollection;
11
9
  }>;
12
10
 
11
+ const BASE_URL = "http://www.booljs.com";
12
+
13
13
  export class HttpRoute {
14
14
  public static rootPattern = ":([a-z0-9A-Z_-]{1,})";
15
15
  public static innerRootPattern = "([a-z0-9A-Z_-]{1,})";
16
16
 
17
17
  public readonly alias: string;
18
18
 
19
- private _map = new Map<keyof THttpMethods, THttpRouteModel>();
19
+ #map = new Map<THttpMethods, THttpRouteModel>();
20
+ #urlPattern: URLPattern;
21
+
22
+ constructor({ alias }: { alias: string }) {
23
+ const thinAlias = this._thinAlias(alias);
20
24
 
21
- constructor(alias: string) {
22
- this.alias = this._thinAlias(alias);
25
+ this.alias = thinAlias;
26
+ this.#urlPattern = new URLPattern({
27
+ pathname: thinAlias,
28
+ baseURL: BASE_URL
29
+ });
23
30
  }
24
31
 
25
32
  /**
@@ -28,162 +35,62 @@ export class HttpRoute {
28
35
  * @param method
29
36
  * @returns
30
37
  */
31
- public test(
32
- pathname: string,
33
- method: keyof THttpMethods
34
- ):
35
- | Readonly<{ parameters: Record<string, string>; model: THttpRouteModel }>
36
- | false
37
- | undefined {
38
+ public test({ pathname }: { pathname: string }): boolean {
38
39
  try {
39
- const model = this._map.get(method);
40
- const aliasSplitted = this.alias.split("/");
41
- const currentPathNameSplitted = this._thinAlias(pathname).split("/");
42
-
43
- if (!model) {
44
- return undefined;
45
- }
46
-
47
- // Compare splitted length
48
- if (aliasSplitted.length !== currentPathNameSplitted.length) {
49
- return undefined;
50
- }
51
-
52
- const parameters: Record<string, string> = Object();
53
- const matchingRegex = this.alias.replace(
54
- new RegExp(HttpRoute.rootPattern, "g"),
55
- HttpRoute.innerRootPattern
56
- );
57
-
58
- if (!new RegExp(matchingRegex).test(this._thinAlias(pathname))) {
59
- return undefined;
60
- }
61
-
62
- for (let index = 0; index < aliasSplitted.length; index++) {
63
- const aliasPart = aliasSplitted[index];
64
- const pathnamePart = currentPathNameSplitted[index];
65
-
66
- // Check pathmane path match a dynamic syntax, if no match => start compare equal or not
67
- if (!new RegExp(HttpRoute.rootPattern, "g").test(aliasPart)) {
68
- if (aliasPart !== pathnamePart) return undefined;
69
- } else {
70
- let isFailed = false;
71
-
72
- aliasPart.replace(
73
- new RegExp(HttpRoute.rootPattern, "g"),
74
- (match, key, offset) => {
75
- if (offset === 0) {
76
- pathnamePart.replace(
77
- new RegExp(HttpRoute.innerRootPattern, "g"),
78
- (innerMatch, innerKey, innerOffset) => {
79
- if (innerOffset === 0) {
80
- Object.assign(parameters, {
81
- [key]: innerMatch
82
- });
83
- }
84
-
85
- return innerMatch;
86
- }
87
- );
88
- }
89
-
90
- return match;
91
- }
92
- );
93
-
94
- if (isFailed) {
95
- return undefined;
96
- }
97
- }
98
-
99
- continue;
100
- }
101
-
102
- return Object.freeze({
103
- parameters: parameters,
104
- model: model
40
+ return this.#urlPattern.test({
41
+ pathname: this._thinAlias(pathname),
42
+ baseURL: BASE_URL
105
43
  });
106
- } catch (err) {
107
- console.error(err);
44
+ } catch (error) {
45
+ console.error(error);
46
+
108
47
  return false;
109
48
  }
110
49
  }
111
50
 
112
- /**
113
- *
114
- * @param pathname
115
- * @param method
116
- * @returns
117
- */
118
- public isMatch(pathname: string, method: keyof THttpMethods) {
51
+ public exec({ pathname, method }: { pathname: string; method: THttpMethods }): Readonly<{
52
+ parameters: Record<string, string | undefined>;
53
+ model: THttpRouteModel;
54
+ }> | null {
119
55
  try {
120
- const handlers = this._map.get(method);
56
+ const model = this.#map.get(method);
121
57
 
122
- if (!handlers) {
123
- return undefined;
58
+ if (!model) {
59
+ return null;
124
60
  }
125
61
 
126
- const aliasSplitted = this.alias.split("/");
127
- const currentPathNameSplitted = this._thinAlias(pathname).split("/");
62
+ const inferResult = this.#urlPattern.exec({
63
+ pathname: this._thinAlias(pathname),
64
+ baseURL: BASE_URL
65
+ });
128
66
 
129
- // Compare splitted length
130
- if (aliasSplitted.length !== currentPathNameSplitted.length) {
131
- return false;
67
+ if (!inferResult) {
68
+ return null;
132
69
  }
133
70
 
134
- const parameters = Object();
135
-
136
- for (let index = 0; index < aliasSplitted.length; index++) {
137
- const aliasPart = aliasSplitted[index];
138
- const pathnamePart = currentPathNameSplitted[index];
139
-
140
- // Check pathmane path match a dynamic syntax, if no match => start compare equal or not
141
- if (!new RegExp(HttpRoute.rootPattern, "g").test(aliasPart)) {
142
- if (aliasPart !== pathnamePart) {
143
- return false;
144
- }
145
- } else {
146
- let isFailed = false;
147
-
148
- aliasPart.replace(
149
- new RegExp(HttpRoute.rootPattern, "g"),
150
- (subString, key, value) => {
151
- if (!new RegExp(value, "g").test(pathnamePart)) {
152
- isFailed = true;
153
- } else {
154
- Object.assign(parameters, {
155
- [key]: pathnamePart
156
- });
157
- }
158
- return "";
159
- }
160
- );
161
-
162
- if (isFailed) {
163
- return false;
164
- }
165
- }
71
+ const parameters = inferResult.pathname.groups;
166
72
 
167
- continue;
168
- }
73
+ return Object.freeze({
74
+ parameters: parameters,
75
+ model: model
76
+ });
77
+ } catch (error) {
78
+ console.error(error);
169
79
 
170
- return true;
171
- } catch (err) {
172
- console.error(err);
173
- return undefined;
80
+ return null;
174
81
  }
175
82
  }
176
83
 
177
84
  /**
178
85
  *
179
- * @param handler
86
+ * @param model
180
87
  * @returns
181
88
  */
182
- public get(handler: THttpRouteModel) {
183
- const currenTHttpRouteModel = this._map.get("GET");
89
+ public get({ model }: { model: THttpRouteModel }) {
90
+ const currenTHttpRouteModel = this.#map.get("GET");
184
91
 
185
92
  if (!currenTHttpRouteModel) {
186
- this._map.set("GET", handler);
93
+ this.#map.set("GET", model);
187
94
  }
188
95
 
189
96
  return this;
@@ -191,14 +98,14 @@ export class HttpRoute {
191
98
 
192
99
  /**
193
100
  *
194
- * @param handler
101
+ * @param model
195
102
  * @returns
196
103
  */
197
- public post(handler: THttpRouteModel) {
198
- const currenTHttpRouteModel = this._map.get("POST");
104
+ public post({ model }: { model: THttpRouteModel }) {
105
+ const currenTHttpRouteModel = this.#map.get("POST");
199
106
 
200
107
  if (!currenTHttpRouteModel) {
201
- this._map.set("POST", handler);
108
+ this.#map.set("POST", model);
202
109
  }
203
110
 
204
111
  return this;
@@ -206,14 +113,14 @@ export class HttpRoute {
206
113
 
207
114
  /**
208
115
  *
209
- * @param handler
116
+ * @param model
210
117
  * @returns
211
118
  */
212
- public put(handler: THttpRouteModel) {
213
- const currenTHttpRouteModel = this._map.get("PUT");
119
+ public put({ model }: { model: THttpRouteModel }) {
120
+ const currenTHttpRouteModel = this.#map.get("PUT");
214
121
 
215
122
  if (!currenTHttpRouteModel) {
216
- this._map.set("PUT", handler);
123
+ this.#map.set("PUT", model);
217
124
  }
218
125
 
219
126
  return this;
@@ -221,14 +128,14 @@ export class HttpRoute {
221
128
 
222
129
  /**
223
130
  *
224
- * @param handler
131
+ * @param model
225
132
  * @returns
226
133
  */
227
- public delete(handler: THttpRouteModel) {
228
- const currenTHttpRouteModel = this._map.get("DELETE");
134
+ public delete({ model }: { model: THttpRouteModel }) {
135
+ const currenTHttpRouteModel = this.#map.get("DELETE");
229
136
 
230
137
  if (!currenTHttpRouteModel) {
231
- this._map.set("DELETE", handler);
138
+ this.#map.set("DELETE", model);
232
139
  }
233
140
 
234
141
  return this;
@@ -236,14 +143,14 @@ export class HttpRoute {
236
143
 
237
144
  /**
238
145
  *
239
- * @param handler
146
+ * @param model
240
147
  * @returns
241
148
  */
242
- public connect(handler: THttpRouteModel) {
243
- const currenTHttpRouteModel = this._map.get("CONNECT");
149
+ public connect({ model }: { model: THttpRouteModel }) {
150
+ const currenTHttpRouteModel = this.#map.get("CONNECT");
244
151
 
245
152
  if (!currenTHttpRouteModel) {
246
- return this._map.set("CONNECT", handler);
153
+ return this.#map.set("CONNECT", model);
247
154
  }
248
155
 
249
156
  return this;
@@ -251,14 +158,14 @@ export class HttpRoute {
251
158
 
252
159
  /**
253
160
  *
254
- * @param handler
161
+ * @param model
255
162
  * @returns
256
163
  */
257
- public options(handler: THttpRouteModel) {
258
- const currenTHttpRouteModel = this._map.get("OPTIONS");
164
+ public options({ model }: { model: THttpRouteModel }) {
165
+ const currenTHttpRouteModel = this.#map.get("OPTIONS");
259
166
 
260
167
  if (!currenTHttpRouteModel) {
261
- return this._map.set("OPTIONS", handler);
168
+ return this.#map.set("OPTIONS", model);
262
169
  }
263
170
 
264
171
  return this;
@@ -266,14 +173,14 @@ export class HttpRoute {
266
173
 
267
174
  /**
268
175
  *
269
- * @param handler
176
+ * @param model
270
177
  * @returns
271
178
  */
272
- public trace(handler: THttpRouteModel) {
273
- const currenTHttpRouteModel = this._map.get("TRACE");
179
+ public trace({ model }: { model: THttpRouteModel }) {
180
+ const currenTHttpRouteModel = this.#map.get("TRACE");
274
181
 
275
182
  if (!currenTHttpRouteModel) {
276
- return this._map.set("TRACE", handler);
183
+ return this.#map.set("TRACE", model);
277
184
  }
278
185
 
279
186
  return this;
@@ -281,14 +188,14 @@ export class HttpRoute {
281
188
 
282
189
  /**
283
190
  *
284
- * @param handler
191
+ * @param model
285
192
  * @returns
286
193
  */
287
- public patch(handler: THttpRouteModel) {
288
- const currenTHttpRouteModel = this._map.get("PATCH");
194
+ public patch({ model }: { model: THttpRouteModel }) {
195
+ const currenTHttpRouteModel = this.#map.get("PATCH");
289
196
 
290
197
  if (!currenTHttpRouteModel) {
291
- return this._map.set("PATCH", handler);
198
+ return this.#map.set("PATCH", model);
292
199
  }
293
200
 
294
201
  return this;
@@ -296,7 +203,7 @@ export class HttpRoute {
296
203
 
297
204
  /**
298
205
  *
299
- * @param handler
206
+ * @param model
300
207
  * @returns
301
208
  */
302
209
  private _thinAlias(alias: string) {
@@ -1,5 +1,3 @@
1
- "use strict";
2
-
3
1
  import HttpRoute from "./httpRoute";
4
2
 
5
3
  export class HttpRouter {
@@ -7,7 +5,7 @@ export class HttpRouter {
7
5
 
8
6
  private _routes: Map<string, HttpRoute> = new Map();
9
7
 
10
- constructor(alias: string) {
8
+ constructor({ alias }: { alias: string }) {
11
9
  this.alias = this._thinAlias(alias);
12
10
  }
13
11
 
@@ -19,7 +17,7 @@ export class HttpRouter {
19
17
  public route(alias: string) {
20
18
  const thinAlias = this._thinAlias(`${this.alias}/${alias}`);
21
19
  const route = this._routes.get(thinAlias);
22
- const newRoute = !route ? new HttpRoute(`${this.alias}/${alias}`) : route;
20
+ const newRoute = !route ? new HttpRoute({ alias: `${this.alias}/${alias}` }) : route;
23
21
 
24
22
  if (!route) {
25
23
  this._routes.set(thinAlias, newRoute);
@@ -1,4 +1,5 @@
1
1
  import type { THttpMethods } from "../http";
2
+ import type { THttpRouteModel } from "./httpRoute";
2
3
  import type { HttpRouter } from "./httpRouter";
3
4
 
4
5
  export class HttpRouterGroup {
@@ -18,23 +19,32 @@ export class HttpRouterGroup {
18
19
 
19
20
  /**
20
21
  *
21
- * @param pathame
22
+ * @param pathname
22
23
  * @param method
23
24
  * @returns
24
25
  */
25
- public find(pathame: string, method: keyof THttpMethods) {
26
+ public find({ pathname, method }: { pathname: string; method: THttpMethods }): Readonly<{
27
+ parameters: Record<string, string | undefined>;
28
+ model: THttpRouteModel;
29
+ }> | null {
26
30
  for (const router of this._routers.values()) {
27
31
  for (const route of router.routes.values()) {
28
- const result = route.test(pathame, method);
32
+ const testResult = route.test({ pathname });
29
33
 
30
- if (!result) {
34
+ if (!testResult) {
31
35
  continue;
32
36
  }
33
37
 
34
- return result;
38
+ const execResult = route.exec({ pathname, method });
39
+
40
+ if (!execResult) {
41
+ continue;
42
+ }
43
+
44
+ return execResult;
35
45
  }
36
46
  }
37
47
 
38
- return undefined;
48
+ return null;
39
49
  }
40
50
  }
@@ -30,12 +30,15 @@ export const httpClientErrors = Object.freeze({
30
30
  451: "UNAVAILABLE_FOR_LEGAL_REASONS"
31
31
  });
32
32
 
33
- export class HttpClientError<T extends keyof typeof httpClientErrors = keyof typeof httpClientErrors, K = any> extends Error {
33
+ export class HttpClientError<
34
+ T extends keyof typeof httpClientErrors = keyof typeof httpClientErrors,
35
+ K = unknown
36
+ > extends Error {
34
37
  public readonly httpCode: T;
35
38
  public readonly message: (typeof httpClientErrors)[T] | string;
36
- public readonly data: K;
39
+ public readonly data: K | undefined;
37
40
 
38
- constructor({ httpCode, data, message }: { httpCode: T; data: K; message?: string }) {
41
+ constructor({ httpCode, data, message }: { httpCode: T; data?: K; message?: string }) {
39
42
  super();
40
43
 
41
44
  this.httpCode = httpCode;
package/src/http/index.ts CHANGED
@@ -1,17 +1,31 @@
1
1
  import { HttpClientError } from "./clientError";
2
2
  import { HttpServerError } from "./serverError";
3
3
 
4
- export type THttpMethods = {
5
- GET: "GET";
6
- HEAD: "HEAD";
7
- POST: "POST";
8
- PUT: "PUT";
9
- DELETE: "DELETE";
10
- CONNECT: "CONNECT";
11
- OPTIONS: "OPTIONS";
12
- TRACE: "TRACE";
13
- PATCH: "PATCH";
14
- };
4
+ export type THttpMethods =
5
+ | "GET"
6
+ | "HEAD"
7
+ | "POST"
8
+ | "PUT"
9
+ | "DELETE"
10
+ | "CONNECT"
11
+ | "OPTIONS"
12
+ | "TRACE"
13
+ | "PATCH";
14
+
15
+ export const httpMethods: Array<THttpMethods> = [
16
+ "GET",
17
+ "HEAD",
18
+ "POST",
19
+ "PUT",
20
+ "DELETE",
21
+ "CONNECT",
22
+ "OPTIONS",
23
+ "TRACE",
24
+ "PATCH"
25
+ ];
26
+
27
+ export const httpMethodsStandardization = (method: string): method is THttpMethods =>
28
+ !!httpMethods.find((httpMethod) => httpMethod === method);
15
29
 
16
30
  export const jsonErrorInfer = (data: any, headers: Headers = new Headers()) => {
17
31
  headers.set("Content-Type", "application/json");
@@ -59,3 +73,4 @@ export const jsonErrorInfer = (data: any, headers: Headers = new Headers()) => {
59
73
 
60
74
  export * from "./clientError";
61
75
  export * from "./serverError";
76
+
@@ -12,12 +12,15 @@ export const httpServerErrors = Object.freeze({
12
12
  511: "NETWORK_AUTHENTICATION_REQUIRED"
13
13
  });
14
14
 
15
- export class HttpServerError<T extends keyof typeof httpServerErrors = keyof typeof httpServerErrors, K = any> extends Error {
15
+ export class HttpServerError<
16
+ T extends keyof typeof httpServerErrors = keyof typeof httpServerErrors,
17
+ K = any
18
+ > extends Error {
16
19
  public readonly httpCode: T;
17
20
  public readonly message: (typeof httpServerErrors)[T] | string;
18
- public readonly data: K;
21
+ public readonly data: K | undefined;
19
22
 
20
- constructor({ httpCode, data, message }: { httpCode: T; data: K; message?: string }) {
23
+ constructor({ httpCode, data, message }: { httpCode: T; data?: K; message?: string }) {
21
24
  super();
22
25
 
23
26
  this.httpCode = httpCode;