fusee-framework 1.9.0 → 1.9.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.
Files changed (62) hide show
  1. package/README.md +1 -1
  2. package/bin/create-fusee-linux +0 -0
  3. package/bin/create-fusee-mac-arm64 +0 -0
  4. package/bin/create-fusee-mac-intel +0 -0
  5. package/bin/create-fusee-win.exe +0 -0
  6. package/bin/create-fusee.exe +0 -0
  7. package/create-fusee-go/internal/assets/embed/framework/auto-import-preset.js +15 -9
  8. package/create-fusee-go/internal/assets/embed/framework/core/async-context.js +27 -0
  9. package/create-fusee-go/internal/assets/embed/framework/core/compiler/ast.js +167 -0
  10. package/create-fusee-go/internal/assets/embed/framework/core/compiler/errors-list.js +47 -0
  11. package/create-fusee-go/internal/assets/embed/framework/core/compiler/errors.js +107 -0
  12. package/create-fusee-go/internal/assets/embed/framework/core/compiler/generator.js +363 -0
  13. package/create-fusee-go/internal/assets/embed/framework/core/compiler/lexer.js +347 -0
  14. package/create-fusee-go/internal/assets/embed/framework/core/compiler/main-compiler.js +115 -0
  15. package/create-fusee-go/internal/assets/embed/framework/core/compiler/parser.js +414 -0
  16. package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/actions-plugin.js +263 -0
  17. package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/compiler-plugin.d.ts +5 -0
  18. package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/compiler-plugin.js +45 -0
  19. package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/file-router-plugin.js +301 -0
  20. package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/router-plugin.js +196 -0
  21. package/create-fusee-go/internal/assets/embed/framework/core/compiler/transformer.js +398 -0
  22. package/create-fusee-go/internal/assets/embed/framework/core/component.js +61 -23
  23. package/create-fusee-go/internal/assets/embed/framework/core/di.js +187 -0
  24. package/create-fusee-go/internal/assets/embed/framework/core/directives.js +40 -96
  25. package/create-fusee-go/internal/assets/embed/framework/core/evaluator.js +1 -1
  26. package/create-fusee-go/internal/assets/embed/framework/core/h.js +430 -0
  27. package/create-fusee-go/internal/assets/embed/framework/core/hydration.js +83 -0
  28. package/create-fusee-go/internal/assets/embed/framework/core/reconcile.js +151 -0
  29. package/create-fusee-go/internal/assets/embed/framework/core/signal.js +269 -0
  30. package/create-fusee-go/internal/assets/embed/framework/core/store.js +322 -81
  31. package/create-fusee-go/internal/assets/embed/framework/index.js +5 -3
  32. package/create-fusee-go/internal/assets/embed/framework/router/file-router.js +1 -1
  33. package/create-fusee-go/internal/assets/embed/framework/router/router.js +113 -21
  34. package/create-fusee-go/internal/assets/embed/framework/server/actions.js +173 -0
  35. package/create-fusee-go/internal/assets/embed/framework/server/actions.server.js +88 -0
  36. package/create-fusee-go/internal/assets/embed/framework/server/index.js +18 -0
  37. package/create-fusee-go/internal/assets/embed/framework/types/actions.d.ts +50 -0
  38. package/create-fusee-go/internal/assets/embed/framework/types/actions.server.d.ts +36 -0
  39. package/create-fusee-go/internal/assets/embed/framework/types/compiler/ast.d.ts +166 -0
  40. package/create-fusee-go/internal/assets/embed/framework/types/compiler/errors-codes.d.ts +23 -0
  41. package/create-fusee-go/internal/assets/embed/framework/types/compiler/errors.d.ts +43 -0
  42. package/create-fusee-go/internal/assets/embed/framework/types/compiler/generator.d.ts +8 -0
  43. package/create-fusee-go/internal/assets/embed/framework/types/compiler/h.d.ts +46 -0
  44. package/create-fusee-go/internal/assets/embed/framework/types/compiler/lexer.d.ts +27 -0
  45. package/create-fusee-go/internal/assets/embed/framework/types/compiler/main-compiler.d.ts +60 -0
  46. package/create-fusee-go/internal/assets/embed/framework/types/compiler/parser.d.ts +4 -0
  47. package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/actions.d.ts +30 -0
  48. package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/compiler-plugin.d.ts +5 -0
  49. package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/file-router-plugins.d.ts +32 -0
  50. package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/router-plugin.d.ts +24 -0
  51. package/create-fusee-go/internal/assets/embed/framework/types/compiler/transformer.d.ts +28 -0
  52. package/create-fusee-go/internal/assets/embed/framework/types/component.d.ts +89 -88
  53. package/create-fusee-go/internal/assets/embed/framework/types/di.d.ts +43 -0
  54. package/create-fusee-go/internal/assets/embed/framework/types/hydration.d.ts +30 -0
  55. package/create-fusee-go/internal/assets/embed/framework/types/index.d.ts +38 -22
  56. package/create-fusee-go/internal/assets/embed/framework/types/reconcile.d.ts +7 -0
  57. package/create-fusee-go/internal/assets/embed/framework/types/router.d.ts +11 -1
  58. package/create-fusee-go/internal/assets/embed/framework/types/server.d.ts +11 -0
  59. package/create-fusee-go/internal/assets/embed/framework/types/signal.d.ts +142 -79
  60. package/create-fusee-go/internal/assets/embed/framework/types/store.d.ts +66 -8
  61. package/package.json +1 -1
  62. package/create-fusee-go/internal/assets/embed/framework/bin/create-fusee.js +0 -199
@@ -1,5 +1,7 @@
1
1
  import { effect, setEffectHook, batch } from './signal.js'
2
2
  import { mountTemplate } from './compiler.js'
3
+ import { rootInjector, runInContext, replaceActiveInjector, EnvironmentInjector } from './di.js'
4
+ export { inject } from './di.js'
3
5
 
4
6
  let currentInstance = null
5
7
 
@@ -129,20 +131,25 @@ export function onUnmount(fn) {
129
131
 
130
132
  export function defineComponent(options) {
131
133
  return function ComponentFactory(props = {}, { listeners = {}, slots = {}, parent = null } = {}) {
134
+ const parentInjector = (parent && parent._injector) || rootInjector;
135
+
132
136
  const instance = {
133
137
  props: options.props ? resolveProps(options.props, props) : props,
134
138
  _mountHooks: [],
135
139
  _unmountHooks: [],
136
140
  _effects: [],
137
141
  _element: null,
138
- _provides: {},
139
142
  _parent: parent,
143
+ _injector: parentInjector,
144
+ _ownsInjector: false
140
145
  }
141
146
 
142
147
  const emit = createEmit(listeners)
143
148
 
144
149
  currentInstance = instance
145
- const result = options.setup(instance.props, { emit, slots })
150
+ const result = runInContext(instance._injector, () => {
151
+ return options.setup(instance.props, { emit, slots });
152
+ });
146
153
  instance.state = result
147
154
  result._instance = instance
148
155
  currentInstance = null
@@ -150,17 +157,41 @@ export function defineComponent(options) {
150
157
  function render(container) {
151
158
  instance._element = container
152
159
 
153
- const resolvedTemplate = resolveSlots(result.template, slots)
154
-
155
- const { effects } = mountTemplate(
156
- resolvedTemplate,
157
- container,
158
- result,
159
- options.components || {}
160
- )
160
+ if (options.render) {
161
+ const nodes = options.render(result, options.components || {})
162
+ container.innerHTML = ''
163
+
164
+ function mountNode(fnode) {
165
+ if (!fnode || !fnode.node) return
166
+ container.appendChild(fnode.node)
167
+
168
+ if (fnode.effects) {
169
+ instance._effects.push(...fnode.effects)
170
+ }
171
+
172
+ if (fnode.children) {
173
+ for (const child of fnode.children) {
174
+ mountNode(child)
175
+ }
176
+ }
177
+ }
178
+
179
+ for (const node of nodes) {
180
+ mountNode(node)
181
+ }
182
+ } else {
183
+ const resolvedTemplate = resolveSlots(result.template, slots)
184
+ const { effects } = mountTemplate(
185
+ resolvedTemplate,
186
+ container,
187
+ result,
188
+ options.components || {}
189
+ )
190
+ instance._effects.push(...effects)
191
+ }
161
192
 
162
- instance._effects.push(...effects)
163
- for (const hook of instance._mountHooks) hook()
193
+ for (const hook of instance._mountHooks)
194
+ hook()
164
195
 
165
196
  return instance
166
197
  }
@@ -183,17 +214,21 @@ export function defineComponent(options) {
183
214
  }
184
215
 
185
216
  export function provide(key, value) {
186
- if (!currentInstance) return
187
- currentInstance._provides[key] = value
188
- }
189
-
190
- export function inject(key) {
191
- let parent = currentInstance?._parent
192
- while (parent) {
193
- if (key in parent._provides) return parent._provides[key];
194
- parent = parent._parent;
217
+ if (!currentInstance) return;
218
+
219
+ if (!currentInstance._ownsInjector) {
220
+ currentInstance._injector = new EnvironmentInjector([], currentInstance._injector);
221
+ currentInstance._ownsInjector = true;
222
+ replaceActiveInjector(currentInstance._injector);
223
+ }
224
+
225
+ if (value === undefined && key && key.provide) {
226
+ currentInstance._injector.provide(key);
227
+ } else if (value && typeof value === 'object' && (value.useClass || value.useFactory || value.useExisting)) {
228
+ currentInstance._injector.provide({ provide: key, ...value });
229
+ } else {
230
+ currentInstance._injector.provide({ provide: key, useValue: value });
195
231
  }
196
- return null;
197
232
  }
198
233
 
199
234
  export function defineAsyncComponent(loaderOrOptions) {
@@ -202,14 +237,17 @@ export function defineAsyncComponent(loaderOrOptions) {
202
237
  : loaderOrOptions
203
238
 
204
239
  return function AsyncComponentFactory(props = {}, { listeners = {}, slots = {}, parent = null } = {}) {
240
+ const parentInjector = (parent && parent._injector) || rootInjector;
241
+
205
242
  const instance = {
206
243
  props,
207
244
  _mountHooks: [],
208
245
  _unmountHooks: [],
209
246
  _effects: [],
210
247
  _element: null,
211
- _provides: {},
212
248
  _parent: parent,
249
+ _injector: parentInjector,
250
+ _ownsInjector: false
213
251
  }
214
252
 
215
253
  let childApi = null
@@ -0,0 +1,187 @@
1
+ export class InjectionToken {
2
+ constructor(description) {
3
+ this.description = description;
4
+ }
5
+ toString() {
6
+ return `InjectionToken ${this.description}`;
7
+ }
8
+ }
9
+
10
+ export function isClass(fn) {
11
+ if (typeof fn !== 'function') return false;
12
+ const str = fn.toString();
13
+ if (/^\s*class\s+/.test(str)) return true;
14
+ return fn.prototype !== undefined &&
15
+ fn.prototype.constructor === fn &&
16
+ Object.getOwnPropertyNames(fn.prototype).length > 1;
17
+ }
18
+
19
+ export class Injector {
20
+ get(token, options = { optional: false }) {
21
+ throw new Error('Not implemented');
22
+ }
23
+ }
24
+
25
+ export class NullInjector extends Injector {
26
+ get(token, options = { optional: false }) {
27
+ if (options.optional) {
28
+ return null;
29
+ }
30
+ const tokenName = token?.name || token?.description || token;
31
+ throw new Error(`NullInjectorError: No provider for ${tokenName}!`);
32
+ }
33
+ }
34
+
35
+ const NULL_INJECTOR = new NullInjector();
36
+
37
+ export class EnvironmentInjector extends Injector {
38
+ constructor(providers = [], parent = NULL_INJECTOR) {
39
+ super();
40
+ this.parent = parent;
41
+ this.records = new Map();
42
+ this.instances = new Map();
43
+ this.resolutionStack = new Set();
44
+ this._normalizeProviders(providers);
45
+ }
46
+
47
+ _normalizeProviders(providers) {
48
+ for (const provider of providers) {
49
+ if (typeof provider === 'function' && isClass(provider)) {
50
+ this.records.set(provider, { useClass: provider });
51
+ } else if (provider && provider.provide) {
52
+ this.records.set(provider.provide, provider);
53
+ } else {
54
+ throw new Error(`Invalid provider configuration: ${provider}`);
55
+ }
56
+ }
57
+ }
58
+
59
+ provide(provider) {
60
+ this._normalizeProviders([provider]);
61
+ }
62
+
63
+ // Bubble-up algorithm for resolving hierarchical dependencies
64
+ get(token, options = { optional: false }) {
65
+ if (this.instances.has(token)) {
66
+ return this.instances.get(token);
67
+ }
68
+
69
+ if (this.records.has(token)) {
70
+ if (this.resolutionStack.has(token)) {
71
+ const path = [...this.resolutionStack, token]
72
+ .map(t => t?.name || t?.description || t)
73
+ .join(' -> ');
74
+ throw new Error(`Circular dependency detected: ${path}`);
75
+ }
76
+
77
+ this.resolutionStack.add(token);
78
+
79
+ try {
80
+ const record = this.records.get(token);
81
+ const instance = this._instantiate(record);
82
+ this.instances.set(token, instance);
83
+ return instance;
84
+ } finally {
85
+ this.resolutionStack.delete(token);
86
+ }
87
+ }
88
+
89
+ if (options.self === true) {
90
+ if (options.optional === true) {
91
+ return null;
92
+ }
93
+ const tokenName = token?.name || token?.description || token;
94
+ throw new Error(`NullInjectorError: No provider found for ${tokenName} locally (self: true)`);
95
+ }
96
+
97
+ return this.parent.get(token, options);
98
+ }
99
+
100
+ _instantiate(record) {
101
+ return runInContext(this, () => {
102
+ if (record.useValue !== undefined) {
103
+ return record.useValue;
104
+ }
105
+ if (record.useFactory) {
106
+ return record.useFactory();
107
+ }
108
+ if (record.useExisting) {
109
+ return inject(record.useExisting);
110
+ }
111
+ if (record.useClass) {
112
+ const ClassDef = record.useClass;
113
+ return new ClassDef();
114
+ }
115
+ throw new Error(`Invalid provider record configuration for ${record.provide?.name || record.provide}`);
116
+ });
117
+ }
118
+
119
+ createChild(providers = []) {
120
+ return new EnvironmentInjector(providers, this);
121
+ }
122
+
123
+ destroy() {
124
+ for (const instance of this.instances.values()) {
125
+ if (instance && typeof instance.destroy === 'function') {
126
+ try {
127
+ instance.destroy();
128
+ } catch (e) {
129
+ console.error('Error during instance destroy:', e);
130
+ }
131
+ } else if (instance && typeof instance.onDestroy === 'function') {
132
+ try {
133
+ instance.onDestroy();
134
+ } catch (e) {
135
+ console.error('Error during instance onDestroy:', e);
136
+ }
137
+ }
138
+ }
139
+ this.instances.clear();
140
+ this.records.clear();
141
+ }
142
+ }
143
+
144
+ let _activeInjector = null;
145
+
146
+ export function runInContext(injector, fn) {
147
+ const previousInjector = _activeInjector;
148
+ _activeInjector = injector;
149
+ try {
150
+ return fn();
151
+ } finally {
152
+ _activeInjector = previousInjector;
153
+ }
154
+ }
155
+
156
+ export function replaceActiveInjector(injector) {
157
+ _activeInjector = injector;
158
+ }
159
+
160
+ export function inject(token, options = {}) {
161
+ if (_activeInjector === null) {
162
+ throw new Error('inject() called outside of an injection context');
163
+ }
164
+
165
+ const isOptional = options.optional === true;
166
+ const skipSelf = options.skipSelf === true;
167
+ const self = options.self === true;
168
+
169
+ if (skipSelf && self) {
170
+ throw new Error('Cannot combine both skipSelf and self InjectOptions');
171
+ }
172
+
173
+ const injectorToUse = skipSelf ? _activeInjector.parent : _activeInjector;
174
+
175
+ if (!injectorToUse) {
176
+ if (isOptional) return null;
177
+ throw new Error(`NullInjectorError: No provider found for ${token?.name || token}`);
178
+ }
179
+
180
+ return injectorToUse.get(token, options);
181
+ }
182
+
183
+ export const rootInjector = new EnvironmentInjector();
184
+
185
+ export function provideGlobal(provider) {
186
+ rootInjector.provide(provider);
187
+ }
@@ -1,8 +1,9 @@
1
1
  import { signal, effect, batch } from './signal.js'
2
2
  import { evaluateExpression } from './evaluator.js'
3
3
  import { compileNode } from './compiler.js'
4
+ import { reconcileArrays } from './reconcile.js'
4
5
  import { registerDelegatedEvent, createEventHandler, isDelegatedEvent } from './event-delegation.js'
5
- import { currentRoute } from '../router/router.js'
6
+ import { currentRoute, navigate } from '../router/router.js'
6
7
 
7
8
  const customDirectives = new Map()
8
9
 
@@ -165,8 +166,7 @@ export function processFor(el, context, components, effects) {
165
166
  const templateNode = el.cloneNode(true)
166
167
  parent.removeChild(el)
167
168
 
168
- let cache = new Map()
169
- let previousOrder = []
169
+ let oldRenderedNodes = []
170
170
 
171
171
  effects.push(effect(() => {
172
172
  const rawItems = evaluateExpression(arrayExpr, context)
@@ -180,9 +180,6 @@ export function processFor(el, context, components, effects) {
180
180
  items = Object.entries(rawItems).map(([key, value], index) => ({ value, key, rawIndex: index }))
181
181
  }
182
182
 
183
- const nextCache = new Map()
184
- const nextOrder = []
185
-
186
183
  const newItemsWithKeys = items.map((item, index) => {
187
184
  const itemContext = Object.create(context)
188
185
  itemContext[itemName] = item.value
@@ -190,116 +187,54 @@ export function processFor(el, context, components, effects) {
190
187
  if (indexName) itemContext[indexName] = index
191
188
 
192
189
  const key = keyExpr ? evaluateExpression(keyExpr, itemContext) : item.rawIndex
193
- return { item, key }
190
+ return { item, key, index }
194
191
  })
195
192
 
196
193
  const parentNode = anchor.parentNode
197
- let currentCursor = anchor.nextSibling
198
-
199
- const isClear = items.length === 0 && previousOrder.length > 0
200
- if (isClear) {
201
- const nodesToRemove = []
202
- let node = anchor.nextSibling
203
- while (node) {
204
- const next = node.nextSibling
205
- nodesToRemove.push(node)
206
- node = next
207
- }
208
- if (nodesToRemove.length > 0) {
209
- const fragment = document.createDocumentFragment()
210
- nodesToRemove.forEach(n => fragment.appendChild(n))
211
- }
212
- for (const entry of cache.values()) {
213
- for (let i = entry.effects.length - 1; i >= 0; i--) {
214
- const cleanup = entry.effects[i]
215
- if (typeof cleanup === 'function') cleanup()
216
- }
217
- }
218
- cache.clear()
219
- previousOrder = []
220
- return
221
- }
222
-
223
- const fragment = document.createDocumentFragment()
224
- const nodesToInsert = []
225
-
226
- newItemsWithKeys.forEach(({ item, key }, index) => {
227
- let entry = cache.get(key)
228
-
229
- if (entry) {
230
- batch(() => {
231
- if (typeof entry.context[itemName] === 'function' && entry.context[itemName].isSignal) {
232
- entry.context[itemName](item.value)
233
- }
234
- if (keyName && typeof entry.context[keyName] === 'function' && entry.context[keyName].isSignal) {
235
- entry.context[keyName](item.hasOwnProperty('key') ? item.key : item.rawIndex)
236
- }
237
- if (indexName && typeof entry.context[indexName] === 'function' && entry.context[indexName].isSignal) {
238
- entry.context[indexName](index)
239
- }
240
- })
241
194
 
242
- if (entry.node !== currentCursor) {
243
- parentNode.insertBefore(entry.node, currentCursor)
244
- } else {
245
- currentCursor = currentCursor.nextSibling
246
- }
247
- cache.delete(key)
248
- } else {
195
+ oldRenderedNodes = reconcileArrays(
196
+ parentNode,
197
+ anchor,
198
+ oldRenderedNodes,
199
+ newItemsWithKeys,
200
+ (obj) => obj.key,
201
+ (newItem, index) => {
249
202
  const itemContext = Object.create(context)
250
- itemContext[itemName] = signal(item.value)
251
- if (keyName) itemContext[keyName] = signal(item.hasOwnProperty('key') ? item.key : item.rawIndex)
203
+ itemContext[itemName] = signal(newItem.item.value)
204
+ if (keyName) itemContext[keyName] = signal(newItem.item.hasOwnProperty('key') ? newItem.item.key : newItem.item.rawIndex)
252
205
  if (indexName) itemContext[indexName] = signal(index)
253
206
 
254
207
  const clone = templateNode.cloneNode(true)
255
208
  const childEffects = []
256
209
  compileNode(clone, itemContext, components, childEffects)
257
210
 
258
- fragment.appendChild(clone)
259
- entry = { node: clone, effects: childEffects, context: itemContext }
260
- nodesToInsert.push({ node: clone, effects: childEffects, context: itemContext, key })
211
+ return { node: clone, effects: childEffects, context: itemContext, key: newItem.key }
212
+ },
213
+ (oldNode, newItem, index) => {
214
+ batch(() => {
215
+ if (typeof oldNode.context[itemName] === 'function' && oldNode.context[itemName].isSignal) {
216
+ oldNode.context[itemName](newItem.item.value)
217
+ }
218
+ if (keyName && typeof oldNode.context[keyName] === 'function' && oldNode.context[keyName].isSignal) {
219
+ oldNode.context[keyName](newItem.item.hasOwnProperty('key') ? newItem.item.key : newItem.item.rawIndex)
220
+ }
221
+ if (indexName && typeof oldNode.context[indexName] === 'function' && oldNode.context[indexName].isSignal) {
222
+ oldNode.context[indexName](index)
223
+ }
224
+ })
261
225
  }
262
-
263
- nextCache.set(key, entry)
264
- nextOrder.push(entry.node)
265
- })
266
-
267
- if (fragment.childNodes.length > 0) {
268
- parentNode.insertBefore(fragment, currentCursor)
269
- nodesToInsert.forEach(({ node, effects, context, key }) => {
270
- nextCache.set(key, { node, effects, context })
271
- })
272
- }
273
-
274
- const removedEntries = []
275
- for (const [_, entry] of cache.entries()) {
276
- removedEntries.push(entry)
277
- }
278
- if (removedEntries.length > 0) {
279
- const removeFragment = document.createDocumentFragment()
280
- removedEntries.forEach(entry => {
281
- for (let i = entry.effects.length - 1; i >= 0; i--) {
282
- const cleanup = entry.effects[i]
283
- if (typeof cleanup === 'function') cleanup()
284
- }
285
- if (entry.node.parentNode) {
286
- removeFragment.appendChild(entry.node)
287
- }
288
- })
289
- }
290
-
291
- cache = nextCache
292
- previousOrder = nextOrder
226
+ )
293
227
  }))
294
228
 
295
229
  effects.push(() => {
296
- for (const entry of cache.values()) {
230
+ for (const entry of oldRenderedNodes) {
231
+ if (!entry) continue
297
232
  for (let i = entry.effects.length - 1; i >= 0; i--) {
298
233
  const cleanup = entry.effects[i]
299
234
  if (typeof cleanup === 'function') cleanup()
300
235
  }
301
236
  }
302
- cache.clear()
237
+ oldRenderedNodes = []
303
238
  })
304
239
 
305
240
  return true
@@ -861,6 +796,8 @@ export function processLinks(el, effects) {
861
796
  const href = link.getAttribute('href')
862
797
  if (!href) continue
863
798
 
799
+ link.removeAttribute('f-link')
800
+
864
801
  effects.push(effect(() => {
865
802
  const currentPath = currentRoute()
866
803
  const isActive = currentPath === href || currentPath.startsWith(href + '/')
@@ -871,5 +808,12 @@ export function processLinks(el, effects) {
871
808
  link.classList.remove('active')
872
809
  }
873
810
  }))
811
+
812
+ const clickHandler = (e) => {
813
+ e.preventDefault()
814
+ navigate(href)
815
+ }
816
+ link.addEventListener('click', clickHandler)
817
+ effects.push(() => link.removeEventListener('click', clickHandler))
874
818
  }
875
819
  }
@@ -37,7 +37,7 @@ export function evaluateExpression(expr, context, extraContext = {}, unwrapSigna
37
37
  ).join('\n')
38
38
  let wrappedExpr = expr
39
39
  for (const id of keysToUnwrap) {
40
- wrappedExpr = wrappedExpr.replace(new RegExp('\\b' + id + '\\b', 'g'), '__' + id)
40
+ wrappedExpr = wrappedExpr.replace(new RegExp('\\b' + id + '\\b(?!\\(|\\.loading\\b|\\.error\\b|\\.isFetching\\b)', 'g'), '__' + id)
41
41
  }
42
42
  body = (unwrapStatements ? unwrapStatements + '\n' : '') + `return ${wrappedExpr}`
43
43
  }