@shuvi/router 2.0.0-dev.32 → 2.0.0-dev.33

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.
@@ -14,6 +14,20 @@ const CATCHALL_TOKEN = {
14
14
  const CATCHALL_TOKEN_STRICT = Object.assign(Object.assign({}, CATCHALL_TOKEN), { regexp: '(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?$' });
15
15
  // Special Regex characters that must be escaped in static tokens
16
16
  const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g;
17
+ /**
18
+ * Whether the pattern built from these segments ends at a separator, with
19
+ * nothing of its own after it. See its use in `tokensToParser`.
20
+ */
21
+ function endsAtSeparator(segments) {
22
+ const last = segments[segments.length - 1];
23
+ if (!last) {
24
+ return false;
25
+ }
26
+ return (last.length === 0 ||
27
+ (last.length === 1 &&
28
+ last[0].type === 0 /* TokenType.Static */ &&
29
+ last[0].value === ''));
30
+ }
17
31
  /**
18
32
  * Creates a path parser from an array of Segments (a segment is an array of Tokens)
19
33
  *
@@ -158,8 +172,25 @@ export function tokensToParser(segments, extraOptions, branchInfo) {
158
172
  if (options.end)
159
173
  pattern += '$';
160
174
  // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else
161
- else if (options.strict)
162
- pattern += '(?:/*|$)';
175
+ //
176
+ // The assertion is zero-width. A non-end parser belongs to an intermediate
177
+ // route, and `matchRouteBranch` slices that route's match off the pathname
178
+ // before running the rest of the branch. Consuming the separator would
179
+ // leave the child `42` rather than `/42` for `/item/42`, and no child
180
+ // pattern starts without a slash, so every route under a nested layout
181
+ // stopped matching, at its canonical url as much as at the slash-suffixed
182
+ // one. Holding the separator back also keeps the pathname an intermediate
183
+ // route reports equal to the loose matcher's.
184
+ //
185
+ // A param token already appends the same lookahead, for the same reason.
186
+ //
187
+ // Except when the pattern stops at a separator with nothing of its own
188
+ // after it, which is the `/` route (one empty static token) and a path that
189
+ // is empty or ends in a slash (an empty segment, which the strict branch
190
+ // above turns into a bare `/`). There the separator is the match, so there
191
+ // is nothing to hold back.
192
+ else if (options.strict && !endsAtSeparator(segments))
193
+ pattern += '(?=/|$)';
163
194
  }
164
195
  const re = new RegExp(pattern, options.sensitive ? '' : 'i');
165
196
  function parse(path) {
@@ -18,6 +18,20 @@ const CATCHALL_TOKEN = {
18
18
  const CATCHALL_TOKEN_STRICT = Object.assign(Object.assign({}, CATCHALL_TOKEN), { regexp: '(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?$' });
19
19
  // Special Regex characters that must be escaped in static tokens
20
20
  const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g;
21
+ /**
22
+ * Whether the pattern built from these segments ends at a separator, with
23
+ * nothing of its own after it. See its use in `tokensToParser`.
24
+ */
25
+ function endsAtSeparator(segments) {
26
+ const last = segments[segments.length - 1];
27
+ if (!last) {
28
+ return false;
29
+ }
30
+ return (last.length === 0 ||
31
+ (last.length === 1 &&
32
+ last[0].type === 0 /* TokenType.Static */ &&
33
+ last[0].value === ''));
34
+ }
21
35
  /**
22
36
  * Creates a path parser from an array of Segments (a segment is an array of Tokens)
23
37
  *
@@ -162,8 +176,25 @@ function tokensToParser(segments, extraOptions, branchInfo) {
162
176
  if (options.end)
163
177
  pattern += '$';
164
178
  // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else
165
- else if (options.strict)
166
- pattern += '(?:/*|$)';
179
+ //
180
+ // The assertion is zero-width. A non-end parser belongs to an intermediate
181
+ // route, and `matchRouteBranch` slices that route's match off the pathname
182
+ // before running the rest of the branch. Consuming the separator would
183
+ // leave the child `42` rather than `/42` for `/item/42`, and no child
184
+ // pattern starts without a slash, so every route under a nested layout
185
+ // stopped matching, at its canonical url as much as at the slash-suffixed
186
+ // one. Holding the separator back also keeps the pathname an intermediate
187
+ // route reports equal to the loose matcher's.
188
+ //
189
+ // A param token already appends the same lookahead, for the same reason.
190
+ //
191
+ // Except when the pattern stops at a separator with nothing of its own
192
+ // after it, which is the `/` route (one empty static token) and a path that
193
+ // is empty or ends in a slash (an empty segment, which the strict branch
194
+ // above turns into a bare `/`). There the separator is the match, so there
195
+ // is nothing to hold back.
196
+ else if (options.strict && !endsAtSeparator(segments))
197
+ pattern += '(?=/|$)';
167
198
  }
168
199
  const re = new RegExp(pattern, options.sensitive ? '' : 'i');
169
200
  function parse(path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shuvi/router",
3
- "version": "2.0.0-dev.32",
3
+ "version": "2.0.0-dev.33",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/shuvijs/shuvi.git",