@ktjs/router 0.32.5 → 0.33.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
@@ -12,11 +12,14 @@
12
12
 
13
13
  <p align="center"><strong>Visit KT.js: <a href="https://baendlorel.github.io/kt.js/">https://baendlorel.github.io/kt.js/</a></strong></p>
14
14
 
15
+ > kt.js is still under development, so there might be some breaking changes. Note the Update Log below
16
+
15
17
  ## Recent Updates
16
18
 
17
- 1. Special refs for `Array`, `Set`, `Map`, `WeakMap`, `WeakSet`, `Date` to better track mutations.
18
- - e.g. `const a = ref.array([1, 2])`, then we can call `a.push(3)` to make a reactive change instead of `a.value.push(3)`.
19
- 2. Fixed issues of `svg` and `mathml` elements.
19
+ 1. `ref.value` remains the standard read API, and it can also replace the whole outer value with `ref.value = nextValue`.
20
+ 2. `ref.draft` is the deep-mutation entry for nested objects, arrays, `Map` / `Set`, and custom mutable objects.
21
+ 3. `ref.draft` itself is not assignable; mutate nested fields or call mutating methods on the returned object instead.
22
+ 4. `addOnChange((newValue, oldValue) => ...)` keeps `oldValue` as the previous reference, not a deep snapshot.
20
23
 
21
24
  ## Community
22
25
 
@@ -29,6 +32,35 @@ kt.js is a simple framework with a tiny runtime that renders real DOM directly (
29
32
 
30
33
  KT.js focuses on one principle: keep direct control of the DOM and avoid unnecessary repainting.
31
34
 
35
+ ## Reactive Contract
36
+
37
+ ```ts
38
+ const user = ref({ profile: { name: 'John' }, tags: ['new'] });
39
+
40
+ console.log(user.value.profile.name); // read
41
+
42
+ user.value = {
43
+ ...user.value,
44
+ profile: { ...user.value.profile, name: 'Jane' },
45
+ tags: [...user.value.tags],
46
+ }; // replace the whole outer value
47
+
48
+ user.draft.profile.name = 'Jane'; // deep write
49
+ user.draft.tags.push('active'); // array / map / set / custom-object style mutation
50
+ ```
51
+
52
+ Rules:
53
+
54
+ - Read with `.value`.
55
+ - Replace the whole outer value with `.value = nextValue`.
56
+ - Use `.draft` for deep mutations on nested objects, arrays, `Map` / `Set`, or other mutable instances.
57
+ - Do not assign to `.draft` itself; mutate inside it.
58
+ - `computed` stays read-only and is consumed through `.value`.
59
+ - `oldValue` in change listeners is the previous reference only, not a deep-cloned snapshot.
60
+ - Correctness is expected to come from the transformer and TypeScript checks; runtime hot paths stay minimal on purpose.
61
+
62
+ This is an explicit contract, closer to a Rust-style model than permissive runtime magic: unclear code should fail early.
63
+
32
64
  ## Quick Start
33
65
 
34
66
  ```bash
package/dist/index.mjs CHANGED
@@ -1,315 +1,155 @@
1
- import { normalizePath, extractParams, $emptyFn, parseQuery, emplaceParams, buildQuery } from '@ktjs/shared';
1
+ import { normalizePath, extractParams, $emptyFn, parseQuery, emplaceParams, buildQuery } from "@ktjs/shared";
2
2
 
3
- /**
4
- * Route matcher for finding matching routes and extracting params
5
- */
6
- const createMatcher = (routes) => {
7
- const nameMap = {};
8
- for (let i = 0; i < routes.length; i++) {
9
- const route = routes[i];
10
- if (route.name !== undefined) {
11
- if (route.name in nameMap) {
12
- throw new Error(`[@ktjs/router error] Duplicate route name detected: '${route.name}'`);
13
- }
14
- nameMap[route.name] = route;
15
- }
16
- }
17
- /**
18
- * Find route by name
19
- */
20
- const findByName = (name) => {
21
- return nameMap[name] ?? null;
22
- };
23
- /**
24
- * Match path against all routes
25
- */
26
- const match = (path) => {
27
- const normalizedPath = normalizePath(path);
28
- // Try exact match first
29
- for (const route of routes) {
30
- if (route.path === normalizedPath) {
31
- return {
32
- route,
33
- params: {},
34
- result: getMatchedChain(route),
35
- };
36
- }
37
- }
38
- // Try dynamic routes
39
- for (const route of routes) {
40
- if (route.path.includes(':')) {
41
- const params = extractParams(route.path, normalizedPath);
42
- if (params) {
43
- return {
44
- route,
45
- params,
46
- result: getMatchedChain(route),
47
- };
48
- }
49
- }
50
- }
51
- return null;
52
- };
53
- /**
54
- * Get chain of matched routes (for nested routes)
55
- * - parent roots ahead
56
- */
57
- const getMatchedChain = (route) => {
58
- const matched = [route];
59
- const path = route.path;
60
- // Find parent routes by path prefix matching
61
- for (let i = 0; i < routes.length; i++) {
62
- const r = routes[i];
63
- if (r !== route && path.startsWith(r.path) && path !== r.path) {
64
- matched.push(r);
65
- }
66
- }
67
- return matched.reverse();
68
- };
69
- return {
70
- findByName,
71
- match,
72
- };
73
- };
74
-
75
- /**
76
- * Create a router view container that automatically renders route components
77
- */
78
- function KTRouter({ router }) {
79
- const view = document.createElement('kt-router-view');
80
- router.setRouterView(view);
81
- return view;
3
+ function KTRouter({router: router}) {
4
+ const view = document.createElement("kt-router-view");
5
+ return router.setRouterView(view), view;
82
6
  }
83
7
 
84
- /**
85
- * Create a new router instance
86
- */
87
- const createRouter = ({ beforeEach = $emptyFn, afterEach = $emptyFn, onNotFound = $emptyFn, onError = $emptyFn, prefix = '', routes: rawRoutes, }) => {
88
- // # private values
89
- const routes = [];
90
- const history = [];
91
- let routerView = null;
92
- let current = null;
93
- // # methods
94
- const normalize = (rawRoutes, parentPath) => rawRoutes.map((route) => {
95
- const path = normalizePath(parentPath, route.path);
96
- const normalized = {
8
+ const createRouter = ({beforeEach: beforeEach = $emptyFn, afterEach: afterEach = $emptyFn, onNotFound: onNotFound = $emptyFn, onError: onError = $emptyFn, prefix: prefix = "", routes: rawRoutes}) => {
9
+ const routes = [], history = [];
10
+ let routerView = null, current = null;
11
+ const normalize = (rawRoutes, parentPath) => rawRoutes.map(route => {
12
+ const path = normalizePath(parentPath, route.path), normalized = {
97
13
  path: prefix + path,
98
- name: route.name ?? '',
14
+ name: route.name ?? "",
99
15
  meta: route.meta ?? {},
100
16
  beforeEnter: route.beforeEnter ?? $emptyFn,
101
17
  after: route.after ?? $emptyFn,
102
18
  children: route.children ? normalize(route.children, path) : [],
103
- component: route.component,
104
- };
105
- // directly push the normalized route to the list
106
- // avoid flatten them again
107
- routes.push(normalized);
108
- return normalized;
109
- });
110
- const guard = async (to, from, guardLevel) => {
111
- try {
112
- if (guardLevel === 0 /* GuardLevel.None */) {
113
- return { continue: true };
114
- }
115
- if (guardLevel & 1 /* GuardLevel.Global */) {
116
- const result = await beforeEach(to, from);
117
- if (result === false) {
118
- return { continue: false };
119
- }
120
- if (typeof result === 'string') {
121
- return { continue: false, redirectTo: { path: result } };
122
- }
123
- if (result && typeof result === 'object') {
124
- return { continue: false, redirectTo: result };
125
- }
126
- }
127
- if (guardLevel & 2 /* GuardLevel.Route */) {
128
- const targetRoute = to.matched[to.matched.length - 1];
129
- const result = await targetRoute.beforeEnter(to);
130
- if (result === false) {
131
- return { continue: false };
132
- }
133
- if (typeof result === 'string') {
134
- return { continue: false, redirectTo: { path: result } };
135
- }
136
- if (result && typeof result === 'object') {
137
- return { continue: false, redirectTo: result };
138
- }
139
- }
140
- return { continue: true };
141
- }
142
- catch (error) {
143
- onError(error);
144
- return { continue: false };
145
- }
146
- };
147
- const navigatePrepare = (options) => {
148
- // Resolve target route
149
- let targetPath;
150
- let targetRoute;
151
- if (options.name) {
152
- targetRoute = findByName(options.name);
153
- if (!targetRoute) {
154
- throw new Error(`[@ktjs/router error] Route not found: ${options.name}`);
155
- }
156
- targetPath = targetRoute.path;
157
- }
158
- else if (options.path) {
159
- targetPath = normalizePath(options.path);
160
- targetRoute = match(targetPath)?.route;
161
- }
162
- else {
163
- throw new Error(`[@ktjs/router error] Either path or name must be provided`);
164
- }
165
- // Substitute params
166
- if (options.params) {
167
- targetPath = emplaceParams(targetPath, options.params);
168
- }
169
- // Match final path
170
- const matched = match(targetPath);
171
- if (!matched) {
172
- onNotFound(targetPath);
173
- return null;
174
- }
175
- // Build route context
176
- const queryString = options.query ? buildQuery(options.query) : '';
177
- const fullPath = targetPath + queryString;
178
- const to = {
179
- path: targetPath,
180
- name: matched.route.name,
181
- params: { ...matched.params, ...(options.params ?? {}) },
182
- query: options.query ?? {},
183
- meta: matched.route.meta ?? {},
184
- matched: matched.result,
185
- };
186
- return {
187
- guardLevel: options.guardLevel ?? 15 /* GuardLevel.Default */,
188
- replace: options.replace ?? false,
189
- to,
190
- fullPath,
19
+ component: route.component
191
20
  };
192
- };
193
- const navigate = async (options, redirectCount = 0) => {
21
+ return routes.push(normalized), normalized;
22
+ }), navigate = async (options, redirectCount = 0) => {
194
23
  try {
195
- // Prevent infinite redirect loop
196
- if (redirectCount > 10) {
197
- onError(new Error('Maximum redirect count exceeded'));
198
- return false;
199
- }
200
- const prep = navigatePrepare(options);
201
- if (!prep) {
202
- return false;
203
- }
204
- const { guardLevel, replace, to, fullPath } = prep;
205
- const guardResult = await guard(to, current, guardLevel);
206
- if (!guardResult.continue) {
207
- // Check if there's a redirect
208
- if (guardResult.redirectTo) {
209
- return await navigate(guardResult.redirectTo, redirectCount + 1);
210
- }
211
- return false;
212
- }
213
- // ---- Guards passed ----
214
- const hashUrl = '#' + fullPath;
215
- if (replace) {
216
- window.location.replace(hashUrl);
217
- }
218
- else {
219
- window.location.hash = fullPath;
220
- }
221
- current = to;
222
- if (replace) {
223
- if (history.length > 0) {
224
- history[history.length - 1] = to;
24
+ if (redirectCount > 10) return onError(new Error("Maximum redirect count exceeded")),
25
+ !1;
26
+ const prep = (options => {
27
+ let targetPath, targetRoute;
28
+ if (options.name) {
29
+ if (targetRoute = findByName(options.name), !targetRoute) throw new Error(`[@ktjs/router error] Route not found: ${options.name}`);
30
+ targetPath = targetRoute.path;
31
+ } else {
32
+ if (!options.path) throw new Error("[@ktjs/router error] Either path or name must be provided");
33
+ targetPath = normalizePath(options.path), targetRoute = match(targetPath)?.route;
225
34
  }
226
- else {
227
- history.push(to);
35
+ options.params && (targetPath = emplaceParams(targetPath, options.params));
36
+ const matched = match(targetPath);
37
+ if (!matched) return onNotFound(targetPath), null;
38
+ const fullPath = targetPath + (options.query ? buildQuery(options.query) : ""), to = {
39
+ path: targetPath,
40
+ name: matched.route.name,
41
+ params: {
42
+ ...matched.params,
43
+ ...options.params ?? {}
44
+ },
45
+ query: options.query ?? {},
46
+ meta: matched.route.meta ?? {},
47
+ matched: matched.result
48
+ };
49
+ return {
50
+ guardLevel: options.guardLevel ?? 15,
51
+ replace: options.replace ?? !1,
52
+ to: to,
53
+ fullPath: fullPath
54
+ };
55
+ })(options);
56
+ if (!prep) return !1;
57
+ const {guardLevel: guardLevel, replace: replace, to: to, fullPath: fullPath} = prep, guardResult = await (async (to, from, guardLevel) => {
58
+ try {
59
+ if (0 === guardLevel) return {
60
+ continue: !0
61
+ };
62
+ if (1 & guardLevel) {
63
+ const result = await beforeEach(to, from);
64
+ if (!1 === result) return {
65
+ continue: !1
66
+ };
67
+ if ("string" == typeof result) return {
68
+ continue: !1,
69
+ redirectTo: {
70
+ path: result
71
+ }
72
+ };
73
+ if (result && "object" == typeof result) return {
74
+ continue: !1,
75
+ redirectTo: result
76
+ };
77
+ }
78
+ if (2 & guardLevel) {
79
+ const targetRoute = to.matched[to.matched.length - 1], result = await targetRoute.beforeEnter(to);
80
+ if (!1 === result) return {
81
+ continue: !1
82
+ };
83
+ if ("string" == typeof result) return {
84
+ continue: !1,
85
+ redirectTo: {
86
+ path: result
87
+ }
88
+ };
89
+ if (result && "object" == typeof result) return {
90
+ continue: !1,
91
+ redirectTo: result
92
+ };
93
+ }
94
+ return {
95
+ continue: !0
96
+ };
97
+ } catch (error) {
98
+ return onError(error), {
99
+ continue: !1
100
+ };
228
101
  }
229
- }
230
- else {
231
- history.push(to);
232
- }
233
- // Render component if routerView exists
234
- if (routerView && to.matched.length > 0) {
102
+ })(to, current, guardLevel);
103
+ if (!guardResult.continue) return !!guardResult.redirectTo && await navigate(guardResult.redirectTo, redirectCount + 1);
104
+ const hashUrl = "#" + fullPath;
105
+ if (replace ? window.location.replace(hashUrl) : window.location.hash = fullPath,
106
+ current = to, replace && history.length > 0 ? history[history.length - 1] = to : history.push(to),
107
+ routerView && to.matched.length > 0) {
235
108
  const route = to.matched[to.matched.length - 1];
236
109
  if (route.component) {
237
110
  const element = await route.component();
238
- routerView.innerHTML = '';
239
- routerView.appendChild(element);
111
+ routerView.innerHTML = "", routerView.appendChild(element);
240
112
  }
241
113
  }
242
- executeAfterHooks(to, history[history.length - 2] ?? null);
243
- return true;
244
- }
245
- catch (error) {
246
- onError(error);
247
- return false;
114
+ return executeAfterHooks(to, history[history.length - 2] ?? null), !0;
115
+ } catch (error) {
116
+ return onError(error), !1;
248
117
  }
249
- };
250
- const executeAfterHooks = async (to, from) => {
118
+ }, executeAfterHooks = async (to, from) => {
251
119
  const targetRoute = to.matched[to.matched.length - 1];
252
- await targetRoute.after(to);
253
- await afterEach(to, from);
254
- };
255
- /**
256
- * Normalize navigation argument
257
- */
258
- const normalizeLocation = (loc) => {
259
- if (typeof loc !== 'string') {
260
- return loc;
261
- }
262
- const [path, queryString] = loc.split('?');
120
+ await targetRoute.after(to), await afterEach(to, from);
121
+ }, normalizeLocation = loc => {
122
+ if ("string" != typeof loc) return loc;
123
+ const [path, queryString] = loc.split("?");
263
124
  return {
264
- path,
265
- query: queryString ? parseQuery(queryString) : undefined,
125
+ path: path,
126
+ query: queryString ? parseQuery(queryString) : void 0
266
127
  };
267
128
  };
268
- // # register events
269
- window.addEventListener('hashchange', () => {
270
- const hash = window.location.hash.slice(1);
271
- const [path] = hash.split('?');
272
- const normalizedPath = normalizePath(path);
273
- if (current && current.path === normalizedPath) {
274
- return;
275
- }
276
- // render route for new hash without adding extra history entry
129
+ window.addEventListener("hashchange", () => {
130
+ const hash = window.location.hash.slice(1), [path] = hash.split("?"), normalizedPath = normalizePath(path);
131
+ if (current && current.path === normalizedPath) return;
277
132
  const matched = match(normalizedPath);
278
- if (!matched) {
279
- onNotFound(normalizedPath);
280
- return;
281
- }
282
- const queryString = window.location.hash.slice(1).split('?')[1];
283
- const to = {
133
+ if (!matched) return void onNotFound(normalizedPath);
134
+ const queryString = window.location.hash.slice(1).split("?")[1], to = {
284
135
  path: normalizedPath,
285
136
  name: matched.route.name,
286
137
  params: matched.params,
287
138
  query: queryString ? parseQuery(queryString) : {},
288
139
  meta: matched.route.meta ?? {},
289
- matched: matched.result,
140
+ matched: matched.result
290
141
  };
291
- // apply without modifying browser history
292
- current = to;
293
- history.push(to);
294
- if (routerView && to.matched.length > 0) {
142
+ if (current = to, history.push(to), routerView && to.matched.length > 0) {
295
143
  const route = to.matched[to.matched.length - 1];
296
144
  if (route.component) {
297
145
  const element = route.component();
298
- if (element instanceof Promise) {
299
- element.then((el) => {
300
- routerView.innerHTML = '';
301
- routerView.appendChild(el);
302
- });
303
- }
304
- else {
305
- routerView.innerHTML = '';
306
- routerView.appendChild(element);
307
- }
146
+ element instanceof Promise ? element.then(el => {
147
+ routerView.innerHTML = "", routerView.appendChild(el);
148
+ }) : (routerView.innerHTML = "", routerView.appendChild(element));
308
149
  }
309
150
  }
310
151
  executeAfterHooks(to, history[history.length - 2] ?? null);
311
152
  });
312
- // # initialize
313
153
  const instance = {
314
154
  get current() {
315
155
  return current;
@@ -326,26 +166,65 @@ const createRouter = ({ beforeEach = $emptyFn, afterEach = $emptyFn, onNotFound
326
166
  },
327
167
  silentPush(location) {
328
168
  const options = normalizeLocation(location);
329
- return navigate({ ...options, guardLevel: 2 /* GuardLevel.Route */ });
169
+ return navigate({
170
+ ...options,
171
+ guardLevel: 2
172
+ });
330
173
  },
331
174
  replace(location) {
332
175
  const options = normalizeLocation(location);
333
- return navigate({ ...options, replace: true });
176
+ return navigate({
177
+ ...options,
178
+ replace: !0
179
+ });
334
180
  },
335
181
  back() {
336
182
  window.history.back();
337
183
  },
338
184
  forward() {
339
185
  window.history.forward();
340
- },
186
+ }
341
187
  };
342
- normalize(rawRoutes, '/');
343
- const { findByName, match } = createMatcher(routes);
344
- const currentHash = window.location.hash.slice(1);
345
- if (currentHash) {
346
- instance.push(currentHash);
347
- }
348
- return instance;
188
+ normalize(rawRoutes, "/");
189
+ const {findByName: findByName, match: match} = (routes => {
190
+ const nameMap = {};
191
+ for (let i = 0; i < routes.length; i++) {
192
+ const route = routes[i];
193
+ if (void 0 !== route.name) {
194
+ if (route.name in nameMap) throw new Error(`[@ktjs/router error] Duplicate route name detected: '${route.name}'`);
195
+ nameMap[route.name] = route;
196
+ }
197
+ }
198
+ const getMatchedChain = route => {
199
+ const matched = [ route ], path = route.path;
200
+ for (let i = 0; i < routes.length; i++) {
201
+ const r = routes[i];
202
+ r !== route && path.startsWith(r.path) && path !== r.path && matched.push(r);
203
+ }
204
+ return matched.reverse();
205
+ };
206
+ return {
207
+ findByName: name => nameMap[name] ?? null,
208
+ match: path => {
209
+ const normalizedPath = normalizePath(path);
210
+ for (const route of routes) if (route.path === normalizedPath) return {
211
+ route: route,
212
+ params: {},
213
+ result: getMatchedChain(route)
214
+ };
215
+ for (const route of routes) if (route.path.includes(":")) {
216
+ const params = extractParams(route.path, normalizedPath);
217
+ if (params) return {
218
+ route: route,
219
+ params: params,
220
+ result: getMatchedChain(route)
221
+ };
222
+ }
223
+ return null;
224
+ }
225
+ };
226
+ })(routes), currentHash = window.location.hash.slice(1);
227
+ return currentHash && instance.push(currentHash), instance;
349
228
  };
350
229
 
351
230
  export { KTRouter, createRouter };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/core/matcher.ts","../src/core/kt-router.ts","../src/core/index.ts"],"sourcesContent":["import type { RouteConfig, RouteMatch } from '../types/router.js';\nimport { extractParams, normalizePath } from '@ktjs/shared';\n\n/**\n * Route matcher for finding matching routes and extracting params\n */\nexport const createMatcher = (routes: RouteConfig[]) => {\n const nameMap: Record<string, RouteConfig> = {};\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i];\n if (route.name !== undefined) {\n if (route.name in nameMap) {\n $throw(`Duplicate route name detected: '${route.name}'`);\n }\n nameMap[route.name] = route;\n }\n }\n\n /**\n * Find route by name\n */\n const findByName = (name: string): RouteConfig | null => {\n return nameMap[name] ?? null;\n };\n\n /**\n * Match path against all routes\n */\n const match = (path: string): RouteMatch | null => {\n const normalizedPath = normalizePath(path);\n\n // Try exact match first\n for (const route of routes) {\n if (route.path === normalizedPath) {\n return {\n route,\n params: {},\n result: getMatchedChain(route),\n };\n }\n }\n\n // Try dynamic routes\n for (const route of routes) {\n if (route.path.includes(':')) {\n const params = extractParams(route.path, normalizedPath);\n if (params) {\n return {\n route,\n params,\n result: getMatchedChain(route),\n };\n }\n }\n }\n\n return null;\n };\n\n /**\n * Get chain of matched routes (for nested routes)\n * - parent roots ahead\n */\n const getMatchedChain = (route: RouteConfig): RouteConfig[] => {\n const matched: RouteConfig[] = [route];\n const path = route.path;\n\n // Find parent routes by path prefix matching\n for (let i = 0; i < routes.length; i++) {\n const r = routes[i];\n if (r !== route && path.startsWith(r.path) && path !== r.path) {\n matched.push(r);\n }\n }\n\n return matched.reverse();\n };\n\n return {\n findByName,\n match,\n };\n};\n","import { JSX } from '@ktjs/core/jsx-runtime';\nimport type { Router } from '../types/router.js';\n\n/**\n * Create a router view container that automatically renders route components\n */\nexport function KTRouter({ router }: { router: Router }): JSX.Element {\n const view = document.createElement('kt-router-view');\n router.setRouterView(view);\n return view as JSX.Element;\n}\n","import { $emptyFn, buildQuery, normalizePath, parseQuery, emplaceParams } from '@ktjs/shared';\n\nimport type { Router, RouterConfig, RouteContext, NavOptions, RawRouteConfig, RouteConfig } from '../types/router.js';\nimport { GuardLevel } from './consts.js';\nimport { createMatcher } from './matcher.js';\n\n/**\n * Create a new router instance\n */\nexport const createRouter = ({\n beforeEach = $emptyFn,\n afterEach = $emptyFn,\n onNotFound = $emptyFn,\n onError = $emptyFn,\n prefix = '',\n routes: rawRoutes,\n}: RouterConfig): Router => {\n // # private values\n const routes: RouteConfig[] = [];\n const history: RouteContext[] = [];\n let routerView: HTMLElement | null = null;\n let current: RouteContext | null = null;\n\n // # methods\n const normalize = (rawRoutes: RawRouteConfig[], parentPath: string): RouteConfig[] =>\n rawRoutes.map((route) => {\n const path = normalizePath(parentPath, route.path);\n const normalized = {\n path: prefix + path,\n name: route.name ?? '',\n meta: route.meta ?? {},\n beforeEnter: route.beforeEnter ?? $emptyFn,\n after: route.after ?? $emptyFn,\n children: route.children ? normalize(route.children, path) : [],\n component: route.component,\n };\n\n // directly push the normalized route to the list\n // avoid flatten them again\n routes.push(normalized);\n return normalized;\n });\n\n const guard = async (\n to: RouteContext,\n from: RouteContext | null,\n guardLevel: GuardLevel,\n ): Promise<{ continue: boolean; redirectTo?: NavOptions }> => {\n try {\n if (guardLevel === GuardLevel.None) {\n return { continue: true };\n }\n\n if (guardLevel & GuardLevel.Global) {\n const result = await beforeEach(to, from);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n if (guardLevel & GuardLevel.Route) {\n const targetRoute = to.matched[to.matched.length - 1];\n const result = await targetRoute.beforeEnter(to);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n return { continue: true };\n } catch (error) {\n onError(error as Error);\n return { continue: false };\n }\n };\n\n const navigatePrepare = (options: NavOptions) => {\n // Resolve target route\n let targetPath: string;\n let targetRoute;\n\n if (options.name) {\n targetRoute = findByName(options.name);\n if (!targetRoute) {\n $throw(`Route not found: ${options.name}`);\n }\n targetPath = targetRoute.path;\n } else if (options.path) {\n targetPath = normalizePath(options.path);\n targetRoute = match(targetPath)?.route;\n } else {\n $throw(`Either path or name must be provided`);\n }\n\n // Substitute params\n if (options.params) {\n targetPath = emplaceParams(targetPath, options.params);\n }\n\n // Match final path\n const matched = match(targetPath);\n if (!matched) {\n onNotFound(targetPath);\n return null;\n }\n\n // Build route context\n const queryString = options.query ? buildQuery(options.query) : '';\n const fullPath = targetPath + queryString;\n\n const to: RouteContext = {\n path: targetPath,\n name: matched.route.name,\n params: { ...matched.params, ...(options.params ?? {}) },\n query: options.query ?? {},\n meta: matched.route.meta ?? {},\n matched: matched.result,\n };\n\n return {\n guardLevel: options.guardLevel ?? GuardLevel.Default,\n replace: options.replace ?? false,\n to,\n fullPath,\n };\n };\n\n const navigate = async (options: NavOptions, redirectCount = 0): Promise<boolean> => {\n try {\n // Prevent infinite redirect loop\n if (redirectCount > 10) {\n onError(new Error('Maximum redirect count exceeded'));\n return false;\n }\n\n const prep = navigatePrepare(options);\n if (!prep) {\n return false;\n }\n\n const { guardLevel, replace, to, fullPath } = prep;\n\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n // Check if there's a redirect\n if (guardResult.redirectTo) {\n return await navigate(guardResult.redirectTo, redirectCount + 1);\n }\n return false;\n }\n\n // ---- Guards passed ----\n\n const hashUrl = '#' + fullPath;\n if (replace) {\n window.location.replace(hashUrl);\n } else {\n window.location.hash = fullPath;\n }\n\n current = to;\n if (replace) {\n if (history.length > 0) {\n history[history.length - 1] = to;\n } else {\n history.push(to);\n }\n } else {\n history.push(to);\n }\n\n // Render component if routerView exists\n if (routerView && to.matched.length > 0) {\n const route = to.matched[to.matched.length - 1];\n if (route.component) {\n const element = await route.component();\n routerView.innerHTML = '';\n routerView.appendChild(element);\n }\n }\n\n executeAfterHooks(to, history[history.length - 2] ?? null);\n return true;\n } catch (error) {\n onError(error as Error);\n return false;\n }\n };\n\n const executeAfterHooks = async (to: RouteContext, from: RouteContext | null): Promise<void> => {\n const targetRoute = to.matched[to.matched.length - 1];\n await targetRoute.after(to);\n await afterEach(to, from);\n };\n\n /**\n * Normalize navigation argument\n */\n const normalizeLocation = (loc: string | NavOptions): NavOptions => {\n if (typeof loc !== 'string') {\n return loc;\n }\n\n const [path, queryString] = loc.split('?');\n return {\n path,\n query: queryString ? parseQuery(queryString) : undefined,\n };\n };\n\n // # register events\n window.addEventListener('hashchange', () => {\n const hash = window.location.hash.slice(1);\n const [path] = hash.split('?');\n const normalizedPath = normalizePath(path);\n if (current && current.path === normalizedPath) {\n return;\n }\n // render route for new hash without adding extra history entry\n const matched = match(normalizedPath);\n if (!matched) {\n onNotFound(normalizedPath);\n return;\n }\n const queryString = window.location.hash.slice(1).split('?')[1];\n const to: RouteContext = {\n path: normalizedPath,\n name: matched.route.name,\n params: matched.params,\n query: queryString ? parseQuery(queryString) : {},\n meta: matched.route.meta ?? {},\n matched: matched.result,\n };\n\n // apply without modifying browser history\n current = to;\n history.push(to);\n\n if (routerView && to.matched.length > 0) {\n const route = to.matched[to.matched.length - 1];\n if (route.component) {\n const element = route.component();\n if (element instanceof Promise) {\n element.then((el) => {\n routerView!.innerHTML = '';\n routerView!.appendChild(el);\n });\n } else {\n routerView.innerHTML = '';\n routerView.appendChild(element);\n }\n }\n }\n\n executeAfterHooks(to, history[history.length - 2] ?? null);\n });\n\n // # initialize\n const instance: Router = {\n get current() {\n return current;\n },\n\n get history() {\n return history.concat();\n },\n\n setRouterView(view: HTMLElement) {\n routerView = view;\n },\n\n push(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate(options);\n },\n\n silentPush(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, guardLevel: GuardLevel.Route });\n },\n\n replace(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, replace: true });\n },\n\n back() {\n window.history.back();\n },\n\n forward() {\n window.history.forward();\n },\n };\n normalize(rawRoutes, '/');\n const { findByName, match } = createMatcher(routes);\n const currentHash = window.location.hash.slice(1);\n if (currentHash) {\n instance.push(currentHash);\n }\n\n return instance;\n};\n\nexport { GuardLevel };\nexport { KTRouter } from './kt-router.js';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/core/kt-router.ts","../src/core/index.ts","../src/core/matcher.ts"],"sourcesContent":["import type { JSX } from '@ktjs/core/jsx-runtime';\nimport type { Router } from '../types/router.js';\n\n/**\n * Create a router view container that automatically renders route components\n */\nexport function KTRouter({ router }: { router: Router }): JSX.Element {\n const view = document.createElement('kt-router-view');\n router.setRouterView(view);\n return view as JSX.Element;\n}\n","import { $emptyFn, buildQuery, normalizePath, parseQuery, emplaceParams } from '@ktjs/shared';\n\nimport type { Router, RouterConfig, RouteContext, NavOptions, RawRouteConfig, RouteConfig } from '../types/router.js';\nimport { GuardLevel } from './consts.js';\nimport { createMatcher } from './matcher.js';\n\n/**\n * Create a new router instance\n */\nexport const createRouter = ({\n beforeEach = $emptyFn,\n afterEach = $emptyFn,\n onNotFound = $emptyFn,\n onError = $emptyFn,\n prefix = '',\n routes: rawRoutes,\n}: RouterConfig): Router => {\n // # private values\n const routes: RouteConfig[] = [];\n const history: RouteContext[] = [];\n let routerView: HTMLElement | null = null;\n let current: RouteContext | null = null;\n\n // # methods\n const normalize = (rawRoutes: RawRouteConfig[], parentPath: string): RouteConfig[] =>\n rawRoutes.map((route) => {\n const path = normalizePath(parentPath, route.path);\n const normalized = {\n path: prefix + path,\n name: route.name ?? '',\n meta: route.meta ?? {},\n beforeEnter: route.beforeEnter ?? $emptyFn,\n after: route.after ?? $emptyFn,\n children: route.children ? normalize(route.children, path) : [],\n component: route.component,\n };\n\n // directly push the normalized route to the list\n // avoid flatten them again\n routes.push(normalized);\n return normalized;\n });\n\n const guard = async (\n to: RouteContext,\n from: RouteContext | null,\n guardLevel: GuardLevel,\n ): Promise<{ continue: boolean; redirectTo?: NavOptions }> => {\n try {\n if (guardLevel === GuardLevel.None) {\n return { continue: true };\n }\n\n if (guardLevel & GuardLevel.Global) {\n const result = await beforeEach(to, from);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n if (guardLevel & GuardLevel.Route) {\n const targetRoute = to.matched[to.matched.length - 1];\n const result = await targetRoute.beforeEnter(to);\n if (result === false) {\n return { continue: false };\n }\n if (typeof result === 'string') {\n return { continue: false, redirectTo: { path: result } };\n }\n if (result && typeof result === 'object') {\n return { continue: false, redirectTo: result };\n }\n }\n\n return { continue: true };\n } catch (error) {\n onError(error as Error);\n return { continue: false };\n }\n };\n\n const navigatePrepare = (options: NavOptions) => {\n // Resolve target route\n let targetPath: string;\n let targetRoute;\n\n if (options.name) {\n targetRoute = findByName(options.name);\n if (!targetRoute) {\n $throw(`Route not found: ${options.name}`);\n }\n targetPath = targetRoute.path;\n } else if (options.path) {\n targetPath = normalizePath(options.path);\n targetRoute = match(targetPath)?.route;\n } else {\n $throw(`Either path or name must be provided`);\n }\n\n // Substitute params\n if (options.params) {\n targetPath = emplaceParams(targetPath, options.params);\n }\n\n // Match final path\n const matched = match(targetPath);\n if (!matched) {\n onNotFound(targetPath);\n return null;\n }\n\n // Build route context\n const queryString = options.query ? buildQuery(options.query) : '';\n const fullPath = targetPath + queryString;\n\n const to: RouteContext = {\n path: targetPath,\n name: matched.route.name,\n params: { ...matched.params, ...(options.params ?? {}) },\n query: options.query ?? {},\n meta: matched.route.meta ?? {},\n matched: matched.result,\n };\n\n return {\n guardLevel: options.guardLevel ?? GuardLevel.Default,\n replace: options.replace ?? false,\n to,\n fullPath,\n };\n };\n\n const navigate = async (options: NavOptions, redirectCount = 0): Promise<boolean> => {\n try {\n // Prevent infinite redirect loop\n if (redirectCount > 10) {\n onError(new Error('Maximum redirect count exceeded'));\n return false;\n }\n\n const prep = navigatePrepare(options);\n if (!prep) {\n return false;\n }\n\n const { guardLevel, replace, to, fullPath } = prep;\n\n const guardResult = await guard(to, current, guardLevel);\n if (!guardResult.continue) {\n // Check if there's a redirect\n if (guardResult.redirectTo) {\n return await navigate(guardResult.redirectTo, redirectCount + 1);\n }\n return false;\n }\n\n // ---- Guards passed ----\n\n const hashUrl = '#' + fullPath;\n if (replace) {\n window.location.replace(hashUrl);\n } else {\n window.location.hash = fullPath;\n }\n\n current = to;\n if (replace) {\n if (history.length > 0) {\n history[history.length - 1] = to;\n } else {\n history.push(to);\n }\n } else {\n history.push(to);\n }\n\n // Render component if routerView exists\n if (routerView && to.matched.length > 0) {\n const route = to.matched[to.matched.length - 1];\n if (route.component) {\n const element = await route.component();\n routerView.innerHTML = '';\n routerView.appendChild(element);\n }\n }\n\n executeAfterHooks(to, history[history.length - 2] ?? null);\n return true;\n } catch (error) {\n onError(error as Error);\n return false;\n }\n };\n\n const executeAfterHooks = async (to: RouteContext, from: RouteContext | null): Promise<void> => {\n const targetRoute = to.matched[to.matched.length - 1];\n await targetRoute.after(to);\n await afterEach(to, from);\n };\n\n /**\n * Normalize navigation argument\n */\n const normalizeLocation = (loc: string | NavOptions): NavOptions => {\n if (typeof loc !== 'string') {\n return loc;\n }\n\n const [path, queryString] = loc.split('?');\n return {\n path,\n query: queryString ? parseQuery(queryString) : undefined,\n };\n };\n\n // # register events\n window.addEventListener('hashchange', () => {\n const hash = window.location.hash.slice(1);\n const [path] = hash.split('?');\n const normalizedPath = normalizePath(path);\n if (current && current.path === normalizedPath) {\n return;\n }\n // render route for new hash without adding extra history entry\n const matched = match(normalizedPath);\n if (!matched) {\n onNotFound(normalizedPath);\n return;\n }\n const queryString = window.location.hash.slice(1).split('?')[1];\n const to: RouteContext = {\n path: normalizedPath,\n name: matched.route.name,\n params: matched.params,\n query: queryString ? parseQuery(queryString) : {},\n meta: matched.route.meta ?? {},\n matched: matched.result,\n };\n\n // apply without modifying browser history\n current = to;\n history.push(to);\n\n if (routerView && to.matched.length > 0) {\n const route = to.matched[to.matched.length - 1];\n if (route.component) {\n const element = route.component();\n if (element instanceof Promise) {\n element.then((el) => {\n routerView!.innerHTML = '';\n routerView!.appendChild(el);\n });\n } else {\n routerView.innerHTML = '';\n routerView.appendChild(element);\n }\n }\n }\n\n executeAfterHooks(to, history[history.length - 2] ?? null);\n });\n\n // # initialize\n const instance: Router = {\n get current() {\n return current;\n },\n\n get history() {\n return history.concat();\n },\n\n setRouterView(view: HTMLElement) {\n routerView = view;\n },\n\n push(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate(options);\n },\n\n silentPush(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, guardLevel: GuardLevel.Route });\n },\n\n replace(location: string | NavOptions): boolean | Promise<boolean> {\n const options = normalizeLocation(location);\n return navigate({ ...options, replace: true });\n },\n\n back() {\n window.history.back();\n },\n\n forward() {\n window.history.forward();\n },\n };\n normalize(rawRoutes, '/');\n const { findByName, match } = createMatcher(routes);\n const currentHash = window.location.hash.slice(1);\n if (currentHash) {\n instance.push(currentHash);\n }\n\n return instance;\n};\n\nexport { GuardLevel };\nexport { KTRouter } from './kt-router.js';\n","import type { RouteConfig, RouteMatch } from '../types/router.js';\nimport { extractParams, normalizePath } from '@ktjs/shared';\n\n/**\n * Route matcher for finding matching routes and extracting params\n */\nexport const createMatcher = (routes: RouteConfig[]) => {\n const nameMap: Record<string, RouteConfig> = {};\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i];\n if (route.name !== undefined) {\n if (route.name in nameMap) {\n $throw(`Duplicate route name detected: '${route.name}'`);\n }\n nameMap[route.name] = route;\n }\n }\n\n /**\n * Find route by name\n */\n const findByName = (name: string): RouteConfig | null => {\n return nameMap[name] ?? null;\n };\n\n /**\n * Match path against all routes\n */\n const match = (path: string): RouteMatch | null => {\n const normalizedPath = normalizePath(path);\n\n // Try exact match first\n for (const route of routes) {\n if (route.path === normalizedPath) {\n return {\n route,\n params: {},\n result: getMatchedChain(route),\n };\n }\n }\n\n // Try dynamic routes\n for (const route of routes) {\n if (route.path.includes(':')) {\n const params = extractParams(route.path, normalizedPath);\n if (params) {\n return {\n route,\n params,\n result: getMatchedChain(route),\n };\n }\n }\n }\n\n return null;\n };\n\n /**\n * Get chain of matched routes (for nested routes)\n * - parent roots ahead\n */\n const getMatchedChain = (route: RouteConfig): RouteConfig[] => {\n const matched: RouteConfig[] = [route];\n const path = route.path;\n\n // Find parent routes by path prefix matching\n for (let i = 0; i < routes.length; i++) {\n const r = routes[i];\n if (r !== route && path.startsWith(r.path) && path !== r.path) {\n matched.push(r);\n }\n }\n\n return matched.reverse();\n };\n\n return {\n findByName,\n match,\n };\n};\n"],"names":["KTRouter","router","view","document","createElement","setRouterView","createRouter","beforeEach","$emptyFn","afterEach","onNotFound","onError","prefix","routes","rawRoutes","history","routerView","current","normalize","parentPath","map","route","path","normalizePath","normalized","name","meta","beforeEnter","after","children","component","push","navigate","async","options","redirectCount","Error","prep","targetPath","targetRoute","findByName","match","params","emplaceParams","matched","fullPath","query","buildQuery","to","result","guardLevel","replace","navigatePrepare","guardResult","from","continue","redirectTo","length","error","guard","hashUrl","window","location","hash","element","innerHTML","appendChild","executeAfterHooks","normalizeLocation","loc","queryString","split","parseQuery","undefined","addEventListener","slice","normalizedPath","Promise","then","el","instance","concat","silentPush","back","forward","nameMap","i","getMatchedChain","r","startsWith","reverse","includes","extractParams","createMatcher","currentHash"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/router",
3
- "version": "0.32.5",
3
+ "version": "0.33.1",
4
4
  "description": "Router for kt.js - client-side routing with navigation guards",
5
5
  "description_zh": "kt.js 的路由库,支持前端路由与导航守卫。",
6
6
  "type": "module",