@esmx/router 3.0.0-rc.49 → 3.0.0-rc.51

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/matcher.mjs CHANGED
@@ -1,12 +1,15 @@
1
1
  import { compile, match } from "path-to-regexp";
2
2
  export function createMatcher(routes) {
3
3
  const compiledRoutes = createRouteMatches(routes);
4
- return (toURL, baseURL) => {
4
+ return (toURL, baseURL, cb) => {
5
5
  const matchPath = toURL.pathname.substring(baseURL.pathname.length - 1);
6
6
  const matches = [];
7
7
  const params = {};
8
8
  const collectMatchingRoutes = (routes2) => {
9
9
  for (const item of routes2) {
10
+ if (cb && !cb(item)) {
11
+ continue;
12
+ }
10
13
  if (item.children.length && collectMatchingRoutes(item.children)) {
11
14
  matches.unshift(item);
12
15
  return true;
package/dist/options.mjs CHANGED
@@ -32,7 +32,7 @@ function getBaseUrl(options) {
32
32
  export function parsedOptions(options = {}) {
33
33
  var _a, _b, _c, _d, _e, _f;
34
34
  const base = getBaseUrl(options);
35
- const routes = Array.from((_a = options.routes) != null ? _a : []);
35
+ const routes = (_a = options.routes) != null ? _a : [];
36
36
  return Object.freeze({
37
37
  rootStyle: options.rootStyle || false,
38
38
  root: options.root || "",
package/dist/route.mjs CHANGED
@@ -85,9 +85,20 @@ export class Route {
85
85
  const base = options.base;
86
86
  const toInput = resolveRouteLocationInput(routeOptions.toInput, from);
87
87
  const to = options.normalizeURL(parseLocation(toInput, base), from);
88
- const isSameOrigin = to.origin === base.origin;
89
- const isSameBase = to.pathname.startsWith(base.pathname);
90
- const match = isSameOrigin && isSameBase ? options.matcher(to, base) : null;
88
+ let match = null;
89
+ if (to.origin === base.origin && to.pathname.startsWith(base.pathname)) {
90
+ const isLayer = toType === RouteType.pushLayer;
91
+ match = options.matcher(to, base, (config) => {
92
+ if (isLayer) {
93
+ return config.layer !== false;
94
+ }
95
+ return config.layer !== true;
96
+ });
97
+ }
98
+ if (match) {
99
+ applyRouteParams(match, toInput, base, to);
100
+ Object.assign(this.params, match.params);
101
+ }
91
102
  this.url = to;
92
103
  this.path = match ? to.pathname.substring(base.pathname.length - 1) : to.pathname;
93
104
  this.fullPath = (match ? this.path : to.pathname) + to.search + to.hash;
@@ -107,10 +118,6 @@ export class Route {
107
118
  this.queryArray[key] = to.searchParams.getAll(key);
108
119
  }
109
120
  this.hash = to.hash;
110
- if (match) {
111
- applyRouteParams(match, toInput, base, to);
112
- Object.assign(this.params, match.params);
113
- }
114
121
  if (typeof toInput.statusCode === "number") {
115
122
  this.statusCode = toInput.statusCode;
116
123
  }
package/dist/types.d.ts CHANGED
@@ -61,6 +61,8 @@ export interface RouteConfig {
61
61
  beforeEnter?: RouteConfirmHook;
62
62
  beforeUpdate?: RouteConfirmHook;
63
63
  beforeLeave?: RouteConfirmHook;
64
+ /** Mark this route as only effective in layer mode */
65
+ layer?: boolean;
64
66
  /**
65
67
  * Route override function for hybrid app development
66
68
  *
@@ -91,7 +93,7 @@ export interface RouteMatchResult {
91
93
  readonly matches: readonly RouteParsedConfig[];
92
94
  readonly params: Record<string, string | string[] | undefined>;
93
95
  }
94
- export type RouteMatcher = (targetURL: URL, baseURL: URL) => RouteMatchResult;
96
+ export type RouteMatcher = (to: URL, base: URL, cb?: (item: RouteParsedConfig) => boolean) => RouteMatchResult;
95
97
  /**
96
98
  * Route constructor options interface
97
99
  */
package/package.json CHANGED
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@biomejs/biome": "1.9.4",
35
- "@esmx/lint": "3.0.0-rc.49",
35
+ "@esmx/lint": "3.0.0-rc.51",
36
36
  "@types/node": "^24.0.0",
37
37
  "@vitest/coverage-v8": "3.2.4",
38
38
  "happy-dom": "^18.0.1",
@@ -41,7 +41,7 @@
41
41
  "unbuild": "3.5.0",
42
42
  "vitest": "3.2.4"
43
43
  },
44
- "version": "3.0.0-rc.49",
44
+ "version": "3.0.0-rc.51",
45
45
  "type": "module",
46
46
  "private": false,
47
47
  "exports": {
@@ -60,5 +60,5 @@
60
60
  "template",
61
61
  "public"
62
62
  ],
63
- "gitHead": "640eb582ee922d64bf47ed38bb8d6ce9cb2369e4"
63
+ "gitHead": "5556ca6bbaf29a673861c685a19414d5853b9166"
64
64
  }
package/src/matcher.ts CHANGED
@@ -3,7 +3,11 @@ import type { RouteConfig, RouteMatcher, RouteParsedConfig } from './types';
3
3
 
4
4
  export function createMatcher(routes: RouteConfig[]): RouteMatcher {
5
5
  const compiledRoutes = createRouteMatches(routes);
6
- return (toURL: URL, baseURL: URL) => {
6
+ return (
7
+ toURL: URL,
8
+ baseURL: URL,
9
+ cb?: (item: RouteParsedConfig) => boolean
10
+ ) => {
7
11
  const matchPath = toURL.pathname.substring(baseURL.pathname.length - 1);
8
12
  const matches: RouteParsedConfig[] = [];
9
13
  const params: Record<string, string | string[]> = {};
@@ -11,6 +15,9 @@ export function createMatcher(routes: RouteConfig[]): RouteMatcher {
11
15
  routes: RouteParsedConfig[]
12
16
  ): boolean => {
13
17
  for (const item of routes) {
18
+ if (cb && !cb(item)) {
19
+ continue;
20
+ }
14
21
  // Depth-first traversal
15
22
  if (
16
23
  item.children.length &&
package/src/options.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import { createMatcher } from './matcher';
2
2
  import type { Router } from './router';
3
3
  import { RouterMode } from './types';
4
- import type { Route, RouterOptions, RouterParsedOptions } from './types';
4
+ import type {
5
+ Route,
6
+ RouteConfig,
7
+ RouterOptions,
8
+ RouterParsedOptions
9
+ } from './types';
5
10
  import { isBrowser } from './util';
6
11
 
7
12
  /**
@@ -60,7 +65,7 @@ export function parsedOptions(
60
65
  options: RouterOptions = {}
61
66
  ): RouterParsedOptions {
62
67
  const base = getBaseUrl(options);
63
- const routes = Array.from(options.routes ?? []);
68
+ const routes = options.routes ?? [];
64
69
  return Object.freeze<RouterParsedOptions>({
65
70
  rootStyle: options.rootStyle || false,
66
71
  root: options.root || '',
package/src/route.ts CHANGED
@@ -153,10 +153,27 @@ export class Route {
153
153
  const base = options.base;
154
154
  const toInput = resolveRouteLocationInput(routeOptions.toInput, from);
155
155
  const to = options.normalizeURL(parseLocation(toInput, base), from);
156
- const isSameOrigin = to.origin === base.origin;
157
- const isSameBase = to.pathname.startsWith(base.pathname);
158
- const match =
159
- isSameOrigin && isSameBase ? options.matcher(to, base) : null;
156
+ let match: RouteMatchResult | null = null;
157
+
158
+ // Check if URL origin matches base origin (protocol + hostname + port)
159
+ // If origins don't match, treat as external URL and don't attempt route matching
160
+ if (
161
+ to.origin === base.origin &&
162
+ to.pathname.startsWith(base.pathname)
163
+ ) {
164
+ const isLayer = toType === RouteType.pushLayer;
165
+ match = options.matcher(to, base, (config) => {
166
+ if (isLayer) {
167
+ return config.layer !== false;
168
+ }
169
+ return config.layer !== true;
170
+ });
171
+ }
172
+
173
+ if (match) {
174
+ applyRouteParams(match, toInput, base, to);
175
+ Object.assign(this.params, match.params);
176
+ }
160
177
 
161
178
  this.url = to;
162
179
  this.path = match
@@ -176,27 +193,18 @@ export class Route {
176
193
  : null;
177
194
  this.meta = this.config?.meta || {};
178
195
 
179
- // Initialize state object - create new local object, merge externally passed state
180
196
  const state: RouteState = {};
181
197
  if (toInput.state) {
182
198
  Object.assign(state, toInput.state);
183
199
  }
184
200
  this.state = state;
185
201
 
186
- // Process query parameters
187
202
  for (const key of new Set(to.searchParams.keys())) {
188
203
  this.query[key] = to.searchParams.get(key)!;
189
204
  this.queryArray[key] = to.searchParams.getAll(key);
190
205
  }
191
206
  this.hash = to.hash;
192
207
 
193
- // Apply user-provided route parameters (if match is successful)
194
- if (match) {
195
- applyRouteParams(match, toInput, base, to);
196
- // Assign matched parameters to route object
197
- Object.assign(this.params, match.params);
198
- }
199
-
200
208
  // Set status code
201
209
  // Prioritize user-provided statusCode
202
210
  if (typeof toInput.statusCode === 'number') {
package/src/types.ts CHANGED
@@ -110,6 +110,8 @@ export interface RouteConfig {
110
110
  beforeEnter?: RouteConfirmHook;
111
111
  beforeUpdate?: RouteConfirmHook;
112
112
  beforeLeave?: RouteConfirmHook;
113
+ /** Mark this route as only effective in layer mode */
114
+ layer?: boolean;
113
115
 
114
116
  /**
115
117
  * Route override function for hybrid app development
@@ -144,7 +146,11 @@ export interface RouteMatchResult {
144
146
  readonly params: Record<string, string | string[] | undefined>;
145
147
  }
146
148
 
147
- export type RouteMatcher = (targetURL: URL, baseURL: URL) => RouteMatchResult;
149
+ export type RouteMatcher = (
150
+ to: URL,
151
+ base: URL,
152
+ cb?: (item: RouteParsedConfig) => boolean
153
+ ) => RouteMatchResult;
148
154
 
149
155
  /**
150
156
  * Route constructor options interface