elysia 0.2.0 → 0.2.2

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.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  /// <reference types="bun-types" />
2
2
  import type { Serve, Server } from 'bun';
3
- import { Router } from './router';
4
3
  import { SCHEMA, DEFS } from './utils';
5
4
  import type { Context } from './context';
6
5
  import type { Handler, BeforeRequestHandler, TypedRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, InternalRoute, BodyParser, ErrorHandler, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, LifeCycleStore, VoidLifeCycle, AfterRequestHandler, MergeIfNotNull, IsAny, OverwritableTypeRoute, MergeSchema, ListenCallback, NoReturnHandler, ElysiaRoute, MaybePromise, IsNever } from './types';
@@ -107,8 +106,8 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
107
106
  schema: Instance['schema'];
108
107
  }>;
109
108
  }
110
- export { Elysia, Router };
109
+ export { Elysia };
111
110
  export { Type as t } from '@sinclair/typebox';
112
- export { SCHEMA, DEFS, getPath, createValidationError, getSchemaValidator } from './utils';
111
+ export { SCHEMA, DEFS, createValidationError, getSchemaValidator, mergeDeep, mergeHook, mergeObjectArray, mapPathnameAndQueryRegEx, mapQuery } from './utils';
113
112
  export type { Context, PreContext } from './context';
114
113
  export type { Handler, RegisteredHook, BeforeRequestHandler, TypedRoute, OverwritableTypeRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, ComposedHandler, InternalRoute, BodyParser, ErrorHandler, ErrorCode, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, AfterRequestHandler, HookHandler, TypedSchemaToRoute, UnwrapSchema, LifeCycleStore, VoidLifeCycle, SchemaValidator, ElysiaRoute, ExtractPath, IsPathParameter, IsAny, IsNever, UnknownFallback, WithArray, ObjectValues, PickInOrder, MaybePromise, MergeIfNotNull } from './types';
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { Router } from './router';
1
+ import { Raikiri } from 'raikiri';
2
2
  import { mapResponse, mapEarlyResponse } from './handler';
3
- import { mapQuery, clone, mergeHook, mergeDeep, createValidationError, getSchemaValidator, SCHEMA, DEFS, getResponseSchemaValidator } from './utils';
3
+ import { mapQuery, clone, mergeHook, mergeDeep, createValidationError, getSchemaValidator, SCHEMA, DEFS, getResponseSchemaValidator, mapPathnameAndQueryRegEx } from './utils';
4
4
  import { registerSchemaPath } from './schema';
5
5
  import { mapErrorCode, mapErrorStatus } from './error';
6
+ const ASYNC_FN = 'AsyncFunction';
6
7
  export default class Elysia {
7
8
  constructor(config = {}) {
8
9
  this.store = {
@@ -22,7 +23,7 @@ export default class Elysia {
22
23
  };
23
24
  this.server = null;
24
25
  this.$schema = null;
25
- this.router = new Router();
26
+ this.router = new Raikiri();
26
27
  this.fallbackRoute = {};
27
28
  this.routes = [];
28
29
  this.lazyLoadModules = [];
@@ -74,17 +75,17 @@ export default class Elysia {
74
75
  hooks: mergeHook(clone(this.event), hook),
75
76
  validator
76
77
  };
77
- this.router.register(path)[method] = {
78
+ const mainHandler = {
78
79
  handle: handler,
79
80
  hooks: mergeHook(clone(this.event), hook),
80
81
  validator
81
82
  };
83
+ this.router.add(method, path, mainHandler);
82
84
  if (!this.config.strictPath && path !== '/')
83
85
  if (path.endsWith('/'))
84
- this.router.register(path.substring(0, path.length - 1))[method] = this.router.register(path)[method];
86
+ this.router.add(method, path.substring(0, path.length - 1), mainHandler);
85
87
  else
86
- this.router.register(`${path}/`)[method] =
87
- this.router.register(path)[method];
88
+ this.router.add(method, `${path}/`, mainHandler);
88
89
  }
89
90
  onStart(handler) {
90
91
  this.event.start.push(handler);
@@ -280,34 +281,38 @@ export default class Elysia {
280
281
  context.request = request;
281
282
  context.set = set;
282
283
  context.store = this.store;
284
+ context.query = {};
283
285
  }
284
286
  else {
285
287
  context = {
286
288
  set,
287
289
  store: this.store,
288
- request
290
+ request,
291
+ query: {}
289
292
  };
290
293
  }
291
294
  try {
292
- for (let i = 0; i < this.event.request.length; i++) {
293
- const onRequest = this.event.request[i];
294
- let response = onRequest(context);
295
- if (response instanceof Promise)
296
- response = await response;
297
- response = mapEarlyResponse(response, set);
298
- if (response)
299
- return response;
300
- }
301
- const index = request.url.indexOf('?', 10);
302
- const route = this.router.find(request.url, index);
295
+ const event = this.event;
296
+ if (event.request.length)
297
+ for (let i = 0; i < event.request.length; i++) {
298
+ const onRequest = event.request[i];
299
+ let response = onRequest(context);
300
+ if (onRequest.constructor.name === ASYNC_FN)
301
+ response = await response;
302
+ response = mapEarlyResponse(response, set);
303
+ if (response)
304
+ return response;
305
+ }
306
+ const fracture = request.url.match(mapPathnameAndQueryRegEx);
307
+ if (!fracture)
308
+ throw new Error('NOT_FOUND');
309
+ const route = this.router.match(request.method, fracture[1]) ||
310
+ this.router.match('ALL', fracture[1]);
303
311
  if (!route)
304
312
  throw new Error('NOT_FOUND');
305
- const handler = route.store[request.method] ||
306
- route.store.ALL ||
307
- this.fallbackRoute[request.method];
313
+ const handler = route.store || this.fallbackRoute[request.method];
308
314
  if (!handler)
309
315
  throw new Error('NOT_FOUND');
310
- const hooks = handler.hooks;
311
316
  let body;
312
317
  if (request.method !== 'GET') {
313
318
  let contentType = request.headers.get('content-type');
@@ -315,15 +320,17 @@ export default class Elysia {
315
320
  const index = contentType.indexOf(';');
316
321
  if (index !== -1)
317
322
  contentType = contentType.slice(0, index);
318
- for (let i = 0; i < this.event.parse.length; i++) {
319
- let temp = this.event.parse[i](context, contentType);
320
- if (temp instanceof Promise)
321
- temp = await temp;
322
- if (temp) {
323
- body = temp;
324
- break;
323
+ if (event.parse.length)
324
+ for (let i = 0; i < event.parse.length; i++) {
325
+ const fn = event.parse[i];
326
+ let temp = fn(context, contentType);
327
+ if (fn.constructor.name === ASYNC_FN)
328
+ temp = await temp;
329
+ if (temp) {
330
+ body = temp;
331
+ break;
332
+ }
325
333
  }
326
- }
327
334
  if (body === undefined) {
328
335
  switch (contentType) {
329
336
  case 'application/json':
@@ -333,7 +340,7 @@ export default class Elysia {
333
340
  body = await request.text();
334
341
  break;
335
342
  case 'application/x-www-form-urlencoded':
336
- body = mapQuery(await request.text(), null);
343
+ body = mapQuery(await request.text());
337
344
  break;
338
345
  }
339
346
  }
@@ -341,12 +348,16 @@ export default class Elysia {
341
348
  }
342
349
  context.body = body;
343
350
  context.params = route?.params || {};
344
- context.query = mapQuery(request.url, index);
345
- for (let i = 0; i < hooks.transform.length; i++) {
346
- const operation = hooks.transform[i](context);
347
- if (operation instanceof Promise)
348
- await operation;
349
- }
351
+ if (fracture[2])
352
+ context.query = mapQuery(fracture[2]);
353
+ const hooks = handler.hooks;
354
+ if (hooks.transform.length)
355
+ for (let i = 0; i < hooks.transform.length; i++) {
356
+ const fn = hooks.transform[i];
357
+ const operation = fn(context);
358
+ if (fn.constructor.name === ASYNC_FN)
359
+ await operation;
360
+ }
350
361
  if (handler.validator) {
351
362
  const validator = handler.validator;
352
363
  if (validator.headers) {
@@ -363,36 +374,41 @@ export default class Elysia {
363
374
  if (validator.body?.Check(body) === false)
364
375
  throw createValidationError('body', validator.body, body);
365
376
  }
366
- for (let i = 0; i < hooks.beforeHandle.length; i++) {
367
- let response = hooks.beforeHandle[i](context);
368
- if (response instanceof Promise)
369
- response = await response;
370
- if (response !== null && response !== undefined) {
371
- for (let i = 0; i < hooks.afterHandle.length; i++) {
372
- let newResponse = hooks.afterHandle[i](context, response);
373
- if (newResponse instanceof Promise)
374
- newResponse = await newResponse;
375
- if (newResponse)
376
- response = newResponse;
377
+ if (hooks.beforeHandle.length)
378
+ for (let i = 0; i < hooks.beforeHandle.length; i++) {
379
+ const fn = hooks.beforeHandle[i];
380
+ let response = fn(context);
381
+ if (fn.constructor.name === ASYNC_FN)
382
+ response = await response;
383
+ if (response !== null && response !== undefined) {
384
+ for (let i = 0; i < hooks.afterHandle.length; i++) {
385
+ const fn = hooks.afterHandle[i];
386
+ let newResponse = fn(context, response);
387
+ if (fn.constructor.name === ASYNC_FN)
388
+ newResponse = await newResponse;
389
+ if (newResponse)
390
+ response = newResponse;
391
+ }
392
+ const result = mapEarlyResponse(response, context.set);
393
+ if (result)
394
+ return result;
377
395
  }
378
- const result = mapEarlyResponse(response, context.set);
379
- if (result)
380
- return result;
381
396
  }
382
- }
383
397
  let response = handler.handle(context);
384
398
  if (response instanceof Promise)
385
399
  response = await response;
386
400
  if (handler.validator?.response?.Check(response) === false)
387
401
  throw createValidationError('response', handler.validator.response, response);
388
- for (let i = 0; i < hooks.afterHandle.length; i++) {
389
- let newResponse = hooks.afterHandle[i](context, response);
390
- if (newResponse instanceof Promise)
391
- newResponse = await newResponse;
392
- const result = mapEarlyResponse(newResponse, context.set);
393
- if (result)
394
- return result;
395
- }
402
+ if (hooks.afterHandle.length)
403
+ for (let i = 0; i < hooks.afterHandle.length; i++) {
404
+ const afterHandle = hooks.afterHandle[i];
405
+ let newResponse = afterHandle(context, response);
406
+ if (afterHandle.constructor.name === ASYNC_FN)
407
+ newResponse = await newResponse;
408
+ const result = mapEarlyResponse(newResponse, context.set);
409
+ if (result)
410
+ return result;
411
+ }
396
412
  return mapResponse(response, context.set);
397
413
  }
398
414
  catch (error) {
@@ -400,8 +416,7 @@ export default class Elysia {
400
416
  }
401
417
  }
402
418
  async handleError(error, set = {
403
- headers: {},
404
- status: undefined
419
+ headers: {}
405
420
  }) {
406
421
  for (let i = 0; i < this.event.error.length; i++) {
407
422
  let response = this.event.error[i]({
@@ -422,12 +437,12 @@ export default class Elysia {
422
437
  listen(options, callback) {
423
438
  if (!Bun)
424
439
  throw new Error('Bun to run');
425
- const fetch = this.handle.bind(this);
426
440
  if (typeof options === 'string') {
427
441
  options = +options;
428
442
  if (Number.isNaN(options))
429
443
  throw new Error('Port must be a numeric value');
430
444
  }
445
+ const fetch = this.handle.bind(this);
431
446
  const serve = typeof options === 'object'
432
447
  ? {
433
448
  ...this.config.serve,
@@ -452,7 +467,8 @@ export default class Elysia {
452
467
  if (callback)
453
468
  callback(this.server);
454
469
  Promise.all(this.lazyLoadModules).then(() => {
455
- Bun.gc(true);
470
+ if (!this.server.pendingRequests)
471
+ Bun.gc(true);
456
472
  });
457
473
  return this;
458
474
  }
@@ -467,6 +483,6 @@ export default class Elysia {
467
483
  return this;
468
484
  }
469
485
  }
470
- export { Elysia, Router };
486
+ export { Elysia };
471
487
  export { Type as t } from '@sinclair/typebox';
472
- export { SCHEMA, DEFS, getPath, createValidationError, getSchemaValidator } from './utils';
488
+ export { SCHEMA, DEFS, createValidationError, getSchemaValidator, mergeDeep, mergeHook, mergeObjectArray, mapPathnameAndQueryRegEx, mapQuery } from './utils';
package/dist/utils.d.ts CHANGED
@@ -6,8 +6,8 @@ export declare const DEFS: unique symbol;
6
6
  export declare const mergeObjectArray: <T>(a: T | T[], b: T | T[]) => T[];
7
7
  export declare const mergeHook: (a: LocalHook<any> | LifeCycleStore<any>, b: LocalHook<any>) => RegisteredHook<any>;
8
8
  export declare const clone: <T extends Object | any[] = Object | any[]>(value: T) => T;
9
- export declare const getPath: (url: string, queryIndex?: number) => string;
10
- export declare const mapQuery: (url: string, queryIndex?: number | null) => Record<string, string>;
9
+ export declare const mapPathnameAndQueryRegEx: RegExp;
10
+ export declare const mapQuery: (url: string) => Record<string, string>;
11
11
  export declare const mergeDeep: <A extends Object = Object, B extends Object = Object>(target: A, source: B) => DeepMergeTwoTypes<A, B>;
12
12
  export declare const createValidationError: (type: string, validator: TypeCheck<any>, value: any) => Error;
13
13
  export declare const getSchemaValidator: (s: TSchema | string | undefined, models: Record<string, TSchema>, additionalProperties?: boolean) => TypeCheck<TSchema> | undefined;
package/dist/utils.js CHANGED
@@ -26,46 +26,19 @@ export const mergeHook = (a, b) => {
26
26
  };
27
27
  };
28
28
  export const clone = (value) => [value][0];
29
- export const getPath = (url, queryIndex = url.indexOf('?')) => {
30
- if (queryIndex === -1) {
31
- const fragmentIndex = url.indexOf('#');
32
- if (fragmentIndex !== -1)
33
- queryIndex = fragmentIndex;
34
- else
35
- queryIndex = url.length;
36
- }
37
- return url.substring(url.indexOf('/', 9), queryIndex);
38
- };
39
- export const mapQuery = (url, queryIndex = url.indexOf('?')) => {
40
- if (queryIndex === -1)
41
- return {};
42
- const query = {};
43
- if (queryIndex)
44
- url = url.slice(queryIndex);
45
- else
46
- url = ';' + url;
47
- while (true) {
48
- const sep = url.indexOf('&', 4);
49
- if (sep === -1) {
50
- const equal = url.indexOf('=');
51
- let value = url.slice(equal + 1);
52
- const hashIndex = value.indexOf('#');
53
- if (hashIndex !== -1)
54
- value = value.slice(0, hashIndex);
55
- if (value.includes('%'))
56
- value = decodeURI(value);
57
- query[url.slice(1, equal)] = value;
58
- break;
59
- }
60
- const path = url.slice(0, sep);
61
- const equal = path.indexOf('=');
62
- let value = path.slice(equal + 1);
29
+ export const mapPathnameAndQueryRegEx = /:\/\/[^/]+([^#?]+)(?:\?([^#]+))?/;
30
+ export const mapQuery = (url) => {
31
+ const mapped = {};
32
+ const paths = url.split('&');
33
+ for (let i = 0; i < paths.length; i++) {
34
+ const part = paths[i];
35
+ const index = part.indexOf('=');
36
+ let value = part.slice(index + 1);
63
37
  if (value.includes('%'))
64
- value = decodeURI(value);
65
- query[path.slice(1, equal)] = value;
66
- url = url.slice(sep);
38
+ value = decodeURIComponent(value);
39
+ mapped[part.slice(0, index)] = value;
67
40
  }
68
- return query;
41
+ return mapped;
69
42
  };
70
43
  const isObject = (item) => item && typeof item === 'object' && !Array.isArray(item);
71
44
  export const mergeDeep = (target, source) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elysia",
3
3
  "description": "Fast, and friendly Bun web framework",
4
- "version": "0.2.0",
4
+ "version": "0.2.2",
5
5
  "author": {
6
6
  "name": "saltyAom",
7
7
  "url": "https://github.com/SaltyAom",
@@ -35,8 +35,9 @@
35
35
  "release": "npm run build && npm run test && npm publish"
36
36
  },
37
37
  "dependencies": {
38
- "@sinclair/typebox": "0.25.21",
39
- "openapi-types": "^12.1.0"
38
+ "@sinclair/typebox": "^0.25.21",
39
+ "openapi-types": "^12.1.0",
40
+ "raikiri": "0.0.0-beta.3"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/node": "^18.11.18",
@@ -47,4 +48,4 @@
47
48
  "rimraf": "^3.0.2",
48
49
  "typescript": "^4.9.4"
49
50
  }
50
- }
51
+ }
package/dist/router.d.ts DELETED
@@ -1,26 +0,0 @@
1
- import type { ComposedHandler } from '../src';
2
- export interface FindResult {
3
- store: Partial<{
4
- [k in string]: ComposedHandler;
5
- }> & Partial<{
6
- wildcardStore?: Map<number, any> | null;
7
- }>;
8
- params: Record<string, any>;
9
- }
10
- export interface ParametricNode {
11
- paramName: string;
12
- store: Record<string, any> | null;
13
- staticChild: Node | null;
14
- }
15
- export interface Node {
16
- pathPart: string;
17
- store: Record<string, any> | null;
18
- staticChildren: Map<any, any> | null;
19
- parametricChild: ParametricNode | null;
20
- wildcardStore: Map<number, any> | null;
21
- }
22
- export declare class Router {
23
- private _root;
24
- register(path: string): FindResult['store'];
25
- find(url: string, queryIndex: number): FindResult | null;
26
- }
package/dist/router.js DELETED
@@ -1,201 +0,0 @@
1
- import { getPath } from './utils';
2
- function createNode(pathPart, staticChildren) {
3
- return {
4
- pathPart,
5
- store: null,
6
- staticChildren: staticChildren !== undefined
7
- ? new Map(staticChildren.map((child) => [
8
- child.pathPart.charCodeAt(0),
9
- child
10
- ]))
11
- : null,
12
- parametricChild: null,
13
- wildcardStore: null
14
- };
15
- }
16
- function cloneNode(node, newPathPart) {
17
- return {
18
- pathPart: newPathPart,
19
- store: node.store,
20
- staticChildren: node.staticChildren,
21
- parametricChild: node.parametricChild,
22
- wildcardStore: node.wildcardStore
23
- };
24
- }
25
- function createParametricNode(paramName) {
26
- return {
27
- paramName,
28
- store: null,
29
- staticChild: null
30
- };
31
- }
32
- export class Router {
33
- constructor() {
34
- this._root = createNode('/');
35
- }
36
- register(path) {
37
- if (typeof path !== 'string')
38
- throw new TypeError('Route path must be a string');
39
- if (path === '' || path[0] !== '/')
40
- throw new Error(`Invalid route: ${path}\nRoute path must begin with a "/"`);
41
- const endsWithWildcard = path.endsWith('*');
42
- if (endsWithWildcard)
43
- path = path.slice(0, -1);
44
- const staticParts = path.split(/:.+?(?=\/|$)/);
45
- const paramParts = path.match(/:.+?(?=\/|$)/g) || [];
46
- if (staticParts[staticParts.length - 1] === '')
47
- staticParts.pop();
48
- let node = this._root;
49
- let paramPartsIndex = 0;
50
- for (let i = 0; i < staticParts.length; ++i) {
51
- let pathPart = staticParts[i];
52
- if (i > 0) {
53
- const paramName = paramParts[paramPartsIndex++].slice(1);
54
- if (node.parametricChild === null)
55
- node.parametricChild = createParametricNode(paramName);
56
- else if (node.parametricChild.paramName !== paramName)
57
- throw new Error(`Cannot create route "${path}" with parameter "${paramName}" ` +
58
- 'because a route already exists with a different parameter name ' +
59
- `("${node.parametricChild.paramName}") in the same location`);
60
- const { parametricChild } = node;
61
- if (parametricChild.staticChild === null) {
62
- node = parametricChild.staticChild = createNode(pathPart);
63
- continue;
64
- }
65
- node = parametricChild.staticChild;
66
- }
67
- for (let j = 0;;) {
68
- if (j === pathPart.length) {
69
- if (j < node.pathPart.length) {
70
- const childNode = cloneNode(node, node.pathPart.slice(j));
71
- Object.assign(node, createNode(pathPart, [childNode]));
72
- }
73
- break;
74
- }
75
- if (j === node.pathPart.length) {
76
- if (node.staticChildren === null)
77
- node.staticChildren = new Map();
78
- else if (node.staticChildren.has(pathPart.charCodeAt(j))) {
79
- node = node.staticChildren.get(pathPart.charCodeAt(j));
80
- pathPart = pathPart.slice(j);
81
- j = 0;
82
- continue;
83
- }
84
- const childNode = createNode(pathPart.slice(j));
85
- node.staticChildren.set(pathPart.charCodeAt(j), childNode);
86
- node = childNode;
87
- break;
88
- }
89
- if (pathPart[j] !== node.pathPart[j]) {
90
- const existingChild = cloneNode(node, node.pathPart.slice(j));
91
- const newChild = createNode(pathPart.slice(j));
92
- Object.assign(node, createNode(node.pathPart.slice(0, j), [
93
- existingChild,
94
- newChild
95
- ]));
96
- node = newChild;
97
- break;
98
- }
99
- ++j;
100
- }
101
- }
102
- if (paramPartsIndex < paramParts.length) {
103
- const param = paramParts[paramPartsIndex];
104
- const paramName = param.slice(1);
105
- if (node.parametricChild === null)
106
- node.parametricChild = createParametricNode(paramName);
107
- else if (node.parametricChild.paramName !== paramName)
108
- throw new Error(`Cannot create route "${path}" with parameter "${paramName}" ` +
109
- 'because a route already exists with a different parameter name ' +
110
- `("${node.parametricChild.paramName}") in the same location`);
111
- if (node.parametricChild.store === null)
112
- node.parametricChild.store = Object.create(null);
113
- return node.parametricChild.store;
114
- }
115
- if (endsWithWildcard) {
116
- if (node.wildcardStore === null)
117
- node.wildcardStore = Object.create(null);
118
- return node.wildcardStore;
119
- }
120
- if (node.store === null)
121
- node.store = Object.create(null);
122
- return node.store;
123
- }
124
- find(url, queryIndex) {
125
- url = getPath(url, queryIndex);
126
- return matchRoute(url, url.length, this._root, 0);
127
- }
128
- }
129
- function matchRoute(url, urlLength, node, startIndex) {
130
- const pathPart = node.pathPart;
131
- const pathPartEndIndex = startIndex + pathPart.length;
132
- if (pathPart.length > 1) {
133
- if (pathPartEndIndex > urlLength)
134
- return null;
135
- if (pathPart.length < 15)
136
- for (let i = 1, j = startIndex + 1; i < pathPart.length; ++i, ++j) {
137
- if (pathPart[i] !== url[j]) {
138
- return null;
139
- }
140
- }
141
- else if (url.slice(startIndex, pathPartEndIndex) !== pathPart)
142
- return null;
143
- }
144
- if (pathPartEndIndex === urlLength) {
145
- if (node.store)
146
- return {
147
- store: node.store,
148
- params: {}
149
- };
150
- if (node.wildcardStore)
151
- return {
152
- store: node.wildcardStore,
153
- params: { '*': '' }
154
- };
155
- return null;
156
- }
157
- if (node.staticChildren) {
158
- const staticChild = node.staticChildren.get(url.charCodeAt(pathPartEndIndex));
159
- if (staticChild !== undefined) {
160
- const route = matchRoute(url, urlLength, staticChild, pathPartEndIndex);
161
- if (route)
162
- return route;
163
- }
164
- }
165
- if (node.parametricChild) {
166
- const slashIndex = url.indexOf('/', pathPartEndIndex);
167
- if (slashIndex !== pathPartEndIndex) {
168
- if (slashIndex === -1 || slashIndex >= urlLength) {
169
- if (node.parametricChild.store) {
170
- const params = {};
171
- let paramData = url.slice(pathPartEndIndex, urlLength);
172
- if (paramData.includes('%'))
173
- paramData = decodeURI(paramData);
174
- params[node.parametricChild.paramName] = paramData;
175
- return {
176
- store: node.parametricChild.store,
177
- params
178
- };
179
- }
180
- }
181
- else if (node.parametricChild.staticChild) {
182
- const route = matchRoute(url, urlLength, node.parametricChild.staticChild, slashIndex);
183
- if (route) {
184
- let paramData = url.slice(pathPartEndIndex, slashIndex);
185
- if (paramData.includes('%'))
186
- paramData = decodeURI(paramData);
187
- route.params[node.parametricChild.paramName] = paramData;
188
- return route;
189
- }
190
- }
191
- }
192
- }
193
- if (node.wildcardStore)
194
- return {
195
- store: node.wildcardStore,
196
- params: {
197
- '*': url.slice(pathPartEndIndex, urlLength)
198
- }
199
- };
200
- return null;
201
- }