zero-query 0.6.3 → 0.8.6
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 +39 -29
- package/cli/commands/build.js +113 -4
- package/cli/commands/bundle.js +392 -29
- package/cli/commands/create.js +1 -1
- package/cli/commands/dev/devtools/index.js +56 -0
- package/cli/commands/dev/devtools/js/components.js +49 -0
- package/cli/commands/dev/devtools/js/core.js +409 -0
- package/cli/commands/dev/devtools/js/elements.js +413 -0
- package/cli/commands/dev/devtools/js/network.js +166 -0
- package/cli/commands/dev/devtools/js/performance.js +73 -0
- package/cli/commands/dev/devtools/js/router.js +105 -0
- package/cli/commands/dev/devtools/js/source.js +132 -0
- package/cli/commands/dev/devtools/js/stats.js +35 -0
- package/cli/commands/dev/devtools/js/tabs.js +79 -0
- package/cli/commands/dev/devtools/panel.html +95 -0
- package/cli/commands/dev/devtools/styles.css +244 -0
- package/cli/commands/dev/index.js +29 -4
- package/cli/commands/dev/logger.js +6 -1
- package/cli/commands/dev/overlay.js +428 -2
- package/cli/commands/dev/server.js +42 -5
- package/cli/commands/dev/watcher.js +59 -1
- package/cli/help.js +8 -5
- package/cli/scaffold/{scripts → app}/app.js +16 -23
- package/cli/scaffold/{scripts → app}/components/about.js +4 -4
- package/cli/scaffold/{scripts → app}/components/api-demo.js +1 -1
- package/cli/scaffold/{scripts → app}/components/contacts/contacts.css +0 -7
- package/cli/scaffold/{scripts → app}/components/contacts/contacts.html +3 -3
- package/cli/scaffold/app/components/home.js +137 -0
- package/cli/scaffold/{scripts → app}/routes.js +1 -1
- package/cli/scaffold/{scripts → app}/store.js +6 -6
- package/cli/scaffold/assets/.gitkeep +0 -0
- package/cli/scaffold/{styles/styles.css → global.css} +4 -2
- package/cli/scaffold/index.html +12 -11
- package/cli/utils.js +111 -6
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +1122 -158
- package/dist/zquery.min.js +3 -16
- package/index.d.ts +129 -1290
- package/index.js +15 -10
- package/package.json +7 -6
- package/src/component.js +172 -49
- package/src/core.js +359 -18
- package/src/diff.js +256 -58
- package/src/expression.js +33 -3
- package/src/reactive.js +37 -5
- package/src/router.js +243 -7
- package/tests/component.test.js +886 -0
- package/tests/core.test.js +977 -0
- package/tests/diff.test.js +525 -0
- package/tests/errors.test.js +162 -0
- package/tests/expression.test.js +482 -0
- package/tests/http.test.js +289 -0
- package/tests/reactive.test.js +339 -0
- package/tests/router.test.js +649 -0
- package/tests/store.test.js +379 -0
- package/tests/utils.test.js +512 -0
- package/types/collection.d.ts +383 -0
- package/types/component.d.ts +217 -0
- package/types/errors.d.ts +103 -0
- package/types/http.d.ts +81 -0
- package/types/misc.d.ts +179 -0
- package/types/reactive.d.ts +76 -0
- package/types/router.d.ts +161 -0
- package/types/ssr.d.ts +49 -0
- package/types/store.d.ts +107 -0
- package/types/utils.d.ts +142 -0
- package/cli/commands/dev.old.js +0 -520
- package/cli/scaffold/scripts/components/home.js +0 -137
- /package/cli/scaffold/{scripts → app}/components/contacts/contacts.js +0 -0
- /package/cli/scaffold/{scripts → app}/components/counter.js +0 -0
- /package/cli/scaffold/{scripts → app}/components/not-found.js +0 -0
- /package/cli/scaffold/{scripts → app}/components/todos.js +0 -0
package/src/router.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Supports hash mode (#/path) and history mode (/path).
|
|
5
5
|
* Route params, query strings, navigation guards, and lazy loading.
|
|
6
|
+
* Sub-route history substates for in-page UI changes (modals, tabs, etc.).
|
|
6
7
|
*
|
|
7
8
|
* Usage:
|
|
8
9
|
* $.router({
|
|
@@ -17,9 +18,12 @@
|
|
|
17
18
|
* });
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
|
-
import { mount, destroy } from './component.js';
|
|
21
|
+
import { mount, destroy, prefetch } from './component.js';
|
|
21
22
|
import { reportError, ErrorCode } from './errors.js';
|
|
22
23
|
|
|
24
|
+
// Unique marker on history.state to identify zQuery-managed entries
|
|
25
|
+
const _ZQ_STATE_KEY = '__zq';
|
|
26
|
+
|
|
23
27
|
class Router {
|
|
24
28
|
constructor(config = {}) {
|
|
25
29
|
this._el = null;
|
|
@@ -53,6 +57,10 @@ class Router {
|
|
|
53
57
|
this._instance = null; // current mounted component
|
|
54
58
|
this._resolving = false; // re-entrancy guard
|
|
55
59
|
|
|
60
|
+
// Sub-route history substates
|
|
61
|
+
this._substateListeners = []; // [(key, data) => bool|void]
|
|
62
|
+
this._inSubstate = false; // true while substate entries are in the history stack
|
|
63
|
+
|
|
56
64
|
// Set outlet element
|
|
57
65
|
if (config.el) {
|
|
58
66
|
this._el = typeof config.el === 'string' ? document.querySelector(config.el) : config.el;
|
|
@@ -67,7 +75,21 @@ class Router {
|
|
|
67
75
|
if (this._mode === 'hash') {
|
|
68
76
|
window.addEventListener('hashchange', () => this._resolve());
|
|
69
77
|
} else {
|
|
70
|
-
window.addEventListener('popstate', () =>
|
|
78
|
+
window.addEventListener('popstate', (e) => {
|
|
79
|
+
// Check for substate pop first — if a listener handles it, don't route
|
|
80
|
+
const st = e.state;
|
|
81
|
+
if (st && st[_ZQ_STATE_KEY] === 'substate') {
|
|
82
|
+
const handled = this._fireSubstate(st.key, st.data, 'pop');
|
|
83
|
+
if (handled) return;
|
|
84
|
+
// Unhandled substate — fall through to route resolve
|
|
85
|
+
// _inSubstate stays true so the next non-substate pop triggers reset
|
|
86
|
+
} else if (this._inSubstate) {
|
|
87
|
+
// Popped past all substates — notify listeners to reset to defaults
|
|
88
|
+
this._inSubstate = false;
|
|
89
|
+
this._fireSubstate(null, null, 'reset');
|
|
90
|
+
}
|
|
91
|
+
this._resolve();
|
|
92
|
+
});
|
|
71
93
|
}
|
|
72
94
|
|
|
73
95
|
// Intercept link clicks for SPA navigation
|
|
@@ -78,7 +100,21 @@ class Router {
|
|
|
78
100
|
if (!link) return;
|
|
79
101
|
if (link.getAttribute('target') === '_blank') return;
|
|
80
102
|
e.preventDefault();
|
|
81
|
-
|
|
103
|
+
let href = link.getAttribute('z-link');
|
|
104
|
+
// Support z-link-params for dynamic :param interpolation
|
|
105
|
+
const paramsAttr = link.getAttribute('z-link-params');
|
|
106
|
+
if (paramsAttr) {
|
|
107
|
+
try {
|
|
108
|
+
const params = JSON.parse(paramsAttr);
|
|
109
|
+
href = this._interpolateParams(href, params);
|
|
110
|
+
} catch { /* ignore malformed JSON */ }
|
|
111
|
+
}
|
|
112
|
+
this.navigate(href);
|
|
113
|
+
// z-to-top modifier: scroll to top after navigation
|
|
114
|
+
if (link.hasAttribute('z-to-top')) {
|
|
115
|
+
const scrollBehavior = link.getAttribute('z-to-top') || 'instant';
|
|
116
|
+
window.scrollTo({ top: 0, behavior: scrollBehavior });
|
|
117
|
+
}
|
|
82
118
|
});
|
|
83
119
|
|
|
84
120
|
// Initial resolve
|
|
@@ -122,7 +158,36 @@ class Router {
|
|
|
122
158
|
|
|
123
159
|
// --- Navigation ----------------------------------------------------------
|
|
124
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Interpolate :param placeholders in a path with the given values.
|
|
163
|
+
* @param {string} path — e.g. '/user/:id/posts/:pid'
|
|
164
|
+
* @param {Object} params — e.g. { id: 42, pid: 7 }
|
|
165
|
+
* @returns {string}
|
|
166
|
+
*/
|
|
167
|
+
_interpolateParams(path, params) {
|
|
168
|
+
if (!params || typeof params !== 'object') return path;
|
|
169
|
+
return path.replace(/:([\w]+)/g, (_, key) => {
|
|
170
|
+
const val = params[key];
|
|
171
|
+
return val != null ? encodeURIComponent(String(val)) : ':' + key;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get the full current URL (path + hash) for same-URL detection.
|
|
177
|
+
* @returns {string}
|
|
178
|
+
*/
|
|
179
|
+
_currentURL() {
|
|
180
|
+
if (this._mode === 'hash') {
|
|
181
|
+
return window.location.hash.slice(1) || '/';
|
|
182
|
+
}
|
|
183
|
+
const pathname = window.location.pathname || '/';
|
|
184
|
+
const hash = window.location.hash || '';
|
|
185
|
+
return pathname + hash;
|
|
186
|
+
}
|
|
187
|
+
|
|
125
188
|
navigate(path, options = {}) {
|
|
189
|
+
// Interpolate :param placeholders if options.params is provided
|
|
190
|
+
if (options.params) path = this._interpolateParams(path, options.params);
|
|
126
191
|
// Separate hash fragment (e.g. /docs/getting-started#cli-bundler)
|
|
127
192
|
const [cleanPath, fragment] = (path || '').split('#');
|
|
128
193
|
let normalized = this._normalizePath(cleanPath);
|
|
@@ -131,15 +196,56 @@ class Router {
|
|
|
131
196
|
// Hash mode uses the URL hash for routing, so a #fragment can't live
|
|
132
197
|
// in the URL. Store it as a scroll target for the destination component.
|
|
133
198
|
if (fragment) window.__zqScrollTarget = fragment;
|
|
134
|
-
|
|
199
|
+
const targetHash = '#' + normalized;
|
|
200
|
+
// Skip if already at this exact hash (prevents duplicate entries)
|
|
201
|
+
if (window.location.hash === targetHash && !options.force) return this;
|
|
202
|
+
window.location.hash = targetHash;
|
|
135
203
|
} else {
|
|
136
|
-
|
|
204
|
+
const targetURL = this._base + normalized + hash;
|
|
205
|
+
const currentURL = (window.location.pathname || '/') + (window.location.hash || '');
|
|
206
|
+
|
|
207
|
+
if (targetURL === currentURL && !options.force) {
|
|
208
|
+
// Same full URL (path + hash) — don't push duplicate entry.
|
|
209
|
+
// If only the hash changed to a fragment target, scroll to it.
|
|
210
|
+
if (fragment) {
|
|
211
|
+
const el = document.getElementById(fragment);
|
|
212
|
+
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
213
|
+
}
|
|
214
|
+
return this;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Same route path but different hash fragment — use replaceState
|
|
218
|
+
// so back goes to the previous *route*, not the previous scroll position.
|
|
219
|
+
const targetPathOnly = this._base + normalized;
|
|
220
|
+
const currentPathOnly = window.location.pathname || '/';
|
|
221
|
+
if (targetPathOnly === currentPathOnly && hash && !options.force) {
|
|
222
|
+
window.history.replaceState(
|
|
223
|
+
{ ...options.state, [_ZQ_STATE_KEY]: 'route' },
|
|
224
|
+
'',
|
|
225
|
+
targetURL
|
|
226
|
+
);
|
|
227
|
+
// Scroll to the fragment target
|
|
228
|
+
if (fragment) {
|
|
229
|
+
const el = document.getElementById(fragment);
|
|
230
|
+
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
231
|
+
}
|
|
232
|
+
// Don't re-resolve — same route, just a hash change
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
window.history.pushState(
|
|
237
|
+
{ ...options.state, [_ZQ_STATE_KEY]: 'route' },
|
|
238
|
+
'',
|
|
239
|
+
targetURL
|
|
240
|
+
);
|
|
137
241
|
this._resolve();
|
|
138
242
|
}
|
|
139
243
|
return this;
|
|
140
244
|
}
|
|
141
245
|
|
|
142
246
|
replace(path, options = {}) {
|
|
247
|
+
// Interpolate :param placeholders if options.params is provided
|
|
248
|
+
if (options.params) path = this._interpolateParams(path, options.params);
|
|
143
249
|
const [cleanPath, fragment] = (path || '').split('#');
|
|
144
250
|
let normalized = this._normalizePath(cleanPath);
|
|
145
251
|
const hash = fragment ? '#' + fragment : '';
|
|
@@ -147,7 +253,11 @@ class Router {
|
|
|
147
253
|
if (fragment) window.__zqScrollTarget = fragment;
|
|
148
254
|
window.location.replace('#' + normalized);
|
|
149
255
|
} else {
|
|
150
|
-
window.history.replaceState(
|
|
256
|
+
window.history.replaceState(
|
|
257
|
+
{ ...options.state, [_ZQ_STATE_KEY]: 'route' },
|
|
258
|
+
'',
|
|
259
|
+
this._base + normalized + hash
|
|
260
|
+
);
|
|
151
261
|
this._resolve();
|
|
152
262
|
}
|
|
153
263
|
return this;
|
|
@@ -202,6 +312,80 @@ class Router {
|
|
|
202
312
|
return () => this._listeners.delete(fn);
|
|
203
313
|
}
|
|
204
314
|
|
|
315
|
+
// --- Sub-route history substates -----------------------------------------
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Push a lightweight history entry for in-component UI state.
|
|
319
|
+
* The URL path does NOT change — only a history entry is added so the
|
|
320
|
+
* back button can undo the UI change (close modal, revert tab, etc.)
|
|
321
|
+
* before navigating away.
|
|
322
|
+
*
|
|
323
|
+
* @param {string} key — identifier (e.g. 'modal', 'tab', 'panel')
|
|
324
|
+
* @param {*} data — arbitrary state (serializable)
|
|
325
|
+
* @returns {Router}
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* // Open a modal and push a substate
|
|
329
|
+
* router.pushSubstate('modal', { id: 'confirm-delete' });
|
|
330
|
+
* // User hits back → onSubstate fires → close the modal
|
|
331
|
+
*/
|
|
332
|
+
pushSubstate(key, data) {
|
|
333
|
+
this._inSubstate = true;
|
|
334
|
+
if (this._mode === 'hash') {
|
|
335
|
+
// Hash mode: stash the substate in a global — hashchange will check.
|
|
336
|
+
// We still push a history entry via a sentinel hash suffix.
|
|
337
|
+
const current = window.location.hash || '#/';
|
|
338
|
+
window.history.pushState(
|
|
339
|
+
{ [_ZQ_STATE_KEY]: 'substate', key, data },
|
|
340
|
+
'',
|
|
341
|
+
window.location.href
|
|
342
|
+
);
|
|
343
|
+
} else {
|
|
344
|
+
window.history.pushState(
|
|
345
|
+
{ [_ZQ_STATE_KEY]: 'substate', key, data },
|
|
346
|
+
'',
|
|
347
|
+
window.location.href // keep same URL
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
return this;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Register a listener for substate pops (back button on a substate entry).
|
|
355
|
+
* The callback receives `(key, data)` and should return `true` if it
|
|
356
|
+
* handled the pop (prevents route resolution). If no listener returns
|
|
357
|
+
* `true`, normal route resolution proceeds.
|
|
358
|
+
*
|
|
359
|
+
* @param {(key: string, data: any, action: string) => boolean|void} fn
|
|
360
|
+
* @returns {() => void} unsubscribe function
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* const unsub = router.onSubstate((key, data) => {
|
|
364
|
+
* if (key === 'modal') { closeModal(); return true; }
|
|
365
|
+
* });
|
|
366
|
+
*/
|
|
367
|
+
onSubstate(fn) {
|
|
368
|
+
this._substateListeners.push(fn);
|
|
369
|
+
return () => {
|
|
370
|
+
this._substateListeners = this._substateListeners.filter(f => f !== fn);
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Fire substate listeners. Returns true if any listener handled it.
|
|
376
|
+
* @private
|
|
377
|
+
*/
|
|
378
|
+
_fireSubstate(key, data, action) {
|
|
379
|
+
for (const fn of this._substateListeners) {
|
|
380
|
+
try {
|
|
381
|
+
if (fn(key, data, action) === true) return true;
|
|
382
|
+
} catch (err) {
|
|
383
|
+
reportError(ErrorCode.ROUTER_GUARD, 'onSubstate listener threw', { key, data }, err);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
|
|
205
389
|
// --- Current state -------------------------------------------------------
|
|
206
390
|
|
|
207
391
|
get current() { return this._current; }
|
|
@@ -253,6 +437,7 @@ class Router {
|
|
|
253
437
|
// Prevent re-entrant calls (e.g. listener triggering navigation)
|
|
254
438
|
if (this._resolving) return;
|
|
255
439
|
this._resolving = true;
|
|
440
|
+
this._redirectCount = 0;
|
|
256
441
|
try {
|
|
257
442
|
await this.__resolve();
|
|
258
443
|
} finally {
|
|
@@ -261,6 +446,16 @@ class Router {
|
|
|
261
446
|
}
|
|
262
447
|
|
|
263
448
|
async __resolve() {
|
|
449
|
+
// Check if we're landing on a substate entry (e.g. page refresh on a
|
|
450
|
+
// substate bookmark, or hash-mode popstate). Fire listeners and bail
|
|
451
|
+
// if handled — the URL hasn't changed so there's no route to resolve.
|
|
452
|
+
const histState = window.history.state;
|
|
453
|
+
if (histState && histState[_ZQ_STATE_KEY] === 'substate') {
|
|
454
|
+
const handled = this._fireSubstate(histState.key, histState.data, 'resolve');
|
|
455
|
+
if (handled) return;
|
|
456
|
+
// No listener handled it — fall through to normal routing
|
|
457
|
+
}
|
|
458
|
+
|
|
264
459
|
const fullPath = this.path;
|
|
265
460
|
const [pathPart, queryString] = fullPath.split('?');
|
|
266
461
|
const path = pathPart || '/';
|
|
@@ -288,13 +483,43 @@ class Router {
|
|
|
288
483
|
const to = { route: matched, params, query, path };
|
|
289
484
|
const from = this._current;
|
|
290
485
|
|
|
486
|
+
// Same-route optimization: if the resolved route is the same component
|
|
487
|
+
// with the same params, skip the full destroy/mount cycle and just
|
|
488
|
+
// update props. This prevents flashing and unnecessary DOM churn.
|
|
489
|
+
if (from && this._instance && matched.component === from.route.component) {
|
|
490
|
+
const sameParams = JSON.stringify(params) === JSON.stringify(from.params);
|
|
491
|
+
const sameQuery = JSON.stringify(query) === JSON.stringify(from.query);
|
|
492
|
+
if (sameParams && sameQuery) {
|
|
493
|
+
// Identical navigation — nothing to do
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
291
498
|
// Run before guards
|
|
292
499
|
for (const guard of this._guards.before) {
|
|
293
500
|
try {
|
|
294
501
|
const result = await guard(to, from);
|
|
295
502
|
if (result === false) return; // Cancel
|
|
296
503
|
if (typeof result === 'string') { // Redirect
|
|
297
|
-
|
|
504
|
+
if (++this._redirectCount > 10) {
|
|
505
|
+
reportError(ErrorCode.ROUTER_GUARD, 'Too many guard redirects (possible loop)', { to }, null);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
// Update URL directly and re-resolve (avoids re-entrancy block)
|
|
509
|
+
const [rPath, rFrag] = result.split('#');
|
|
510
|
+
const rNorm = this._normalizePath(rPath || '/');
|
|
511
|
+
const rHash = rFrag ? '#' + rFrag : '';
|
|
512
|
+
if (this._mode === 'hash') {
|
|
513
|
+
if (rFrag) window.__zqScrollTarget = rFrag;
|
|
514
|
+
window.location.replace('#' + rNorm);
|
|
515
|
+
} else {
|
|
516
|
+
window.history.replaceState(
|
|
517
|
+
{ [_ZQ_STATE_KEY]: 'route' },
|
|
518
|
+
'',
|
|
519
|
+
this._base + rNorm + rHash
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
return this.__resolve();
|
|
298
523
|
}
|
|
299
524
|
} catch (err) {
|
|
300
525
|
reportError(ErrorCode.ROUTER_GUARD, 'Before-guard threw', { to, from }, err);
|
|
@@ -315,6 +540,12 @@ class Router {
|
|
|
315
540
|
|
|
316
541
|
// Mount component into outlet
|
|
317
542
|
if (this._el && matched.component) {
|
|
543
|
+
// Pre-load external templates/styles so the mount renders synchronously
|
|
544
|
+
// (keeps old content visible during the fetch instead of showing blank)
|
|
545
|
+
if (typeof matched.component === 'string') {
|
|
546
|
+
await prefetch(matched.component);
|
|
547
|
+
}
|
|
548
|
+
|
|
318
549
|
// Destroy previous
|
|
319
550
|
if (this._instance) {
|
|
320
551
|
this._instance.destroy();
|
|
@@ -322,6 +553,7 @@ class Router {
|
|
|
322
553
|
}
|
|
323
554
|
|
|
324
555
|
// Create container
|
|
556
|
+
const _routeStart = typeof window !== 'undefined' && window.__zqRenderHook ? performance.now() : 0;
|
|
325
557
|
this._el.innerHTML = '';
|
|
326
558
|
|
|
327
559
|
// Pass route params and query as props
|
|
@@ -332,10 +564,12 @@ class Router {
|
|
|
332
564
|
const container = document.createElement(matched.component);
|
|
333
565
|
this._el.appendChild(container);
|
|
334
566
|
this._instance = mount(container, matched.component, props);
|
|
567
|
+
if (_routeStart) window.__zqRenderHook(this._el, performance.now() - _routeStart, 'route', matched.component);
|
|
335
568
|
}
|
|
336
569
|
// If component is a render function
|
|
337
570
|
else if (typeof matched.component === 'function') {
|
|
338
571
|
this._el.innerHTML = matched.component(to);
|
|
572
|
+
if (_routeStart) window.__zqRenderHook(this._el, performance.now() - _routeStart, 'route', to);
|
|
339
573
|
}
|
|
340
574
|
}
|
|
341
575
|
|
|
@@ -353,6 +587,8 @@ class Router {
|
|
|
353
587
|
destroy() {
|
|
354
588
|
if (this._instance) this._instance.destroy();
|
|
355
589
|
this._listeners.clear();
|
|
590
|
+
this._substateListeners = [];
|
|
591
|
+
this._inSubstate = false;
|
|
356
592
|
this._routes = [];
|
|
357
593
|
this._guards = { before: [], after: [] };
|
|
358
594
|
}
|