apprun 4.0.0 → 6.0.0-rc.0

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.
Files changed (135) hide show
  1. package/CHANGELOG.md +235 -12
  2. package/LICENSE +1 -1
  3. package/README.md +225 -110
  4. package/apprun.d.ts +240 -34
  5. package/cli/app.js +29 -0
  6. package/cli/colors.js +69 -0
  7. package/cli/index.html +13 -0
  8. package/cli/index.js +96 -0
  9. package/dist/apprun-code.js +2 -0
  10. package/dist/apprun-code.js.map +1 -0
  11. package/dist/apprun-dev-tools.js +1 -1
  12. package/dist/apprun-dev-tools.js.map +1 -1
  13. package/dist/apprun-html.esm.js +34 -0
  14. package/dist/apprun-html.esm.js.map +1 -0
  15. package/dist/apprun-html.js +2 -1
  16. package/dist/apprun-html.js.LICENSE.txt +11 -0
  17. package/dist/apprun-html.js.map +1 -1
  18. package/dist/apprun-play.js +2 -0
  19. package/dist/apprun-play.js.map +1 -0
  20. package/dist/apprun.esm.js +2 -0
  21. package/dist/apprun.esm.js.map +1 -0
  22. package/dist/apprun.js +1 -1
  23. package/dist/apprun.js.map +1 -1
  24. package/dist/createState.js +2 -0
  25. package/dist/createState.js.map +1 -0
  26. package/esm/add-components.js +90 -0
  27. package/esm/add-components.js.map +1 -0
  28. package/esm/app.js +209 -0
  29. package/esm/app.js.map +1 -0
  30. package/esm/apprun-code.js +170 -0
  31. package/esm/apprun-code.js.map +1 -0
  32. package/esm/apprun-dev-tools-tests.js +95 -0
  33. package/esm/apprun-dev-tools-tests.js.map +1 -0
  34. package/esm/apprun-dev-tools.js +281 -0
  35. package/esm/apprun-dev-tools.js.map +1 -0
  36. package/esm/apprun-html.js +24 -0
  37. package/esm/apprun-html.js.map +1 -0
  38. package/esm/apprun-play.js +248 -0
  39. package/esm/apprun-play.js.map +1 -0
  40. package/esm/apprun.js +220 -0
  41. package/esm/apprun.js.map +1 -0
  42. package/esm/component.js +413 -0
  43. package/esm/component.js.map +1 -0
  44. package/esm/createState.js +9 -0
  45. package/esm/createState.js.map +1 -0
  46. package/esm/decorator.js +88 -0
  47. package/esm/decorator.js.map +1 -0
  48. package/esm/directive.js +306 -0
  49. package/esm/directive.js.map +1 -0
  50. package/esm/router.js +345 -0
  51. package/esm/router.js.map +1 -0
  52. package/esm/type-utils.js +90 -0
  53. package/esm/type-utils.js.map +1 -0
  54. package/esm/types.js +58 -0
  55. package/esm/types.js.map +1 -0
  56. package/esm/vdom-lit-html.js +65 -0
  57. package/esm/vdom-lit-html.js.map +1 -0
  58. package/esm/vdom-my-prop-attr.js +227 -0
  59. package/esm/vdom-my-prop-attr.js.map +1 -0
  60. package/esm/vdom-my.js +293 -0
  61. package/esm/vdom-my.js.map +1 -0
  62. package/esm/vdom-to-html.js +54 -0
  63. package/esm/vdom-to-html.js.map +1 -0
  64. package/esm/vdom.js +28 -0
  65. package/esm/vdom.js.map +1 -0
  66. package/esm/version.js +15 -0
  67. package/esm/version.js.map +1 -0
  68. package/esm/web-component.js +155 -0
  69. package/esm/web-component.js.map +1 -0
  70. package/jsx-runtime.js +2 -0
  71. package/jsx-runtime.js.map +1 -0
  72. package/package.json +90 -41
  73. package/.travis.yml +0 -10
  74. package/.vscode/launch.json +0 -19
  75. package/BACKERS.md +0 -3
  76. package/apprun-cli.js +0 -177
  77. package/cli-templates/_gitignore +0 -6
  78. package/cli-templates/component.ts_ +0 -16
  79. package/cli-templates/index.html +0 -11
  80. package/cli-templates/karma.conf.js +0 -24
  81. package/cli-templates/main.ts_ +0 -13
  82. package/cli-templates/readme.md +0 -7
  83. package/cli-templates/spa_index.html +0 -14
  84. package/cli-templates/spa_main.ts_ +0 -47
  85. package/cli-templates/spec.ts_ +0 -11
  86. package/cli-templates/tsconfig.json +0 -12
  87. package/cli-templates/webpack.config.js +0 -23
  88. package/demo-html/app.js +0 -2
  89. package/demo-html/app.js.map +0 -1
  90. package/demo-html/counter-c.html +0 -29
  91. package/demo-html/counter-wc-event.html +0 -29
  92. package/demo-html/counter-wc.html +0 -29
  93. package/demo-html/counter.html +0 -26
  94. package/demo-html/index.html +0 -14
  95. package/demo-html/main.tsx +0 -31
  96. package/docs/README.md +0 -326
  97. package/docs/index.html +0 -23
  98. package/index.html +0 -85
  99. package/logo.png +0 -0
  100. package/src/app.ts +0 -69
  101. package/src/apprun-dev-tools.tsx +0 -67
  102. package/src/apprun-html.ts +0 -13
  103. package/src/apprun.ts +0 -53
  104. package/src/component.ts +0 -189
  105. package/src/createComponent.tsx +0 -38
  106. package/src/decorator.ts +0 -36
  107. package/src/router.ts +0 -19
  108. package/src/types.ts +0 -9
  109. package/src/vdom-html.ts +0 -17
  110. package/src/vdom-my.ts +0 -191
  111. package/src/vdom-to-html.tsx +0 -45
  112. package/src/vdom.ts +0 -7
  113. package/src/web-component.ts +0 -29
  114. package/tests/app-rx.spec_ +0 -41
  115. package/tests/app.spec.ts +0 -122
  116. package/tests/application.spec.tsx +0 -23
  117. package/tests/component.spec.tsx +0 -296
  118. package/tests/custom-element.spec.tsx +0 -19
  119. package/tests/data-attr.spec.tsx +0 -42
  120. package/tests/decorator.spec.tsx +0 -104
  121. package/tests/fragment.spec.tsx +0 -79
  122. package/tests/hyperscript.spec.ts +0 -43
  123. package/tests/node-test.js +0 -7
  124. package/tests/router.spec.ts +0 -69
  125. package/tests/stateful-component.spec.tsx +0 -248
  126. package/tests/typed.spec.tsx +0 -63
  127. package/tests/vdom-html.spec.ts +0 -35
  128. package/tests/vdom-jsx.spec.tsx +0 -131
  129. package/tests/vdom-my.spec.tsx +0 -195
  130. package/tests/view-engine.spec.js +0 -59
  131. package/tsconfig.json +0 -11
  132. package/tslint.json +0 -124
  133. package/typescriptreact.json +0 -87
  134. package/viewEngine.js +0 -54
  135. package/webpack.config.js +0 -30
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Component Directives Implementation
3
+ *
4
+ * This file provides built-in directives for components:
5
+ * 1. Event Binding ($on directives)
6
+ * - $on: Bind DOM events to component events
7
+ * - Supports event delegation and parameters
8
+ * - Handles function, string, and array event handlers
9
+ * - Type-safe event target handling
10
+ *
11
+ * 2. Two-way Data Binding ($bind directive)
12
+ * - $bind: Sync form elements with component state
13
+ * - Handles input types: text, checkbox, radio, number, range
14
+ * - Supports select (single/multiple) and textarea elements
15
+ * - Automatic value type conversion for numbers
16
+ * - Support for complex property paths
17
+ *
18
+ * 3. Custom Directives
19
+ * - Extensible directive system via '$' events
20
+ * - Processes virtual DOM during rendering
21
+ * - Supports custom attribute directives
22
+ *
23
+ * Features:
24
+ * - Automatic state synchronization
25
+ * - Type conversion for form inputs
26
+ * - Event delegation support
27
+ * - Multiple event handler formats
28
+ * - Nested property binding
29
+ * - Custom directive extensibility
30
+ *
31
+ * Type Safety Improvements (v3.35.1):
32
+ * - Added null checks for event targets before type assertions
33
+ * - Proper typing for different HTML element types
34
+ * - Enhanced error handling for invalid event targets
35
+ * - Safer DOM element property access
36
+ *
37
+ * Nested State Binding Support (v3.37.4):
38
+ * - Enhanced $bind directive to support nested object and array paths
39
+ * - Supports dot notation: 'user.name', 'user.profile.settings.theme'
40
+ * - Supports bracket notation: 'items[0]', 'users[1].name'
41
+ * - Supports mixed notation: 'users[0].settings.theme', 'data["key"].value'
42
+ * - Safe traversal with automatic intermediate object/array creation
43
+ * - Maintains backward compatibility with simple property binding
44
+ *
45
+ * Usage:
46
+ * ```tsx
47
+ * // Event binding
48
+ * <button $onclick="event-name">Click</button>
49
+ * <input $oninput={e => setState(e.target.value)} />
50
+ *
51
+ * // Simple two-way binding
52
+ * <input $bind="state.property" />
53
+ * <select $bind="selected">...</select>
54
+ *
55
+ * // Nested object binding
56
+ * <input $bind="user.profile.name" />
57
+ * <input $bind="user.settings.theme" />
58
+ *
59
+ * // Array element binding
60
+ * <input $bind="items[0]" />
61
+ * <input $bind="todos[1].title" />
62
+ *
63
+ * // Mixed nested binding
64
+ * <input $bind="users[0].profile.settings.notifications.email" />
65
+ * <select $bind="config.display.mode">...</select>
66
+ *
67
+ * // Array handlers
68
+ * <button $onclick={['handler', param1, param2]}>Click</button>
69
+ * ```
70
+ */
71
+ import app from './app';
72
+ import { safeEventTarget } from './type-utils';
73
+ /**
74
+ * Parse a path string into an array of keys and indices
75
+ * Supports paths like: 'a.b', 'a[0]', 'a[0].b', 'a["key"]'
76
+ */
77
+ const parsePath = (path) => {
78
+ if (!path)
79
+ return [];
80
+ const keys = [];
81
+ let current = '';
82
+ let inBracket = false;
83
+ let quoteChar = '';
84
+ for (let i = 0; i < path.length; i++) {
85
+ const char = path[i];
86
+ if (char === '[' && !inBracket) {
87
+ if (current) {
88
+ keys.push(current);
89
+ current = '';
90
+ }
91
+ inBracket = true;
92
+ }
93
+ else if (char === ']' && inBracket) {
94
+ if (quoteChar) {
95
+ // Remove quotes from string keys
96
+ current = current.slice(1, -1);
97
+ }
98
+ else if (/^\d+$/.test(current)) {
99
+ // Convert numeric strings to numbers
100
+ current = parseInt(current, 10);
101
+ }
102
+ keys.push(current);
103
+ current = '';
104
+ inBracket = false;
105
+ quoteChar = '';
106
+ }
107
+ else if ((char === '"' || char === "'") && inBracket) {
108
+ if (!quoteChar) {
109
+ quoteChar = char;
110
+ }
111
+ else if (char === quoteChar) {
112
+ quoteChar = '';
113
+ }
114
+ current += char;
115
+ }
116
+ else if (char === '.' && !inBracket) {
117
+ if (current) {
118
+ keys.push(current);
119
+ current = '';
120
+ }
121
+ }
122
+ else {
123
+ current += char;
124
+ }
125
+ }
126
+ if (current) {
127
+ keys.push(current);
128
+ }
129
+ return keys;
130
+ };
131
+ /**
132
+ * Safely get a nested value from an object using a path
133
+ */
134
+ const getNestedValue = (obj, path) => {
135
+ let current = obj;
136
+ for (const key of path) {
137
+ if (current == null)
138
+ return undefined;
139
+ current = current[key];
140
+ }
141
+ return current;
142
+ };
143
+ /**
144
+ * Safely set a nested value in an object using a path
145
+ * Creates intermediate objects/arrays as needed
146
+ */
147
+ const setNestedValue = (obj, path, value) => {
148
+ if (path.length === 0)
149
+ return value;
150
+ const result = { ...obj };
151
+ let current = result;
152
+ for (let i = 0; i < path.length - 1; i++) {
153
+ const key = path[i];
154
+ const nextKey = path[i + 1];
155
+ if (current[key] == null) {
156
+ // Create array if next key is numeric, object otherwise
157
+ current[key] = typeof nextKey === 'number' ? [] : {};
158
+ }
159
+ else if (Array.isArray(current[key])) {
160
+ current[key] = [...current[key]];
161
+ }
162
+ else if (typeof current[key] === 'object') {
163
+ current[key] = { ...current[key] };
164
+ }
165
+ current = current[key];
166
+ }
167
+ current[path[path.length - 1]] = value;
168
+ return result;
169
+ };
170
+ const getStateValue = (component, name) => {
171
+ if (!name)
172
+ return component['state'] || '';
173
+ const path = parsePath(name);
174
+ const value = getNestedValue(component['state'], path);
175
+ return value !== undefined ? value : '';
176
+ };
177
+ const setStateValue = (component, name, value) => {
178
+ if (!name) {
179
+ component.setState(value);
180
+ return;
181
+ }
182
+ const path = parsePath(name);
183
+ const currentState = component['state'] || {};
184
+ const newState = setNestedValue(currentState, path, value);
185
+ component.setState(newState);
186
+ };
187
+ const apply_directive = (key, props, tag, component) => {
188
+ if (key.startsWith('$on')) {
189
+ const event = props[key];
190
+ key = key.substring(1);
191
+ if (typeof event === 'boolean') {
192
+ props[key] = e => component.run ? component.run(key, e) : app.run(key, e);
193
+ }
194
+ else if (typeof event === 'string') {
195
+ props[key] = e => component.run ? component.run(event, e) : app.run(event, e);
196
+ }
197
+ else if (typeof event === 'function') {
198
+ props[key] = e => component.setState(event(component.state, e));
199
+ }
200
+ else if (Array.isArray(event)) {
201
+ const [handler, ...p] = event;
202
+ if (typeof handler === 'string') {
203
+ props[key] = e => component.run ? component.run(handler, ...p, e) : app.run(handler, ...p, e);
204
+ }
205
+ else if (typeof handler === 'function') {
206
+ props[key] = e => component.setState(handler(component.state, ...p, e));
207
+ }
208
+ }
209
+ }
210
+ else if (key === '$bind') {
211
+ const type = props['type'] || 'text';
212
+ const name = typeof props[key] === 'string' ? props[key] : props['name'];
213
+ if (tag === 'input') {
214
+ switch (type) {
215
+ case 'checkbox':
216
+ props['checked'] = getStateValue(component, name);
217
+ props['onclick'] = e => {
218
+ const target = safeEventTarget(e);
219
+ if (target) {
220
+ setStateValue(component, name || target.name, target.checked);
221
+ }
222
+ };
223
+ break;
224
+ case 'radio':
225
+ props['checked'] = getStateValue(component, name) === props['value'];
226
+ props['onclick'] = e => {
227
+ const target = safeEventTarget(e);
228
+ if (target) {
229
+ setStateValue(component, name || target.name, target.value);
230
+ }
231
+ };
232
+ break;
233
+ case 'number':
234
+ case 'range':
235
+ props['value'] = getStateValue(component, name);
236
+ props['oninput'] = e => {
237
+ const target = safeEventTarget(e);
238
+ if (target) {
239
+ setStateValue(component, name || target.name, Number(target.value));
240
+ }
241
+ };
242
+ break;
243
+ default:
244
+ props['value'] = getStateValue(component, name);
245
+ props['oninput'] = e => {
246
+ const target = safeEventTarget(e);
247
+ if (target) {
248
+ setStateValue(component, name || target.name, target.value);
249
+ }
250
+ };
251
+ }
252
+ }
253
+ else if (tag === 'select') {
254
+ props['value'] = getStateValue(component, name);
255
+ props['onchange'] = e => {
256
+ const target = safeEventTarget(e);
257
+ if (target && !target.multiple) { // multiple selection use $bind on option
258
+ setStateValue(component, name || target.name, target.value);
259
+ }
260
+ };
261
+ }
262
+ else if (tag === 'option') {
263
+ props['selected'] = getStateValue(component, name);
264
+ props['onclick'] = e => {
265
+ const target = safeEventTarget(e);
266
+ if (target) {
267
+ setStateValue(component, name || target.name, target.selected);
268
+ }
269
+ };
270
+ }
271
+ else if (tag === 'textarea') {
272
+ props['value'] = getStateValue(component, name);
273
+ props['oninput'] = e => {
274
+ const target = safeEventTarget(e);
275
+ if (target) {
276
+ setStateValue(component, name || target.name, target.value);
277
+ }
278
+ };
279
+ }
280
+ }
281
+ else {
282
+ app.run('$', { key, tag, props, component });
283
+ }
284
+ };
285
+ const directive = (vdom, component) => {
286
+ if (Array.isArray(vdom)) {
287
+ return vdom.map(element => directive(element, component));
288
+ }
289
+ else {
290
+ let { type, tag, props, children } = vdom;
291
+ tag = tag || type;
292
+ children = children || props?.children;
293
+ if (props)
294
+ Object.keys(props).forEach(key => {
295
+ if (key.startsWith('$')) {
296
+ apply_directive(key, props, tag, component);
297
+ delete props[key];
298
+ }
299
+ });
300
+ if (children)
301
+ directive(children, component);
302
+ return vdom;
303
+ }
304
+ };
305
+ export default directive;
306
+ //# sourceMappingURL=directive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directive.js","sourceRoot":"","sources":["../src/directive.ts"],"names":[],"mappings":"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"}
package/esm/router.js ADDED
@@ -0,0 +1,345 @@
1
+ /**
2
+ * AppRun Router Implementation with Hierarchical Matching
3
+ *
4
+ * This file provides URL routing capabilities:
5
+ * 1. Hash-based routing (#/path)
6
+ * - Works with SPA mode using hash fragments
7
+ * - Handles hashchange events automatically
8
+ * - No server configuration required
9
+ * 2. Path-based routing (/path)
10
+ * - Works with browser history API
11
+ * - Requires server configuration for SPA routing
12
+ * - Handles popstate events automatically
13
+ * 3. Event-based navigation
14
+ * - Routes trigger corresponding component events
15
+ * - Automatic route parameter extraction
16
+ * - Fallback to 404 handling for unknown routes
17
+ *
18
+ * Features:
19
+ * - Automatic route event firing with ROUTER_EVENT
20
+ * - 404 handling via ROUTER_404_EVENT for unmatched routes
21
+ * - History API integration for seamless navigation
22
+ * - Route parameter parsing and injection into events
23
+ * - URL pattern matching with :param and * rest support
24
+ * - Global and component-level route handling
25
+ * - **NEW: Hierarchical route matching** - progressively tries parent routes
26
+ * - 2026-06-19: Added :param and * route-pattern matching before hierarchical fallback
27
+ *
28
+ * Type Safety Improvements (v3.35.1):
29
+ * - Enhanced route type definitions
30
+ * - Better parameter type inference
31
+ * - Improved URL validation and error handling
32
+ *
33
+ * Usage:
34
+ * ```ts
35
+ * // Basic routing
36
+ * app.on('#/home', () => // Show home page);
37
+ * app.on('#/users/:id', (id) => // Show user profile);
38
+ * app.on('/api/*', (path) => // Handle API routes);
39
+ *
40
+ * // Navigate programmatically
41
+ * app.run('route', '#/home');
42
+ * route('/users/123'); // Direct routing
43
+ *
44
+ * // Hierarchical matching examples
45
+ * app.on('/api', (operation, id) => // Handle /api/users/123);
46
+ * app.on('#users', (id, action) => // Handle #users/123/edit);
47
+ *
48
+ * // Hierarchical Route Matching (NEW):
49
+ * // For URL: /api/v1/users/123
50
+ * // Router tries: /api/v1/users/123 → /api/v1/users → /api/v1 → /api → 404
51
+ * // If handler found at /api, it receives: ('v1', 'users', '123')
52
+ *
53
+ * // Base Path Support (NEW):
54
+ * app.basePath = '/myapp'; // For sub-directory deployments
55
+ * // Links: <a href="/users/123"> (relative paths)
56
+ * // Navigation: /myapp/users/123 (full path)
57
+ * // Routing: /users/123 (base path stripped)
58
+ *
59
+ * // Empty Path Handling (NEW):
60
+ * // For URL: "" (empty)
61
+ * // Router tries: # → / → #/ → 404 (in priority order)
62
+ *
63
+ * // 404 Behavior (ENHANCED):
64
+ * // Fires only at minimal levels: /a, #a, #/a, a
65
+ * // Never tries root handlers: /, #, #/
66
+ * ```
67
+ */
68
+ import app from './app';
69
+ // Helper functions for hierarchical routing
70
+ /**
71
+ * Extract clean path segments from URL
72
+ * @param url - The URL to parse
73
+ * @returns Array of path segments
74
+ */
75
+ function parsePathSegments(url) {
76
+ if (!url)
77
+ return [];
78
+ // Handle different URL types
79
+ if (url.startsWith('#/')) {
80
+ return url.substring(2).split('/');
81
+ }
82
+ else if (url.startsWith('#')) {
83
+ return url.substring(1).split('/');
84
+ }
85
+ else if (url.startsWith('/')) {
86
+ return url.substring(1).split('/');
87
+ }
88
+ else {
89
+ return url.split('/');
90
+ }
91
+ }
92
+ /**
93
+ * Normalize trailing slash - convert /a/ to /a
94
+ * @param url - The URL to normalize
95
+ * @returns Normalized URL
96
+ */
97
+ function normalizeTrailingSlash(url) {
98
+ if (!url || url === '/' || url === '#' || url === '#/')
99
+ return url;
100
+ if (url.endsWith('/'))
101
+ return url.slice(0, -1);
102
+ return url;
103
+ }
104
+ /**
105
+ * Validate hierarchy depth and warn if too deep
106
+ * @param segments - Path segments to validate
107
+ */
108
+ function validateHierarchyDepth(segments) {
109
+ // Count non-empty segments for depth validation
110
+ const nonEmptySegments = segments.filter(Boolean);
111
+ if (nonEmptySegments.length > 11) {
112
+ console.warn(`Deep route hierarchy detected: ${nonEmptySegments.join('/')} (${nonEmptySegments.length} levels)`);
113
+ }
114
+ }
115
+ /**
116
+ * Strip base path from URL
117
+ * @param url - The URL to process
118
+ * @param basePath - The base path to remove
119
+ * @returns URL with base path removed
120
+ */
121
+ function stripBasePath(url, basePath) {
122
+ if (!basePath || basePath === '/' || basePath === '')
123
+ return url;
124
+ // Normalize base path
125
+ const normalizedBasePath = basePath.startsWith('/') ? basePath : '/' + basePath;
126
+ if (url.startsWith(normalizedBasePath)) {
127
+ const stripped = url.substring(normalizedBasePath.length);
128
+ return stripped.startsWith('/') ? stripped : '/' + stripped;
129
+ }
130
+ return url;
131
+ }
132
+ /**
133
+ * Generate hierarchy of routes to try (stops at minimal level)
134
+ * @param segments - Array of path segments
135
+ * @param routeType - Type of route (path, hash, hash-slash, non-prefixed)
136
+ * @returns Array of route names to try in order
137
+ */
138
+ function generateRouteHierarchy(segments, routeType) {
139
+ const hierarchy = [];
140
+ // Build hierarchy from most specific to least specific
141
+ for (let i = segments.length; i > 0; i--) {
142
+ const currentSegments = segments.slice(0, i);
143
+ let routeName = '';
144
+ switch (routeType) {
145
+ case 'path':
146
+ routeName = '/' + currentSegments.join('/');
147
+ break;
148
+ case 'hash':
149
+ routeName = '#' + currentSegments.join('/');
150
+ break;
151
+ case 'hash-slash':
152
+ routeName = '#/' + currentSegments.join('/');
153
+ break;
154
+ case 'non-prefixed':
155
+ routeName = currentSegments.join('/');
156
+ break;
157
+ }
158
+ hierarchy.push(routeName);
159
+ }
160
+ return hierarchy;
161
+ }
162
+ function getRouteType(url) {
163
+ if (url.startsWith('#/'))
164
+ return 'hash-slash';
165
+ if (url.startsWith('#'))
166
+ return 'hash';
167
+ if (url.startsWith('/'))
168
+ return 'path';
169
+ return 'non-prefixed';
170
+ }
171
+ function isPatternRoute(routeName) {
172
+ return parsePathSegments(routeName).some(segment => segment === '*' || segment.startsWith(':'));
173
+ }
174
+ function matchPatternRoute(pattern, routeType, segments) {
175
+ if (getRouteType(pattern) !== routeType || !isPatternRoute(pattern))
176
+ return null;
177
+ const patternSegments = parsePathSegments(pattern);
178
+ const parameters = [];
179
+ let staticSegments = 0;
180
+ for (let i = 0; i < patternSegments.length; i++) {
181
+ const patternSegment = patternSegments[i];
182
+ if (patternSegment === '*') {
183
+ parameters.push(segments.slice(i).join('/'));
184
+ return {
185
+ eventName: pattern,
186
+ parameters,
187
+ score: staticSegments * 10 + patternSegments.length
188
+ };
189
+ }
190
+ const segment = segments[i];
191
+ if (segment === undefined)
192
+ return null;
193
+ if (patternSegment.startsWith(':')) {
194
+ parameters.push(segment);
195
+ }
196
+ else if (patternSegment === segment) {
197
+ staticSegments++;
198
+ }
199
+ else {
200
+ return null;
201
+ }
202
+ }
203
+ if (patternSegments.length !== segments.length)
204
+ return null;
205
+ return {
206
+ eventName: pattern,
207
+ parameters,
208
+ score: staticSegments * 10 + patternSegments.length
209
+ };
210
+ }
211
+ function findPatternHandler(routeType, segments) {
212
+ const matches = Object.keys(app['_events'] || {})
213
+ .map(routeName => matchPatternRoute(routeName, routeType, segments))
214
+ .filter(Boolean)
215
+ .sort((a, b) => b.score - a.score || b.eventName.length - a.eventName.length);
216
+ return matches.length > 0 ? {
217
+ eventName: matches[0].eventName,
218
+ parameters: matches[0].parameters
219
+ } : null;
220
+ }
221
+ /**
222
+ * Find handler in hierarchy and return handler info
223
+ * @param hierarchy - Array of route names to try
224
+ * @param originalSegments - Original path segments
225
+ * @returns Handler info if found, null otherwise
226
+ */
227
+ function findHandlerInHierarchy(hierarchy, originalSegments) {
228
+ for (let i = 0; i < hierarchy.length; i++) {
229
+ const routeName = hierarchy[i];
230
+ const subscribers = app.find(routeName);
231
+ if (subscribers && subscribers.length > 0) {
232
+ // Found handler - calculate remaining parameters
233
+ const handlerDepth = hierarchy.length - i;
234
+ const parameters = originalSegments.slice(handlerDepth);
235
+ return {
236
+ eventName: routeName,
237
+ parameters: parameters
238
+ };
239
+ }
240
+ }
241
+ return null;
242
+ }
243
+ /**
244
+ * Handle empty path with priority order: # → / → #/ → 404
245
+ */
246
+ function handleEmptyPath() {
247
+ // Try # first
248
+ const hashSubscribers = app.find('#');
249
+ if (hashSubscribers && hashSubscribers.length > 0) {
250
+ app.run('#');
251
+ app.run(ROUTER_EVENT, '#');
252
+ return;
253
+ }
254
+ // Try / second
255
+ const pathSubscribers = app.find('/');
256
+ if (pathSubscribers && pathSubscribers.length > 0) {
257
+ app.run('/');
258
+ app.run(ROUTER_EVENT, '/');
259
+ return;
260
+ }
261
+ // Try #/ third
262
+ const hashSlashSubscribers = app.find('#/');
263
+ if (hashSlashSubscribers && hashSlashSubscribers.length > 0) {
264
+ app.run('#/');
265
+ app.run(ROUTER_EVENT, '#/');
266
+ return;
267
+ }
268
+ // Fire 404 if no handlers found
269
+ if (app['debug'])
270
+ console.warn('No subscribers for event: ');
271
+ app.run(ROUTER_404_EVENT, '');
272
+ app.run(ROUTER_EVENT, '');
273
+ }
274
+ /**
275
+ * Main hierarchical routing logic
276
+ * @param url - The URL to route
277
+ */
278
+ function routeWithHierarchy(url) {
279
+ // Handle empty path
280
+ if (!url) {
281
+ handleEmptyPath();
282
+ return;
283
+ }
284
+ // Normalize trailing slash
285
+ url = normalizeTrailingSlash(url);
286
+ // Strip base path if configured
287
+ const basePath = app['basePath'];
288
+ if (basePath) {
289
+ url = stripBasePath(url, basePath);
290
+ }
291
+ // Parse segments and validate depth
292
+ const segments = parsePathSegments(url);
293
+ validateHierarchyDepth(segments);
294
+ // Determine route type
295
+ const routeType = getRouteType(url);
296
+ // Generate hierarchy
297
+ const hierarchy = generateRouteHierarchy(segments, routeType);
298
+ const exactRoute = hierarchy[0];
299
+ const exactSubscribers = app.find(exactRoute);
300
+ const handlerInfo = exactSubscribers && exactSubscribers.length > 0 ?
301
+ { eventName: exactRoute, parameters: [] } :
302
+ findPatternHandler(routeType, segments) || findHandlerInHierarchy(hierarchy.slice(1), segments);
303
+ if (handlerInfo) {
304
+ // Found handler - publish route with parameters
305
+ publishRoute(handlerInfo.eventName, ...handlerInfo.parameters);
306
+ }
307
+ else {
308
+ // No handler found - fire 404 with original URL
309
+ if (hierarchy.length > 0) {
310
+ const minimalRoute = hierarchy[hierarchy.length - 1];
311
+ if (app['debug'])
312
+ console.warn(`No subscribers for event: ${minimalRoute}`);
313
+ app.run(ROUTER_404_EVENT, url);
314
+ app.run(ROUTER_EVENT, url);
315
+ }
316
+ else {
317
+ handleEmptyPath();
318
+ }
319
+ }
320
+ }
321
+ const publishRoute = (name, ...args) => {
322
+ if (!name || name === ROUTER_EVENT || name === ROUTER_404_EVENT)
323
+ return;
324
+ const subscribers = app.find(name);
325
+ if (!subscribers || subscribers.length === 0) {
326
+ if (app['debug'])
327
+ console.warn(`No subscribers for event: ${name}`);
328
+ app.run(ROUTER_404_EVENT, name, ...args);
329
+ }
330
+ else {
331
+ app.run(name, ...args);
332
+ }
333
+ app.run(ROUTER_EVENT, name, ...args);
334
+ };
335
+ export const ROUTER_EVENT = '//';
336
+ export const ROUTER_404_EVENT = '///';
337
+ export const route = (url) => {
338
+ if (app['lastUrl'] === url)
339
+ return; // Prevent duplicate routing
340
+ app['lastUrl'] = url;
341
+ // Use hierarchical routing logic
342
+ routeWithHierarchy(url);
343
+ };
344
+ export default route;
345
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}