@marianmeres/simple-router 1.9.2 → 2.0.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 CHANGED
@@ -40,6 +40,7 @@ Route segments:
40
40
  - `[name(regex)]` matches if `regex.test(segment)` is truthy
41
41
  - `exact?` or `[name]?` marks segment as optional
42
42
  - `[...name]` matches "rest segments"
43
+ - `*` matches zero or more following segments
43
44
 
44
45
  Few notes on segments separators (which is slash `/` by default):
45
46
  - multiple ones are always normalized to single,
@@ -68,8 +69,11 @@ Few notes on segments separators (which is slash `/` by default):
68
69
  | `/foo/[id([0-9]+)]/[bar]` | `/foo/bar/baz` | `null` |
69
70
  | `/foo/[([0-9]+)]` | `/foo/123` | `null` (missing name before regex) |
70
71
  | `/foo/[bar]?` | `/foo` | `{}` |
71
- | `/foo/[bar]?` | `/foo/bar` | `{ bar: 'bar' }` |
72
- | `/foo/[bar]?/baz` | `/foo/bar/baz` | `{ bar: 'bar' }` |
73
- | `/[...path]/[file]` | `/foo/bar/baz.js` | `{ path': 'foo/bar', file: 'baz.js' }`|
72
+ | `/foo/[bar]?` | `/foo/bar` | `{ bar: "bar" }` |
73
+ | `/foo/[bar]?/baz` | `/foo/bar/baz` | `{ bar: "bar" }` |
74
+ | `/[...path]/[file]` | `/foo/bar/baz.js` | `{ path: "foo/bar", file: "baz.js" }`|
75
+ | `/foo/*` | `/foo/bar/baz.js` | `{}` |
76
+ | `/[foo]/*` | `/foo/bar` | `{ foo: "foo" }` |
77
+ | `/*` | `/foo/bar` | `{}` |
74
78
  See [tests](tests) or [examples](examples) for more.
75
79
 
package/dist/index.cjs CHANGED
@@ -3,6 +3,7 @@
3
3
  class SimpleRoute {
4
4
  route;
5
5
  static SPLITTER = '/';
6
+ static WILDCARD = '*';
6
7
  _parsed;
7
8
  constructor(route) {
8
9
  this.route = route;
@@ -25,7 +26,8 @@ class SimpleRoute {
25
26
  }
26
27
  static _parse(route) {
27
28
  let wasSpread = false;
28
- return SimpleRoute._sanitizeAndSplit(route).reduce((memo, segment) => {
29
+ let wasWildcard = false;
30
+ return SimpleRoute._sanitizeAndSplit(route).reduce((memo, segment, idx, all) => {
29
31
  let name = null;
30
32
  // if optional, remove trailing '?' marker
31
33
  let isOptional = segment.endsWith('?');
@@ -43,17 +45,30 @@ class SimpleRoute {
43
45
  segment = '[' + segment.slice(4);
44
46
  }
45
47
  let test = new RegExp('^' + SimpleRoute._escapeRegExp(segment) + '$');
46
- // starting with at least one word char within brackets...
47
- let m = segment.match(/^\[(\w.*)]$/);
48
- if (m) {
49
- name = m[1];
50
- test = /.+/;
51
- // id([0-9]+)
52
- let m2 = m[1].match(/^(\w.*)\((.+)\)$/);
53
- if (m2) {
54
- name = m2[1];
55
- test = new RegExp('^' + m2[2] + '$');
48
+ // catch all wildcard
49
+ if (segment === SimpleRoute.WILDCARD) {
50
+ if (idx < all.length - 1) {
51
+ throw new Error(`Wildcard '${SimpleRoute.WILDCARD}' can be used only as a last segment`);
56
52
  }
53
+ wasWildcard = true;
54
+ }
55
+ else {
56
+ // starting with at least one word char within brackets...
57
+ let m = segment.match(/^\[(\w.*)]$/);
58
+ if (m) {
59
+ name = m[1];
60
+ test = /.+/;
61
+ // id([0-9]+)
62
+ let m2 = m[1].match(/^(\w.*)\((.+)\)$/);
63
+ if (m2) {
64
+ name = m2[1];
65
+ test = new RegExp('^' + m2[2] + '$');
66
+ }
67
+ }
68
+ }
69
+ if (wasWildcard) {
70
+ isOptional = true;
71
+ test = /.*/;
57
72
  }
58
73
  memo.push({ segment, name, test, isOptional, isSpread });
59
74
  return memo;
@@ -105,6 +120,11 @@ class SimpleRoute {
105
120
  });
106
121
  segments = newSegments;
107
122
  }
123
+ // return early no-op special case: first segment is a wildcard
124
+ // (no need to process further)
125
+ if (this._parsed?.[0]?.segment === SimpleRoute.WILDCARD) {
126
+ return matched;
127
+ }
108
128
  // minimum required (not optional) segments length
109
129
  const reqLen = this._parsed.reduce((memo, p, idx, arr) => {
110
130
  const next = arr[idx + 1];
@@ -126,6 +146,9 @@ class SimpleRoute {
126
146
  if (p.name) {
127
147
  matched[decodeURIComponent(p.name)] = decodeURIComponent(s);
128
148
  }
149
+ if (p.segment === SimpleRoute.WILDCARD) {
150
+ break;
151
+ }
129
152
  }
130
153
  return matched;
131
154
  }
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  class SimpleRoute {
2
2
  route;
3
3
  static SPLITTER = '/';
4
+ static WILDCARD = '*';
4
5
  _parsed;
5
6
  constructor(route) {
6
7
  this.route = route;
@@ -23,7 +24,8 @@ class SimpleRoute {
23
24
  }
24
25
  static _parse(route) {
25
26
  let wasSpread = false;
26
- return SimpleRoute._sanitizeAndSplit(route).reduce((memo, segment) => {
27
+ let wasWildcard = false;
28
+ return SimpleRoute._sanitizeAndSplit(route).reduce((memo, segment, idx, all) => {
27
29
  let name = null;
28
30
  // if optional, remove trailing '?' marker
29
31
  let isOptional = segment.endsWith('?');
@@ -41,17 +43,30 @@ class SimpleRoute {
41
43
  segment = '[' + segment.slice(4);
42
44
  }
43
45
  let test = new RegExp('^' + SimpleRoute._escapeRegExp(segment) + '$');
44
- // starting with at least one word char within brackets...
45
- let m = segment.match(/^\[(\w.*)]$/);
46
- if (m) {
47
- name = m[1];
48
- test = /.+/;
49
- // id([0-9]+)
50
- let m2 = m[1].match(/^(\w.*)\((.+)\)$/);
51
- if (m2) {
52
- name = m2[1];
53
- test = new RegExp('^' + m2[2] + '$');
46
+ // catch all wildcard
47
+ if (segment === SimpleRoute.WILDCARD) {
48
+ if (idx < all.length - 1) {
49
+ throw new Error(`Wildcard '${SimpleRoute.WILDCARD}' can be used only as a last segment`);
54
50
  }
51
+ wasWildcard = true;
52
+ }
53
+ else {
54
+ // starting with at least one word char within brackets...
55
+ let m = segment.match(/^\[(\w.*)]$/);
56
+ if (m) {
57
+ name = m[1];
58
+ test = /.+/;
59
+ // id([0-9]+)
60
+ let m2 = m[1].match(/^(\w.*)\((.+)\)$/);
61
+ if (m2) {
62
+ name = m2[1];
63
+ test = new RegExp('^' + m2[2] + '$');
64
+ }
65
+ }
66
+ }
67
+ if (wasWildcard) {
68
+ isOptional = true;
69
+ test = /.*/;
55
70
  }
56
71
  memo.push({ segment, name, test, isOptional, isSpread });
57
72
  return memo;
@@ -103,6 +118,11 @@ class SimpleRoute {
103
118
  });
104
119
  segments = newSegments;
105
120
  }
121
+ // return early no-op special case: first segment is a wildcard
122
+ // (no need to process further)
123
+ if (this._parsed?.[0]?.segment === SimpleRoute.WILDCARD) {
124
+ return matched;
125
+ }
106
126
  // minimum required (not optional) segments length
107
127
  const reqLen = this._parsed.reduce((memo, p, idx, arr) => {
108
128
  const next = arr[idx + 1];
@@ -124,6 +144,9 @@ class SimpleRoute {
124
144
  if (p.name) {
125
145
  matched[decodeURIComponent(p.name)] = decodeURIComponent(s);
126
146
  }
147
+ if (p.segment === SimpleRoute.WILDCARD) {
148
+ break;
149
+ }
127
150
  }
128
151
  return matched;
129
152
  }
package/dist/route.d.ts CHANGED
@@ -8,6 +8,7 @@ export interface RouteConfig {
8
8
  export declare class SimpleRoute {
9
9
  readonly route: any;
10
10
  static SPLITTER: string;
11
+ static WILDCARD: string;
11
12
  protected _parsed: RouteConfig[];
12
13
  constructor(route: any);
13
14
  protected static _escapeRegExp(str: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/simple-router",
3
- "version": "1.9.2",
3
+ "version": "2.0.1",
4
4
  "description": "Minimalistic route parser for sapper-like regex routes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",