sv-router 0.11.0 → 0.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sv-router",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Modern Svelte Routing",
5
5
  "keywords": [
6
6
  "svelte",
@@ -36,29 +36,29 @@
36
36
  "esm-env": "^1.2.2"
37
37
  },
38
38
  "devDependencies": {
39
- "@changesets/cli": "^2.29.7",
40
- "@eslint/js": "^9.39.0",
39
+ "@changesets/cli": "^2.29.8",
40
+ "@eslint/js": "^9.39.1",
41
41
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
42
42
  "@testing-library/jest-dom": "^6.9.1",
43
- "@testing-library/svelte": "^5.2.8",
43
+ "@testing-library/svelte": "^5.2.9",
44
44
  "@testing-library/user-event": "^14.6.1",
45
- "@types/node": "^24.9.2",
46
- "eslint": "^9.39.0",
45
+ "@types/node": "^24.10.1",
46
+ "eslint": "^9.39.1",
47
47
  "eslint-config-prettier": "^10.1.8",
48
48
  "eslint-plugin-simple-import-sort": "^12.1.1",
49
- "eslint-plugin-svelte": "^3.13.0",
49
+ "eslint-plugin-svelte": "^3.13.1",
50
50
  "eslint-plugin-unicorn": "^62.0.0",
51
51
  "globals": "^16.5.0",
52
- "happy-dom": "^20.0.10",
53
- "prettier": "^3.6.2",
54
- "prettier-plugin-jsdoc": "^1.5.0",
52
+ "happy-dom": "^20.0.11",
53
+ "prettier": "^3.7.4",
54
+ "prettier-plugin-jsdoc": "^1.8.0",
55
55
  "prettier-plugin-svelte": "^3.4.0",
56
- "svelte-check": "^4.3.3",
56
+ "svelte-check": "^4.3.4",
57
57
  "type-testing": "^0.2.0",
58
58
  "typescript": "^5.9.3",
59
- "typescript-eslint": "^8.46.2",
60
- "vite": "^7.1.12",
61
- "vitest": "^4.0.6"
59
+ "typescript-eslint": "^8.48.1",
60
+ "vite": "^7.2.6",
61
+ "vitest": "^4.0.15"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "svelte": "^5"
@@ -134,7 +134,7 @@ function navigate(path, options = {}) {
134
134
 
135
135
  path = constructPath(path, options.params);
136
136
  if (base.name === '#') {
137
- path = new URL(path).hash;
137
+ path = path.replace('/#', '');
138
138
  } else if (options.hash && !options.hash.startsWith('#')) {
139
139
  options.hash = '#' + options.hash;
140
140
  }
@@ -200,8 +200,10 @@ export async function onNavigate(path, options = {}) {
200
200
  url.hash = options.hash || '';
201
201
  if (base.name === '#') {
202
202
  url.hash = path;
203
+ } else if (base.name && !path.startsWith(base.name)) {
204
+ url.pathname = join(base.name, path);
203
205
  } else {
204
- url.pathname = base.name ? join(base.name, path) : path;
206
+ url.pathname = path;
205
207
  }
206
208
  const historyMethod = options.replace ? 'replaceState' : 'pushState';
207
209
  globalThis.history[historyMethod](options.state || {}, '', url.toString());
@@ -5,7 +5,7 @@ import path from 'node:path';
5
5
 
6
6
  /**
7
7
  * @typedef {{
8
- * [key: string]: string | GeneratedRoutes;
8
+ * [key: string]: string | string[] | GeneratedRoutes;
9
9
  * }} GeneratedRoutes
10
10
  */
11
11
 
@@ -144,22 +144,28 @@ function mergeRouteGroup(result, childMap) {
144
144
  const layout = childMap.layout;
145
145
  const hooks = childMap.hooks;
146
146
  const meta = childMap.meta;
147
+ const hasRootRoute = '/' in childMap;
147
148
 
148
149
  for (const [key, val] of Object.entries(childMap)) {
149
150
  if (key === 'layout' || key === 'hooks' || key === 'meta') {
150
151
  continue;
151
152
  }
152
153
 
154
+ const childMeta =
155
+ typeof val === 'object' && !Array.isArray(val) && 'meta' in val ? val.meta : undefined;
156
+ const mergedMeta =
157
+ childMeta && meta && !hasRootRoute ? [childMeta, meta].flat() : childMeta || meta;
158
+
153
159
  /** @type {GeneratedRoutes} */
154
160
  let routeWithGroupFiles = {};
155
161
  if (typeof val === 'string') {
156
162
  routeWithGroupFiles = { '/': val };
157
- } else {
163
+ } else if (!Array.isArray(val)) {
158
164
  routeWithGroupFiles = { ...val };
159
165
  }
160
- if (layout) routeWithGroupFiles.layout = layout;
161
- if (hooks) routeWithGroupFiles.hooks = hooks;
162
- if (meta) routeWithGroupFiles.meta = meta;
166
+ if (layout) routeWithGroupFiles.layout = /** @type {string} */ (layout);
167
+ if (hooks) routeWithGroupFiles.hooks = /** @type {string} */ (hooks);
168
+ if (mergedMeta) routeWithGroupFiles.meta = /** @type {string | string[]} */ (mergedMeta);
163
169
  if (result[key]) {
164
170
  throw new Error(`Route conflict at \`${key}\``);
165
171
  }
@@ -186,12 +192,18 @@ export function createRouterCode(routes, routesPath, { allLazy = false, js = fal
186
192
  /** @type {GeneratedRoutes} */
187
193
  const result = {};
188
194
  for (const [key, value] of Object.entries(routes)) {
189
- if (typeof value === 'object') {
195
+ if (typeof value === 'object' && !Array.isArray(value)) {
190
196
  result[key] = handleImports(value, routesPath);
197
+ } else if (key === 'meta' && Array.isArray(value)) {
198
+ const varNames = value.map((metaPath) => {
199
+ const variableName = pathToCorrectCasing(metaPath);
200
+ importsMap.set(variableName, routesPath + metaPath);
201
+ return variableName;
202
+ });
203
+ result[key] = `{ ...${varNames.toReversed().join(', ...')} }`;
191
204
  } else if (
192
- key === 'hooks' ||
193
- key === 'meta' ||
194
- (!value.endsWith('.lazy.svelte') && !allLazy)
205
+ typeof value === 'string' &&
206
+ (key === 'hooks' || key === 'meta' || (!value.endsWith('.lazy.svelte') && !allLazy))
195
207
  ) {
196
208
  const variableName = pathToCorrectCasing(value);
197
209
  importsMap.set(variableName, routesPath + value);
@@ -1,5 +1,5 @@
1
1
  import { base, location } from '../create-router.svelte.js';
2
- import { constructPath, join } from './utils.js';
2
+ import { constructPath } from './utils.js';
3
3
 
4
4
  /**
5
5
  * @param {string} pathname
@@ -7,8 +7,7 @@ import { constructPath, join } from './utils.js';
7
7
  * @returns {boolean}
8
8
  */
9
9
  export function isActive(pathname, params) {
10
- const p = base.name && base.name !== '#' ? join(base.name, pathname) : pathname;
11
- return compare((a, b) => a === b, p, params);
10
+ return compare((a, b) => a === b, pathname, params);
12
11
  }
13
12
 
14
13
  /**
@@ -17,8 +16,7 @@ export function isActive(pathname, params) {
17
16
  * @returns {boolean}
18
17
  */
19
18
  isActive.startsWith = (pathname, params) => {
20
- const p = base.name && base.name !== '#' ? join(base.name, pathname) : pathname;
21
- return compare((a, b) => a.startsWith(b), p, params);
19
+ return compare((a, b) => a.startsWith(b), pathname, params);
22
20
  };
23
21
 
24
22
  /**
@@ -34,7 +32,7 @@ function compare(compareFn, pathname, params) {
34
32
 
35
33
  if (params) {
36
34
  if (base.name === '#') {
37
- return compareFn(location.pathname, new URL(constructPath(pathname, params)).hash.slice(1));
35
+ return compareFn(location.pathname, constructPath(pathname, params).replace('/#', ''));
38
36
  } else {
39
37
  return compareFn(location.pathname, constructPath(pathname, params));
40
38
  }
@@ -45,6 +45,11 @@ export function matchRoute(pathname, routes) {
45
45
  /** @type {RouteMeta} */
46
46
  let meta = {};
47
47
 
48
+ const rootRoute = routes['/'];
49
+ if (rootRoute && typeof rootRoute === 'object' && 'meta' in rootRoute && rootRoute.meta) {
50
+ meta = { ...meta, ...rootRoute.meta };
51
+ }
52
+
48
53
  let breakFromLayouts = false;
49
54
 
50
55
  outer: for (const route of allRoutes) {
@@ -13,11 +13,12 @@ export function constructPath(path, params) {
13
13
  }
14
14
 
15
15
  if (base.name === '#') {
16
- const url = new URL(globalThis.location.toString());
17
- url.hash = path;
18
- url.search = '';
19
-
20
- return url.toString();
16
+ if (path === '/') {
17
+ return '/#/';
18
+ }
19
+ return join('#', path);
20
+ } else if (base.name) {
21
+ return join(base.name, path);
21
22
  }
22
23
 
23
24
  return path;