effect-start 0.18.0 → 0.20.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.
- package/README.md +3 -3
- package/dist/Development.d.ts +8 -3
- package/dist/Development.js +14 -7
- package/dist/Effectify.d.ts +212 -0
- package/dist/Effectify.js +19 -0
- package/dist/FilePathPattern.d.ts +29 -0
- package/dist/FilePathPattern.js +86 -0
- package/dist/FileRouter.d.ts +39 -41
- package/dist/FileRouter.js +104 -158
- package/dist/FileRouterCodegen.d.ts +7 -8
- package/dist/FileRouterCodegen.js +97 -66
- package/dist/PlatformError.d.ts +46 -0
- package/dist/PlatformError.js +43 -0
- package/dist/PlatformRuntime.d.ts +27 -0
- package/dist/PlatformRuntime.js +51 -0
- package/dist/Route.d.ts +6 -2
- package/dist/Route.js +22 -0
- package/dist/RouteBody.d.ts +1 -1
- package/dist/RouteHttp.d.ts +1 -1
- package/dist/RouteHttp.js +12 -19
- package/dist/RouteMount.d.ts +2 -1
- package/dist/Start.d.ts +33 -6
- package/dist/Start.js +31 -13
- package/dist/Unique.d.ts +50 -0
- package/dist/Unique.js +187 -0
- package/dist/bun/BunHttpServer.js +5 -6
- package/dist/bun/BunPlatformHttpServer.d.ts +10 -0
- package/dist/bun/BunPlatformHttpServer.js +53 -0
- package/dist/bun/BunRoute.d.ts +4 -6
- package/dist/bun/BunRoute.js +10 -18
- package/dist/bun/BunRuntime.d.ts +2 -1
- package/dist/bun/BunRuntime.js +10 -5
- package/dist/bun/BunServer.d.ts +33 -0
- package/dist/bun/BunServer.js +133 -0
- package/dist/bun/BunServerRequest.d.ts +60 -0
- package/dist/bun/BunServerRequest.js +252 -0
- package/dist/bun/index.d.ts +1 -1
- package/dist/bun/index.js +1 -1
- package/dist/datastar/actions/fetch.d.ts +30 -0
- package/dist/datastar/actions/fetch.js +411 -0
- package/dist/datastar/actions/peek.d.ts +1 -0
- package/dist/datastar/actions/peek.js +14 -0
- package/dist/datastar/actions/setAll.d.ts +1 -0
- package/dist/datastar/actions/setAll.js +13 -0
- package/dist/datastar/actions/toggleAll.d.ts +1 -0
- package/dist/datastar/actions/toggleAll.js +13 -0
- package/dist/datastar/attributes/attr.d.ts +1 -0
- package/dist/datastar/attributes/attr.js +49 -0
- package/dist/datastar/attributes/bind.d.ts +1 -0
- package/dist/datastar/attributes/bind.js +183 -0
- package/dist/datastar/attributes/class.d.ts +1 -0
- package/dist/datastar/attributes/class.js +50 -0
- package/dist/datastar/attributes/computed.d.ts +1 -0
- package/dist/datastar/attributes/computed.js +27 -0
- package/dist/datastar/attributes/effect.d.ts +1 -0
- package/dist/datastar/attributes/effect.js +10 -0
- package/dist/datastar/attributes/indicator.d.ts +1 -0
- package/dist/datastar/attributes/indicator.js +32 -0
- package/dist/datastar/attributes/init.d.ts +1 -0
- package/dist/datastar/attributes/init.js +27 -0
- package/dist/datastar/attributes/jsonSignals.d.ts +1 -0
- package/dist/datastar/attributes/jsonSignals.js +31 -0
- package/dist/datastar/attributes/on.d.ts +1 -0
- package/dist/datastar/attributes/on.js +59 -0
- package/dist/datastar/attributes/onIntersect.d.ts +1 -0
- package/dist/datastar/attributes/onIntersect.js +54 -0
- package/dist/datastar/attributes/onInterval.d.ts +1 -0
- package/dist/datastar/attributes/onInterval.js +31 -0
- package/dist/datastar/attributes/onSignalPatch.d.ts +1 -0
- package/dist/datastar/attributes/onSignalPatch.js +44 -0
- package/dist/datastar/attributes/ref.d.ts +1 -0
- package/dist/datastar/attributes/ref.js +11 -0
- package/dist/datastar/attributes/show.d.ts +1 -0
- package/dist/datastar/attributes/show.js +32 -0
- package/dist/datastar/attributes/signals.d.ts +1 -0
- package/dist/datastar/attributes/signals.js +18 -0
- package/dist/datastar/attributes/style.d.ts +1 -0
- package/dist/datastar/attributes/style.js +56 -0
- package/dist/datastar/attributes/text.d.ts +1 -0
- package/dist/datastar/attributes/text.js +27 -0
- package/dist/datastar/engine.d.ts +156 -0
- package/dist/datastar/engine.js +971 -0
- package/dist/datastar/index.d.ts +24 -0
- package/dist/datastar/index.js +24 -0
- package/dist/datastar/load.d.ts +24 -0
- package/dist/datastar/load.js +24 -0
- package/dist/datastar/utils.d.ts +51 -0
- package/dist/datastar/utils.js +205 -0
- package/dist/datastar/watchers/patchElements.d.ts +1 -0
- package/dist/datastar/watchers/patchElements.js +420 -0
- package/dist/datastar/watchers/patchSignals.d.ts +1 -0
- package/dist/datastar/watchers/patchSignals.js +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/node/Effectify.d.ts +209 -0
- package/dist/node/Effectify.js +19 -0
- package/dist/node/FileSystem.d.ts +3 -5
- package/dist/node/FileSystem.js +42 -62
- package/dist/node/NodeFileSystem.d.ts +7 -0
- package/dist/node/NodeFileSystem.js +420 -0
- package/dist/node/NodeUtils.d.ts +2 -0
- package/dist/node/NodeUtils.js +20 -0
- package/dist/node/PlatformError.d.ts +46 -0
- package/dist/node/PlatformError.js +43 -0
- package/dist/testing/TestLogger.js +1 -1
- package/dist/x/tailwind/plugin.js +1 -1
- package/package.json +18 -7
- package/src/Development.ts +36 -40
- package/src/Effectify.ts +269 -0
- package/src/FilePathPattern.ts +115 -0
- package/src/FileRouter.ts +178 -255
- package/src/FileRouterCodegen.ts +135 -92
- package/src/PlatformError.ts +117 -0
- package/src/PlatformRuntime.ts +108 -0
- package/src/Route.ts +31 -2
- package/src/RouteBody.ts +1 -1
- package/src/RouteHttp.ts +15 -29
- package/src/RouteMount.ts +1 -1
- package/src/Start.ts +61 -27
- package/src/Unique.ts +232 -0
- package/src/bun/BunPlatformHttpServer.ts +88 -0
- package/src/bun/BunRoute.ts +14 -24
- package/src/bun/BunRuntime.ts +21 -5
- package/src/bun/BunServer.ts +228 -0
- package/src/bun/index.ts +1 -1
- package/src/datastar/README.md +18 -0
- package/src/datastar/actions/fetch.ts +609 -0
- package/src/datastar/actions/peek.ts +17 -0
- package/src/datastar/actions/setAll.ts +20 -0
- package/src/datastar/actions/toggleAll.ts +20 -0
- package/src/datastar/attributes/attr.ts +50 -0
- package/src/datastar/attributes/bind.ts +220 -0
- package/src/datastar/attributes/class.ts +57 -0
- package/src/datastar/attributes/computed.ts +33 -0
- package/src/datastar/attributes/effect.ts +11 -0
- package/src/datastar/attributes/indicator.ts +39 -0
- package/src/datastar/attributes/init.ts +35 -0
- package/src/datastar/attributes/jsonSignals.ts +38 -0
- package/src/datastar/attributes/on.ts +71 -0
- package/src/datastar/attributes/onIntersect.ts +65 -0
- package/src/datastar/attributes/onInterval.ts +39 -0
- package/src/datastar/attributes/onSignalPatch.ts +63 -0
- package/src/datastar/attributes/ref.ts +12 -0
- package/src/datastar/attributes/show.ts +33 -0
- package/src/datastar/attributes/signals.ts +22 -0
- package/src/datastar/attributes/style.ts +63 -0
- package/src/datastar/attributes/text.ts +30 -0
- package/src/datastar/engine.ts +1341 -0
- package/src/datastar/index.ts +25 -0
- package/src/datastar/utils.ts +286 -0
- package/src/datastar/watchers/patchElements.ts +554 -0
- package/src/datastar/watchers/patchSignals.ts +15 -0
- package/src/index.ts +1 -0
- package/src/node/{FileSystem.ts → NodeFileSystem.ts} +59 -97
- package/src/node/{Utils.ts → NodeUtils.ts} +2 -0
- package/src/testing/TestLogger.ts +1 -1
- package/src/x/tailwind/plugin.ts +1 -1
- package/dist/Random.d.ts +0 -5
- package/dist/Random.js +0 -49
- package/src/Commander.test.ts +0 -1639
- package/src/ContentNegotiation.test.ts +0 -603
- package/src/Development.test.ts +0 -119
- package/src/Entity.test.ts +0 -592
- package/src/FileRouterCodegen.todo.ts +0 -1133
- package/src/FileRouterPattern.test.ts +0 -147
- package/src/FileRouterPattern.ts +0 -59
- package/src/FileRouter_files.test.ts +0 -64
- package/src/FileRouter_path.test.ts +0 -145
- package/src/FileRouter_tree.test.ts +0 -132
- package/src/Http.test.ts +0 -319
- package/src/HttpAppExtra.test.ts +0 -103
- package/src/HttpUtils.test.ts +0 -85
- package/src/PathPattern.test.ts +0 -648
- package/src/Random.ts +0 -59
- package/src/RouteBody.test.ts +0 -232
- package/src/RouteHook.test.ts +0 -40
- package/src/RouteHttp.test.ts +0 -2909
- package/src/RouteMount.test.ts +0 -481
- package/src/RouteSchema.test.ts +0 -427
- package/src/RouteSse.test.ts +0 -249
- package/src/RouteTree.test.ts +0 -494
- package/src/RouteTrie.test.ts +0 -322
- package/src/RouterPattern.test.ts +0 -676
- package/src/RouterPattern.ts +0 -416
- package/src/StartApp.ts +0 -47
- package/src/Values.test.ts +0 -263
- package/src/bun/BunBundle.test.ts +0 -268
- package/src/bun/BunBundle_imports.test.ts +0 -48
- package/src/bun/BunHttpServer.test.ts +0 -251
- package/src/bun/BunHttpServer.ts +0 -306
- package/src/bun/BunImportTrackerPlugin.test.ts +0 -77
- package/src/bun/BunRoute.test.ts +0 -162
- package/src/bundler/BundleHttp.test.ts +0 -132
- package/src/effect/HttpRouter.test.ts +0 -548
- package/src/experimental/EncryptedCookies.test.ts +0 -488
- package/src/hyper/HyperHtml.test.ts +0 -209
- package/src/hyper/HyperRoute.test.tsx +0 -197
- package/src/middlewares/BasicAuthMiddleware.test.ts +0 -84
- package/src/testing/TestHttpClient.test.ts +0 -83
- package/src/testing/TestLogger.test.ts +0 -51
- package/src/x/datastar/Datastar.test.ts +0 -266
- package/src/x/tailwind/TailwindPlugin.test.ts +0 -333
- /package/src/bun/{BunHttpServer_web.ts → BunServerRequest.ts} +0 -0
|
@@ -0,0 +1,1341 @@
|
|
|
1
|
+
import {
|
|
2
|
+
aliasify,
|
|
3
|
+
hasOwn,
|
|
4
|
+
isHTMLOrSVG,
|
|
5
|
+
isPojo,
|
|
6
|
+
pathToObj,
|
|
7
|
+
snake,
|
|
8
|
+
} from "./utils.ts"
|
|
9
|
+
|
|
10
|
+
/*********
|
|
11
|
+
* consts.ts
|
|
12
|
+
*********/
|
|
13
|
+
const lol = /🖕JS_DS🚀/.source
|
|
14
|
+
export const DSP = lol.slice(0, 5)
|
|
15
|
+
export const DSS = lol.slice(4)
|
|
16
|
+
export const DATASTAR_FETCH_EVENT = "datastar-fetch"
|
|
17
|
+
export const DATASTAR_SIGNAL_PATCH_EVENT = "datastar-signal-patch"
|
|
18
|
+
|
|
19
|
+
/*********
|
|
20
|
+
* types.ts
|
|
21
|
+
*********/
|
|
22
|
+
export type JSONPatch = Record<string, any> & { length?: never }
|
|
23
|
+
export type Paths = [string, any][]
|
|
24
|
+
|
|
25
|
+
export type DatastarFetchEvent = {
|
|
26
|
+
type: string
|
|
27
|
+
el: HTMLOrSVG
|
|
28
|
+
argsRaw: Record<string, string>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type CustomEventMap = {
|
|
32
|
+
[DATASTAR_SIGNAL_PATCH_EVENT]: CustomEvent<JSONPatch>
|
|
33
|
+
}
|
|
34
|
+
export type WatcherFn<K extends keyof CustomEventMap> = (
|
|
35
|
+
this: Document,
|
|
36
|
+
ev: CustomEventMap[K],
|
|
37
|
+
) => void
|
|
38
|
+
|
|
39
|
+
export type ErrorFn = (name: string, ctx?: Record<string, any>) => void
|
|
40
|
+
|
|
41
|
+
export type ActionContext = {
|
|
42
|
+
el: HTMLOrSVG
|
|
43
|
+
evt?: Event
|
|
44
|
+
error: ErrorFn
|
|
45
|
+
cleanups: Map<string, () => void>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type RequirementType = "allowed" | "must" | "denied" | "exclusive"
|
|
49
|
+
|
|
50
|
+
export type Requirement =
|
|
51
|
+
| RequirementType
|
|
52
|
+
| {
|
|
53
|
+
key: Exclude<RequirementType, "exclusive">
|
|
54
|
+
value?: Exclude<RequirementType, "exclusive">
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
key?: Exclude<RequirementType, "exclusive">
|
|
58
|
+
value: Exclude<RequirementType, "exclusive">
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type Rx<B extends boolean> = (...args: any[]) => B extends true ? unknown : void
|
|
62
|
+
|
|
63
|
+
type ReqField<R, K extends "key" | "value", Return> = R extends
|
|
64
|
+
| "must"
|
|
65
|
+
| { [P in K]: "must" } ? Return
|
|
66
|
+
: R extends "denied" | { [P in K]: "denied" } ? undefined
|
|
67
|
+
: R extends
|
|
68
|
+
| "allowed"
|
|
69
|
+
| { [P in K]: "allowed" }
|
|
70
|
+
| (K extends keyof R ? never : R) ? Return | undefined
|
|
71
|
+
: never
|
|
72
|
+
|
|
73
|
+
type ReqFields<R extends Requirement, B extends boolean> = R extends "exclusive"
|
|
74
|
+
?
|
|
75
|
+
| { key: string; value: undefined; rx: undefined }
|
|
76
|
+
| { key: undefined; value: string; rx: Rx<B> }
|
|
77
|
+
: {
|
|
78
|
+
key: ReqField<R, "key", string>
|
|
79
|
+
value: ReqField<R, "value", string>
|
|
80
|
+
rx: ReqField<R, "value", Rx<B>>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type AttributeContext<
|
|
84
|
+
R extends Requirement = Requirement,
|
|
85
|
+
RxReturn extends boolean = boolean,
|
|
86
|
+
> = {
|
|
87
|
+
el: HTMLOrSVG
|
|
88
|
+
mods: Modifiers
|
|
89
|
+
rawKey: string
|
|
90
|
+
evt?: Event
|
|
91
|
+
error: ErrorFn
|
|
92
|
+
loadedPluginNames: {
|
|
93
|
+
actions: Readonly<Set<string>>
|
|
94
|
+
attributes: Readonly<Set<string>>
|
|
95
|
+
}
|
|
96
|
+
} & ReqFields<R, RxReturn>
|
|
97
|
+
|
|
98
|
+
export type AttributePlugin<
|
|
99
|
+
R extends Requirement = Requirement,
|
|
100
|
+
RxReturn extends boolean = boolean,
|
|
101
|
+
> = {
|
|
102
|
+
name: string
|
|
103
|
+
apply: (ctx: AttributeContext<R, RxReturn>) => void | (() => void)
|
|
104
|
+
requirement?: R
|
|
105
|
+
returnsValue?: RxReturn
|
|
106
|
+
argNames?: string[]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type WatcherContext = {
|
|
110
|
+
error: ErrorFn
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type WatcherPlugin = {
|
|
114
|
+
name: string
|
|
115
|
+
apply: (ctx: WatcherContext, args: Record<string, string | undefined>) => void
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type ActionPlugins = Record<string, ActionPlugin>
|
|
119
|
+
|
|
120
|
+
export type ActionPlugin<T = any> = {
|
|
121
|
+
name: string
|
|
122
|
+
apply: (ctx: ActionContext, ...args: any[]) => T
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type MergePatchArgs = {
|
|
126
|
+
ifMissing?: boolean
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export type HTMLOrSVG = HTMLElement | SVGElement | MathMLElement
|
|
130
|
+
export type Modifiers = Map<string, Set<string>>
|
|
131
|
+
|
|
132
|
+
export type EventCallbackHandler = (...args: any[]) => void
|
|
133
|
+
|
|
134
|
+
export type SignalFilter = RegExp
|
|
135
|
+
export type SignalFilterOptions = {
|
|
136
|
+
include?: RegExp | string
|
|
137
|
+
exclude?: RegExp | string
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export type Signal<T> = {
|
|
141
|
+
(): T
|
|
142
|
+
(value: T): boolean
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export type Computed<T> = () => T
|
|
146
|
+
|
|
147
|
+
export type Effect = () => void
|
|
148
|
+
|
|
149
|
+
/*********
|
|
150
|
+
* signals.ts
|
|
151
|
+
*********/
|
|
152
|
+
interface ReactiveNode {
|
|
153
|
+
deps_?: Link
|
|
154
|
+
depsTail_?: Link
|
|
155
|
+
subs_?: Link
|
|
156
|
+
subsTail_?: Link
|
|
157
|
+
flags_: ReactiveFlags
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface Link {
|
|
161
|
+
version_: number
|
|
162
|
+
dep_: ReactiveNode
|
|
163
|
+
sub_: ReactiveNode
|
|
164
|
+
prevSub_?: Link
|
|
165
|
+
nextSub_?: Link
|
|
166
|
+
prevDep_?: Link
|
|
167
|
+
nextDep_?: Link
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
interface Stack<T> {
|
|
171
|
+
value_: T
|
|
172
|
+
prev_?: Stack<T>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const ReactiveFlags = {
|
|
176
|
+
None: 0,
|
|
177
|
+
Mutable: 1 << 0,
|
|
178
|
+
Watching: 1 << 1,
|
|
179
|
+
RecursedCheck: 1 << 2,
|
|
180
|
+
Recursed: 1 << 3,
|
|
181
|
+
Dirty: 1 << 4,
|
|
182
|
+
Pending: 1 << 5,
|
|
183
|
+
} as const
|
|
184
|
+
type ReactiveFlags = typeof ReactiveFlags[keyof typeof ReactiveFlags]
|
|
185
|
+
type ReactiveFlags_None = typeof ReactiveFlags.None
|
|
186
|
+
type ReactiveFlags_Mutable = typeof ReactiveFlags.Mutable
|
|
187
|
+
type ReactiveFlags_Watching = typeof ReactiveFlags.Watching
|
|
188
|
+
type ReactiveFlags_RecursedCheck = typeof ReactiveFlags.RecursedCheck
|
|
189
|
+
type ReactiveFlags_Recursed = typeof ReactiveFlags.Recursed
|
|
190
|
+
type ReactiveFlags_Dirty = typeof ReactiveFlags.Dirty
|
|
191
|
+
type ReactiveFlags_Pending = typeof ReactiveFlags.Pending
|
|
192
|
+
|
|
193
|
+
const EffectFlags = {
|
|
194
|
+
Queued: 1 << 6,
|
|
195
|
+
} as const
|
|
196
|
+
type EffectFlags_Queued = typeof EffectFlags.Queued
|
|
197
|
+
|
|
198
|
+
interface AlienEffect extends ReactiveNode {
|
|
199
|
+
fn_(): void
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
interface AlienComputed<T = unknown> extends ReactiveNode {
|
|
203
|
+
value_?: T
|
|
204
|
+
getter(previousValue?: T): T
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface AlienSignal<T = unknown> extends ReactiveNode {
|
|
208
|
+
previousValue: T
|
|
209
|
+
value_: T
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const currentPatch: Paths = []
|
|
213
|
+
const queuedEffects: (AlienEffect | undefined)[] = []
|
|
214
|
+
let batchDepth = 0
|
|
215
|
+
let notifyIndex = 0
|
|
216
|
+
let queuedEffectsLength = 0
|
|
217
|
+
let prevSub: ReactiveNode | undefined
|
|
218
|
+
let activeSub: ReactiveNode | undefined
|
|
219
|
+
let version = 0
|
|
220
|
+
|
|
221
|
+
export const beginBatch = (): void => {
|
|
222
|
+
batchDepth++
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const endBatch = (): void => {
|
|
226
|
+
if (!--batchDepth) {
|
|
227
|
+
flush()
|
|
228
|
+
dispatch()
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export const startPeeking = (sub?: ReactiveNode): void => {
|
|
233
|
+
prevSub = activeSub
|
|
234
|
+
activeSub = sub
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export const stopPeeking = (): void => {
|
|
238
|
+
activeSub = prevSub
|
|
239
|
+
prevSub = undefined
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export const signal = <T>(initialValue?: T): Signal<T> => {
|
|
243
|
+
return signalOper.bind(0, {
|
|
244
|
+
previousValue: initialValue,
|
|
245
|
+
value_: initialValue,
|
|
246
|
+
flags_: 1 satisfies ReactiveFlags_Mutable,
|
|
247
|
+
}) as Signal<T>
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const computedSymbol = Symbol("computed")
|
|
251
|
+
export const computed = <T>(getter: (previousValue?: T) => T): Computed<T> => {
|
|
252
|
+
const c = computedOper.bind(0, {
|
|
253
|
+
flags_: 17 as ReactiveFlags_Mutable | ReactiveFlags_Dirty,
|
|
254
|
+
getter,
|
|
255
|
+
}) as Computed<T>
|
|
256
|
+
// @ts-ignore
|
|
257
|
+
c[computedSymbol] = 1
|
|
258
|
+
return c
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const effect = (fn: () => void): Effect => {
|
|
262
|
+
const e: AlienEffect = {
|
|
263
|
+
fn_: fn,
|
|
264
|
+
flags_: 2 satisfies ReactiveFlags_Watching,
|
|
265
|
+
}
|
|
266
|
+
if (activeSub) {
|
|
267
|
+
link(e, activeSub)
|
|
268
|
+
}
|
|
269
|
+
startPeeking(e)
|
|
270
|
+
beginBatch()
|
|
271
|
+
try {
|
|
272
|
+
e.fn_()
|
|
273
|
+
} finally {
|
|
274
|
+
endBatch()
|
|
275
|
+
stopPeeking()
|
|
276
|
+
}
|
|
277
|
+
return effectOper.bind(0, e)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const flush = () => {
|
|
281
|
+
while (notifyIndex < queuedEffectsLength) {
|
|
282
|
+
const effect = queuedEffects[notifyIndex]!
|
|
283
|
+
queuedEffects[notifyIndex++] = undefined
|
|
284
|
+
run(effect, effect.flags_ &= ~EffectFlags.Queued)
|
|
285
|
+
}
|
|
286
|
+
notifyIndex = 0
|
|
287
|
+
queuedEffectsLength = 0
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const update = (signal: AlienSignal | AlienComputed): boolean => {
|
|
291
|
+
if ("getter" in signal) {
|
|
292
|
+
return updateComputed(signal)
|
|
293
|
+
}
|
|
294
|
+
return updateSignal(signal, signal.value_)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const updateComputed = (c: AlienComputed): boolean => {
|
|
298
|
+
startPeeking(c)
|
|
299
|
+
startTracking(c)
|
|
300
|
+
try {
|
|
301
|
+
const oldValue = c.value_
|
|
302
|
+
return oldValue !== (c.value_ = c.getter(oldValue))
|
|
303
|
+
} finally {
|
|
304
|
+
stopPeeking()
|
|
305
|
+
endTracking(c)
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const updateSignal = <T>(s: AlienSignal<T>, value: T): boolean => {
|
|
310
|
+
s.flags_ = 1 satisfies ReactiveFlags_Mutable
|
|
311
|
+
return s.previousValue !== (s.previousValue = value)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const notify = (e: AlienEffect): void => {
|
|
315
|
+
const flags = e.flags_
|
|
316
|
+
if (!(flags & EffectFlags.Queued)) {
|
|
317
|
+
e.flags_ = flags | EffectFlags.Queued
|
|
318
|
+
const subs = e.subs_
|
|
319
|
+
if (subs) {
|
|
320
|
+
notify(subs.sub_ as AlienEffect)
|
|
321
|
+
} else {
|
|
322
|
+
queuedEffects[queuedEffectsLength++] = e
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const run = (e: AlienEffect, flags: ReactiveFlags): void => {
|
|
328
|
+
if (
|
|
329
|
+
flags & (16 satisfies ReactiveFlags_Dirty)
|
|
330
|
+
|| (flags & (32 satisfies ReactiveFlags_Pending) && checkDirty(e.deps_!, e))
|
|
331
|
+
) {
|
|
332
|
+
startPeeking(e)
|
|
333
|
+
startTracking(e)
|
|
334
|
+
beginBatch()
|
|
335
|
+
try {
|
|
336
|
+
e.fn_()
|
|
337
|
+
} finally {
|
|
338
|
+
endBatch()
|
|
339
|
+
stopPeeking()
|
|
340
|
+
endTracking(e)
|
|
341
|
+
}
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
if (flags & (32 satisfies ReactiveFlags_Pending)) {
|
|
345
|
+
e.flags_ = flags & ~(32 satisfies ReactiveFlags_Pending)
|
|
346
|
+
}
|
|
347
|
+
let link = e.deps_
|
|
348
|
+
while (link) {
|
|
349
|
+
const dep = link.dep_
|
|
350
|
+
const depFlags = dep.flags_
|
|
351
|
+
if (depFlags & EffectFlags.Queued) {
|
|
352
|
+
run(dep as AlienEffect, dep.flags_ = depFlags & ~EffectFlags.Queued)
|
|
353
|
+
}
|
|
354
|
+
link = link.nextDep_
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const signalOper = <T>(s: AlienSignal<T>, ...value: [T]): T | boolean => {
|
|
359
|
+
if (value.length) {
|
|
360
|
+
if (s.value_ !== (s.value_ = value[0])) {
|
|
361
|
+
s.flags_ = 17 as ReactiveFlags_Mutable | ReactiveFlags_Dirty
|
|
362
|
+
const subs = s.subs_
|
|
363
|
+
if (subs) {
|
|
364
|
+
propagate(subs)
|
|
365
|
+
if (!batchDepth) {
|
|
366
|
+
flush()
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return true
|
|
370
|
+
}
|
|
371
|
+
return false
|
|
372
|
+
}
|
|
373
|
+
const currentValue = s.value_
|
|
374
|
+
if (s.flags_ & (16 satisfies ReactiveFlags_Dirty)) {
|
|
375
|
+
if (updateSignal(s, currentValue)) {
|
|
376
|
+
const subs_ = s.subs_
|
|
377
|
+
if (subs_) {
|
|
378
|
+
shallowPropagate(subs_)
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (activeSub) {
|
|
383
|
+
link(s, activeSub)
|
|
384
|
+
}
|
|
385
|
+
return currentValue
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const computedOper = <T>(c: AlienComputed<T>): T => {
|
|
389
|
+
const flags = c.flags_
|
|
390
|
+
if (
|
|
391
|
+
flags & (16 satisfies ReactiveFlags_Dirty)
|
|
392
|
+
|| (flags & (32 satisfies ReactiveFlags_Pending) && checkDirty(c.deps_!, c))
|
|
393
|
+
) {
|
|
394
|
+
if (updateComputed(c)) {
|
|
395
|
+
const subs = c.subs_
|
|
396
|
+
if (subs) {
|
|
397
|
+
shallowPropagate(subs)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} else if (flags & (32 satisfies ReactiveFlags_Pending)) {
|
|
401
|
+
c.flags_ = flags & ~(32 satisfies ReactiveFlags_Pending)
|
|
402
|
+
}
|
|
403
|
+
if (activeSub) {
|
|
404
|
+
link(c, activeSub)
|
|
405
|
+
}
|
|
406
|
+
return c.value_!
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const effectOper = (e: AlienEffect): void => {
|
|
410
|
+
let dep = e.deps_
|
|
411
|
+
while (dep) {
|
|
412
|
+
dep = unlink(dep, e)
|
|
413
|
+
}
|
|
414
|
+
const sub = e.subs_
|
|
415
|
+
if (sub) {
|
|
416
|
+
unlink(sub)
|
|
417
|
+
}
|
|
418
|
+
e.flags_ = 0 satisfies ReactiveFlags_None
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const link = (dep: ReactiveNode, sub: ReactiveNode): void => {
|
|
422
|
+
const prevDep = sub.depsTail_
|
|
423
|
+
if (prevDep && prevDep.dep_ === dep) {
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
const nextDep = prevDep ? prevDep.nextDep_ : sub.deps_
|
|
427
|
+
if (nextDep && nextDep.dep_ === dep) {
|
|
428
|
+
nextDep.version_ = version
|
|
429
|
+
sub.depsTail_ = nextDep
|
|
430
|
+
return
|
|
431
|
+
}
|
|
432
|
+
const prevSub = dep.subsTail_
|
|
433
|
+
if (prevSub && prevSub.version_ === version && prevSub.sub_ === sub) {
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
const newLink = (sub.depsTail_ =
|
|
437
|
+
dep.subsTail_ =
|
|
438
|
+
{
|
|
439
|
+
version_: version,
|
|
440
|
+
dep_: dep,
|
|
441
|
+
sub_: sub,
|
|
442
|
+
prevDep_: prevDep,
|
|
443
|
+
nextDep_: nextDep,
|
|
444
|
+
prevSub_: prevSub,
|
|
445
|
+
})
|
|
446
|
+
if (nextDep) {
|
|
447
|
+
nextDep.prevDep_ = newLink
|
|
448
|
+
}
|
|
449
|
+
if (prevDep) {
|
|
450
|
+
prevDep.nextDep_ = newLink
|
|
451
|
+
} else {
|
|
452
|
+
sub.deps_ = newLink
|
|
453
|
+
}
|
|
454
|
+
if (prevSub) {
|
|
455
|
+
prevSub.nextSub_ = newLink
|
|
456
|
+
} else {
|
|
457
|
+
dep.subs_ = newLink
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const unlink = (link: Link, sub = link.sub_): Link | undefined => {
|
|
462
|
+
const dep_ = link.dep_
|
|
463
|
+
const prevDep_ = link.prevDep_
|
|
464
|
+
const nextDep_ = link.nextDep_
|
|
465
|
+
const nextSub_ = link.nextSub_
|
|
466
|
+
const prevSub_ = link.prevSub_
|
|
467
|
+
if (nextDep_) {
|
|
468
|
+
nextDep_.prevDep_ = prevDep_
|
|
469
|
+
} else {
|
|
470
|
+
sub.depsTail_ = prevDep_
|
|
471
|
+
}
|
|
472
|
+
if (prevDep_) {
|
|
473
|
+
prevDep_.nextDep_ = nextDep_
|
|
474
|
+
} else {
|
|
475
|
+
sub.deps_ = nextDep_
|
|
476
|
+
}
|
|
477
|
+
if (nextSub_) {
|
|
478
|
+
nextSub_.prevSub_ = prevSub_
|
|
479
|
+
} else {
|
|
480
|
+
dep_.subsTail_ = prevSub_
|
|
481
|
+
}
|
|
482
|
+
if (prevSub_) {
|
|
483
|
+
prevSub_.nextSub_ = nextSub_
|
|
484
|
+
} else if (!(dep_.subs_ = nextSub_)) {
|
|
485
|
+
if ("getter" in dep_) {
|
|
486
|
+
let toRemove = dep_.deps_
|
|
487
|
+
if (toRemove) {
|
|
488
|
+
dep_.flags_ = 17 as ReactiveFlags_Mutable | ReactiveFlags_Dirty
|
|
489
|
+
do {
|
|
490
|
+
toRemove = unlink(toRemove, dep_)
|
|
491
|
+
} while (toRemove)
|
|
492
|
+
}
|
|
493
|
+
} else if (!("previousValue" in dep_)) {
|
|
494
|
+
effectOper(dep_ as AlienEffect)
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return nextDep_
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const propagate = (link: Link): void => {
|
|
501
|
+
let next = link.nextSub_
|
|
502
|
+
let stack: Stack<Link | undefined> | undefined
|
|
503
|
+
|
|
504
|
+
top: while (true) {
|
|
505
|
+
const sub = link.sub_
|
|
506
|
+
|
|
507
|
+
let flags = sub.flags_
|
|
508
|
+
|
|
509
|
+
if (
|
|
510
|
+
!(
|
|
511
|
+
flags
|
|
512
|
+
& (60 as
|
|
513
|
+
| ReactiveFlags_RecursedCheck
|
|
514
|
+
| ReactiveFlags_Recursed
|
|
515
|
+
| ReactiveFlags_Dirty
|
|
516
|
+
| ReactiveFlags_Pending)
|
|
517
|
+
)
|
|
518
|
+
) {
|
|
519
|
+
sub.flags_ = flags | (32 satisfies ReactiveFlags_Pending)
|
|
520
|
+
} else if (
|
|
521
|
+
!(flags & (12 as ReactiveFlags_RecursedCheck | ReactiveFlags_Recursed))
|
|
522
|
+
) {
|
|
523
|
+
flags = 0 satisfies ReactiveFlags_None
|
|
524
|
+
} else if (!(flags & (4 satisfies ReactiveFlags_RecursedCheck))) {
|
|
525
|
+
sub.flags_ = (flags & ~(8 satisfies ReactiveFlags_Recursed))
|
|
526
|
+
| (32 satisfies ReactiveFlags_Pending)
|
|
527
|
+
} else if (
|
|
528
|
+
!(flags & (48 as ReactiveFlags_Dirty | ReactiveFlags_Pending))
|
|
529
|
+
&& isValidLink(link, sub)
|
|
530
|
+
) {
|
|
531
|
+
sub.flags_ = flags
|
|
532
|
+
| (40 as ReactiveFlags_Recursed | ReactiveFlags_Pending)
|
|
533
|
+
flags &= 1 satisfies ReactiveFlags_Mutable
|
|
534
|
+
} else {
|
|
535
|
+
flags = 0 satisfies ReactiveFlags_None
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (flags & (2 satisfies ReactiveFlags_Watching)) {
|
|
539
|
+
notify(sub as AlienEffect)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (flags & (1 satisfies ReactiveFlags_Mutable)) {
|
|
543
|
+
const subSubs = sub.subs_
|
|
544
|
+
if (subSubs) {
|
|
545
|
+
const nextSub = (link = subSubs).nextSub_
|
|
546
|
+
if (nextSub) {
|
|
547
|
+
stack = { value_: next, prev_: stack }
|
|
548
|
+
next = nextSub
|
|
549
|
+
}
|
|
550
|
+
continue
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if ((link = next!)) {
|
|
555
|
+
next = link.nextSub_
|
|
556
|
+
continue
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
while (stack) {
|
|
560
|
+
link = stack.value_!
|
|
561
|
+
stack = stack.prev_
|
|
562
|
+
if (link) {
|
|
563
|
+
next = link.nextSub_
|
|
564
|
+
continue top
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
break
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const startTracking = (sub: ReactiveNode): void => {
|
|
573
|
+
version++
|
|
574
|
+
sub.depsTail_ = undefined
|
|
575
|
+
sub.flags_ = (sub.flags_
|
|
576
|
+
& ~(56 as
|
|
577
|
+
| ReactiveFlags_Recursed
|
|
578
|
+
| ReactiveFlags_Dirty
|
|
579
|
+
| ReactiveFlags_Pending))
|
|
580
|
+
| (4 satisfies ReactiveFlags_RecursedCheck)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const endTracking = (sub: ReactiveNode): void => {
|
|
584
|
+
const depsTail_ = sub.depsTail_
|
|
585
|
+
let toRemove = depsTail_ ? depsTail_.nextDep_ : sub.deps_
|
|
586
|
+
while (toRemove) {
|
|
587
|
+
toRemove = unlink(toRemove, sub)
|
|
588
|
+
}
|
|
589
|
+
sub.flags_ &= ~(4 satisfies ReactiveFlags_RecursedCheck)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const checkDirty = (link: Link, sub: ReactiveNode): boolean => {
|
|
593
|
+
let stack: Stack<Link> | undefined
|
|
594
|
+
let checkDepth = 0
|
|
595
|
+
let dirty = false
|
|
596
|
+
|
|
597
|
+
top: while (true) {
|
|
598
|
+
const dep = link.dep_
|
|
599
|
+
const flags = dep.flags_
|
|
600
|
+
|
|
601
|
+
if (sub.flags_ & (16 satisfies ReactiveFlags_Dirty)) {
|
|
602
|
+
dirty = true
|
|
603
|
+
} else if (
|
|
604
|
+
(flags & (17 as ReactiveFlags_Mutable | ReactiveFlags_Dirty))
|
|
605
|
+
=== (17 as ReactiveFlags_Mutable | ReactiveFlags_Dirty)
|
|
606
|
+
) {
|
|
607
|
+
if (update(dep as AlienSignal | AlienComputed)) {
|
|
608
|
+
const subs = dep.subs_!
|
|
609
|
+
if (subs.nextSub_) {
|
|
610
|
+
shallowPropagate(subs)
|
|
611
|
+
}
|
|
612
|
+
dirty = true
|
|
613
|
+
}
|
|
614
|
+
} else if (
|
|
615
|
+
(flags & (33 as ReactiveFlags_Mutable | ReactiveFlags_Pending))
|
|
616
|
+
=== (33 as ReactiveFlags_Mutable | ReactiveFlags_Pending)
|
|
617
|
+
) {
|
|
618
|
+
if (link.nextSub_ || link.prevSub_) {
|
|
619
|
+
stack = { value_: link, prev_: stack }
|
|
620
|
+
}
|
|
621
|
+
link = dep.deps_!
|
|
622
|
+
sub = dep
|
|
623
|
+
++checkDepth
|
|
624
|
+
continue
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (!dirty) {
|
|
628
|
+
const nextDep = link.nextDep_
|
|
629
|
+
if (nextDep) {
|
|
630
|
+
link = nextDep
|
|
631
|
+
continue
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
while (checkDepth--) {
|
|
636
|
+
const firstSub = sub.subs_!
|
|
637
|
+
const hasMultipleSubs = firstSub.nextSub_
|
|
638
|
+
if (hasMultipleSubs) {
|
|
639
|
+
link = stack!.value_
|
|
640
|
+
stack = stack!.prev_
|
|
641
|
+
} else {
|
|
642
|
+
link = firstSub
|
|
643
|
+
}
|
|
644
|
+
if (dirty) {
|
|
645
|
+
if (update(sub as AlienSignal | AlienComputed)) {
|
|
646
|
+
if (hasMultipleSubs) {
|
|
647
|
+
shallowPropagate(firstSub)
|
|
648
|
+
}
|
|
649
|
+
sub = link.sub_
|
|
650
|
+
continue
|
|
651
|
+
}
|
|
652
|
+
dirty = false
|
|
653
|
+
} else {
|
|
654
|
+
sub.flags_ &= ~(32 satisfies ReactiveFlags_Pending)
|
|
655
|
+
}
|
|
656
|
+
sub = link.sub_
|
|
657
|
+
if (link.nextDep_) {
|
|
658
|
+
link = link.nextDep_
|
|
659
|
+
continue top
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return dirty
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const shallowPropagate = (link: Link): void => {
|
|
668
|
+
do {
|
|
669
|
+
const sub = link.sub_
|
|
670
|
+
const flags = sub.flags_
|
|
671
|
+
if (
|
|
672
|
+
(flags & (48 as ReactiveFlags_Pending | ReactiveFlags_Dirty))
|
|
673
|
+
=== (32 satisfies ReactiveFlags_Pending)
|
|
674
|
+
) {
|
|
675
|
+
sub.flags_ = flags | (16 satisfies ReactiveFlags_Dirty)
|
|
676
|
+
if (flags & (2 satisfies ReactiveFlags_Watching)) {
|
|
677
|
+
notify(sub as AlienEffect)
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
} while ((link = link.nextSub_!))
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const isValidLink = (checkLink: Link, sub: ReactiveNode): boolean => {
|
|
684
|
+
let link = sub.depsTail_
|
|
685
|
+
while (link) {
|
|
686
|
+
if (link === checkLink) {
|
|
687
|
+
return true
|
|
688
|
+
}
|
|
689
|
+
link = link.prevDep_
|
|
690
|
+
}
|
|
691
|
+
return false
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export const getPath = <T = any>(path: string): T | undefined => {
|
|
695
|
+
let result = root
|
|
696
|
+
const split = path.split(".")
|
|
697
|
+
for (const path of split) {
|
|
698
|
+
if (result == null || !hasOwn(result, path)) {
|
|
699
|
+
return
|
|
700
|
+
}
|
|
701
|
+
result = result[path]
|
|
702
|
+
}
|
|
703
|
+
return result as T
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const deep = (value: any, prefix = ""): any => {
|
|
707
|
+
const isArr = Array.isArray(value)
|
|
708
|
+
if (isArr || isPojo(value)) {
|
|
709
|
+
const deepObj = (isArr ? [] : {}) as Record<string, Signal<any>>
|
|
710
|
+
for (const key in value) {
|
|
711
|
+
deepObj[key] = signal(
|
|
712
|
+
deep((value as Record<string, Signal<any>>)[key], `${prefix + key}.`),
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
const keys = signal(0)
|
|
716
|
+
return new Proxy(deepObj, {
|
|
717
|
+
get(_, prop: string) {
|
|
718
|
+
if (!(prop === "toJSON" && !hasOwn(deepObj, prop))) {
|
|
719
|
+
if (isArr && prop in Array.prototype) {
|
|
720
|
+
keys()
|
|
721
|
+
return deepObj[prop]
|
|
722
|
+
}
|
|
723
|
+
if (typeof prop === "symbol") {
|
|
724
|
+
return deepObj[prop]
|
|
725
|
+
}
|
|
726
|
+
if (!hasOwn(deepObj, prop) || deepObj[prop]() == null) {
|
|
727
|
+
deepObj[prop] = signal("")
|
|
728
|
+
dispatch(prefix + prop, "")
|
|
729
|
+
keys(keys() + 1)
|
|
730
|
+
}
|
|
731
|
+
return deepObj[prop]()
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
set(_, prop: string, newValue) {
|
|
735
|
+
const path = prefix + prop
|
|
736
|
+
if (isArr && prop === "length") {
|
|
737
|
+
const diff = (deepObj[prop] as unknown as number) - newValue
|
|
738
|
+
deepObj[prop] = newValue
|
|
739
|
+
if (diff > 0) {
|
|
740
|
+
const patch: Record<string, any> = {}
|
|
741
|
+
for (let i = newValue; i < deepObj[prop]; i++) {
|
|
742
|
+
patch[i] = null
|
|
743
|
+
}
|
|
744
|
+
dispatch(prefix.slice(0, -1), patch)
|
|
745
|
+
keys(keys() + 1)
|
|
746
|
+
}
|
|
747
|
+
} else if (hasOwn(deepObj, prop)) {
|
|
748
|
+
if (newValue == null) {
|
|
749
|
+
delete deepObj[prop]
|
|
750
|
+
} else if (hasOwn(newValue, computedSymbol)) {
|
|
751
|
+
deepObj[prop] = newValue
|
|
752
|
+
dispatch(path, "")
|
|
753
|
+
} else {
|
|
754
|
+
const currentValue = deepObj[prop]()
|
|
755
|
+
const pathStr = `${path}.`
|
|
756
|
+
if (isPojo(currentValue) && isPojo(newValue)) {
|
|
757
|
+
for (const key in currentValue) {
|
|
758
|
+
if (!hasOwn(newValue, key)) {
|
|
759
|
+
delete currentValue[key]
|
|
760
|
+
dispatch(pathStr + key, null)
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
for (const key in newValue) {
|
|
764
|
+
const nextVal = newValue[key]
|
|
765
|
+
if (currentValue[key] !== nextVal) {
|
|
766
|
+
currentValue[key] = nextVal
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
} else if (deepObj[prop](deep(newValue, pathStr))) {
|
|
770
|
+
dispatch(path, newValue)
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
} else if (newValue != null) {
|
|
774
|
+
if (hasOwn(newValue, computedSymbol)) {
|
|
775
|
+
deepObj[prop] = newValue
|
|
776
|
+
dispatch(path, "")
|
|
777
|
+
} else {
|
|
778
|
+
deepObj[prop] = signal(deep(newValue, `${path}.`))
|
|
779
|
+
dispatch(path, newValue)
|
|
780
|
+
}
|
|
781
|
+
keys(keys() + 1)
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return true
|
|
785
|
+
},
|
|
786
|
+
deleteProperty(_, prop: string) {
|
|
787
|
+
delete deepObj[prop]
|
|
788
|
+
keys(keys() + 1)
|
|
789
|
+
return true
|
|
790
|
+
},
|
|
791
|
+
ownKeys() {
|
|
792
|
+
keys()
|
|
793
|
+
return Reflect.ownKeys(deepObj)
|
|
794
|
+
},
|
|
795
|
+
has(_, prop) {
|
|
796
|
+
keys()
|
|
797
|
+
return prop in deepObj
|
|
798
|
+
},
|
|
799
|
+
})
|
|
800
|
+
}
|
|
801
|
+
return value
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const dispatch = (path?: string, value?: any) => {
|
|
805
|
+
if (path !== undefined && value !== undefined) {
|
|
806
|
+
currentPatch.push([path, value])
|
|
807
|
+
}
|
|
808
|
+
if (!batchDepth && currentPatch.length) {
|
|
809
|
+
const detail = pathToObj(currentPatch)
|
|
810
|
+
currentPatch.length = 0
|
|
811
|
+
document.dispatchEvent(
|
|
812
|
+
new CustomEvent<JSONPatch>(DATASTAR_SIGNAL_PATCH_EVENT, {
|
|
813
|
+
detail,
|
|
814
|
+
}),
|
|
815
|
+
)
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export const mergePatch = (
|
|
820
|
+
patch: JSONPatch,
|
|
821
|
+
{ ifMissing }: MergePatchArgs = {},
|
|
822
|
+
): void => {
|
|
823
|
+
beginBatch()
|
|
824
|
+
for (const key in patch) {
|
|
825
|
+
if (patch[key] == null) {
|
|
826
|
+
if (!ifMissing) {
|
|
827
|
+
delete root[key]
|
|
828
|
+
}
|
|
829
|
+
} else {
|
|
830
|
+
mergeInner(patch[key], key, root, "", ifMissing)
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
endBatch()
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
export const mergePaths = (paths: Paths, options?: MergePatchArgs): void =>
|
|
837
|
+
mergePatch(pathToObj(paths), options)
|
|
838
|
+
|
|
839
|
+
const mergeInner = (
|
|
840
|
+
patch: any,
|
|
841
|
+
target: string,
|
|
842
|
+
targetParent: Record<string, any>,
|
|
843
|
+
prefix: string,
|
|
844
|
+
ifMissing: boolean | undefined,
|
|
845
|
+
): void => {
|
|
846
|
+
if (isPojo(patch)) {
|
|
847
|
+
if (
|
|
848
|
+
!(
|
|
849
|
+
hasOwn(targetParent, target)
|
|
850
|
+
&& (isPojo(targetParent[target]) || Array.isArray(targetParent[target]))
|
|
851
|
+
)
|
|
852
|
+
) {
|
|
853
|
+
targetParent[target] = {}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
for (const key in patch) {
|
|
857
|
+
if (patch[key] == null) {
|
|
858
|
+
if (!ifMissing) {
|
|
859
|
+
delete targetParent[target][key]
|
|
860
|
+
}
|
|
861
|
+
} else {
|
|
862
|
+
mergeInner(
|
|
863
|
+
patch[key],
|
|
864
|
+
key,
|
|
865
|
+
targetParent[target],
|
|
866
|
+
`${prefix + target}.`,
|
|
867
|
+
ifMissing,
|
|
868
|
+
)
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
} else if (!(ifMissing && hasOwn(targetParent, target))) {
|
|
872
|
+
targetParent[target] = patch
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
const toRegExp = (val: string | RegExp): RegExp =>
|
|
877
|
+
typeof val === "string" ? RegExp(val.replace(/^\/|\/$/g, "")) : val
|
|
878
|
+
|
|
879
|
+
export const filtered = (
|
|
880
|
+
{ include = /.*/, exclude = /(?!)/ }: SignalFilterOptions = {},
|
|
881
|
+
obj: JSONPatch = root,
|
|
882
|
+
): Record<string, any> => {
|
|
883
|
+
const includeRe = toRegExp(include)
|
|
884
|
+
const excludeRe = toRegExp(exclude)
|
|
885
|
+
const paths: Paths = []
|
|
886
|
+
const stack: [any, string][] = [[obj, ""]]
|
|
887
|
+
|
|
888
|
+
while (stack.length) {
|
|
889
|
+
const [node, prefix] = stack.pop()!
|
|
890
|
+
|
|
891
|
+
for (const key in node) {
|
|
892
|
+
const path = prefix + key
|
|
893
|
+
if (isPojo(node[key])) {
|
|
894
|
+
stack.push([node[key], `${path}.`])
|
|
895
|
+
} else if (includeRe.test(path) && !excludeRe.test(path)) {
|
|
896
|
+
paths.push([path, getPath(path)])
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return pathToObj(paths)
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
export const root: Record<string, any> = deep({})
|
|
905
|
+
|
|
906
|
+
/*********
|
|
907
|
+
* engine.ts (plugin system)
|
|
908
|
+
*********/
|
|
909
|
+
const url = "https://data-star.dev/errors"
|
|
910
|
+
|
|
911
|
+
const error = (
|
|
912
|
+
ctx: Record<string, any>,
|
|
913
|
+
reason: string,
|
|
914
|
+
metadata: Record<string, any> = {},
|
|
915
|
+
) => {
|
|
916
|
+
Object.assign(metadata, ctx)
|
|
917
|
+
const e = new Error()
|
|
918
|
+
const r = snake(reason)
|
|
919
|
+
const q = new URLSearchParams({
|
|
920
|
+
metadata: JSON.stringify(metadata),
|
|
921
|
+
})
|
|
922
|
+
.toString()
|
|
923
|
+
const c = JSON.stringify(metadata, null, 2)
|
|
924
|
+
e.message = `${reason}\nMore info: ${url}/${r}?${q}\nContext: ${c}`
|
|
925
|
+
return e
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
const actionPlugins: Map<string, ActionPlugin> = new Map()
|
|
929
|
+
const attributePlugins: Map<string, AttributePlugin> = new Map()
|
|
930
|
+
const watcherPlugins: Map<string, WatcherPlugin> = new Map()
|
|
931
|
+
|
|
932
|
+
export const actions: Record<
|
|
933
|
+
string,
|
|
934
|
+
(ctx: ActionContext, ...args: any[]) => any
|
|
935
|
+
> = new Proxy(
|
|
936
|
+
{},
|
|
937
|
+
{
|
|
938
|
+
get: (_, prop: string) => actionPlugins.get(prop)?.apply,
|
|
939
|
+
has: (_, prop: string) => actionPlugins.has(prop),
|
|
940
|
+
ownKeys: () => Reflect.ownKeys(actionPlugins),
|
|
941
|
+
set: () => false,
|
|
942
|
+
deleteProperty: () => false,
|
|
943
|
+
},
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
const removals = new Map<HTMLOrSVG, Map<string, Map<string, () => void>>>()
|
|
947
|
+
|
|
948
|
+
const queuedAttributes: AttributePlugin[] = []
|
|
949
|
+
const queuedAttributeNames = new Set<string>()
|
|
950
|
+
const observedRoots = new WeakSet<Node>()
|
|
951
|
+
export const attribute = <R extends Requirement, B extends boolean>(
|
|
952
|
+
plugin: AttributePlugin<R, B>,
|
|
953
|
+
): void => {
|
|
954
|
+
queuedAttributes.push(plugin as unknown as AttributePlugin)
|
|
955
|
+
|
|
956
|
+
if (queuedAttributes.length === 1) {
|
|
957
|
+
setTimeout(() => {
|
|
958
|
+
for (const attribute of queuedAttributes) {
|
|
959
|
+
queuedAttributeNames.add(attribute.name)
|
|
960
|
+
attributePlugins.set(attribute.name, attribute)
|
|
961
|
+
}
|
|
962
|
+
queuedAttributes.length = 0
|
|
963
|
+
apply()
|
|
964
|
+
queuedAttributeNames.clear()
|
|
965
|
+
})
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
export const action = <T>(plugin: ActionPlugin<T>): void => {
|
|
970
|
+
actionPlugins.set(plugin.name, plugin)
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
document.addEventListener(
|
|
974
|
+
DATASTAR_FETCH_EVENT,
|
|
975
|
+
((
|
|
976
|
+
evt: CustomEvent<DatastarFetchEvent>,
|
|
977
|
+
) => {
|
|
978
|
+
const plugin = watcherPlugins.get(evt.detail.type)
|
|
979
|
+
if (plugin) {
|
|
980
|
+
plugin.apply(
|
|
981
|
+
{
|
|
982
|
+
error: error.bind(0, {
|
|
983
|
+
plugin: { type: "watcher", name: plugin.name },
|
|
984
|
+
element: {
|
|
985
|
+
id: (evt.target as Element).id,
|
|
986
|
+
tag: (evt.target as Element).tagName,
|
|
987
|
+
},
|
|
988
|
+
}),
|
|
989
|
+
},
|
|
990
|
+
evt.detail.argsRaw,
|
|
991
|
+
)
|
|
992
|
+
}
|
|
993
|
+
}) as EventListener,
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
export const watcher = (plugin: WatcherPlugin): void => {
|
|
997
|
+
watcherPlugins.set(plugin.name, plugin)
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
const cleanupEls = (els: Iterable<HTMLOrSVG>): void => {
|
|
1001
|
+
for (const el of els) {
|
|
1002
|
+
const elCleanups = removals.get(el)
|
|
1003
|
+
if (elCleanups && removals.delete(el)) {
|
|
1004
|
+
for (const attrCleanups of elCleanups.values()) {
|
|
1005
|
+
for (const cleanup of attrCleanups.values()) {
|
|
1006
|
+
cleanup()
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
const aliasedIgnore = aliasify("ignore")
|
|
1014
|
+
const aliasedIgnoreAttr = `[${aliasedIgnore}]`
|
|
1015
|
+
const shouldIgnore = (el: HTMLOrSVG) =>
|
|
1016
|
+
el.hasAttribute(`${aliasedIgnore}__self`) || !!el.closest(aliasedIgnoreAttr)
|
|
1017
|
+
|
|
1018
|
+
const applyEls = (els: Iterable<HTMLOrSVG>, onlyNew?: boolean): void => {
|
|
1019
|
+
for (const el of els) {
|
|
1020
|
+
if (!shouldIgnore(el)) {
|
|
1021
|
+
for (const key in el.dataset) {
|
|
1022
|
+
applyAttributePlugin(
|
|
1023
|
+
el,
|
|
1024
|
+
key.replace(/[A-Z]/g, "-$&").toLowerCase(),
|
|
1025
|
+
el.dataset[key]!,
|
|
1026
|
+
onlyNew,
|
|
1027
|
+
)
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const observe = (mutations: MutationRecord[]) => {
|
|
1034
|
+
for (
|
|
1035
|
+
const {
|
|
1036
|
+
target,
|
|
1037
|
+
type,
|
|
1038
|
+
attributeName,
|
|
1039
|
+
addedNodes,
|
|
1040
|
+
removedNodes,
|
|
1041
|
+
} of mutations
|
|
1042
|
+
) {
|
|
1043
|
+
if (type === "childList") {
|
|
1044
|
+
for (const node of removedNodes) {
|
|
1045
|
+
if (isHTMLOrSVG(node)) {
|
|
1046
|
+
cleanupEls([node])
|
|
1047
|
+
cleanupEls(node.querySelectorAll<HTMLOrSVG>("*"))
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
for (const node of addedNodes) {
|
|
1052
|
+
if (isHTMLOrSVG(node)) {
|
|
1053
|
+
applyEls([node])
|
|
1054
|
+
applyEls(node.querySelectorAll<HTMLOrSVG>("*"))
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
} else if (
|
|
1058
|
+
type === "attributes"
|
|
1059
|
+
&& attributeName!.startsWith("data-")
|
|
1060
|
+
&& isHTMLOrSVG(target)
|
|
1061
|
+
&& !shouldIgnore(target)
|
|
1062
|
+
) {
|
|
1063
|
+
const key = attributeName!.slice(5)
|
|
1064
|
+
const value = target.getAttribute(attributeName!)
|
|
1065
|
+
if (value === null) {
|
|
1066
|
+
const elCleanups = removals.get(target)
|
|
1067
|
+
if (elCleanups) {
|
|
1068
|
+
const attrCleanups = elCleanups.get(key)
|
|
1069
|
+
if (attrCleanups) {
|
|
1070
|
+
for (const cleanup of attrCleanups.values()) {
|
|
1071
|
+
cleanup()
|
|
1072
|
+
}
|
|
1073
|
+
elCleanups.delete(key)
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
} else {
|
|
1077
|
+
applyAttributePlugin(target, key, value)
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
const mutationObserver = new MutationObserver(observe)
|
|
1084
|
+
|
|
1085
|
+
export const parseAttributeKey = (
|
|
1086
|
+
rawKey: string,
|
|
1087
|
+
): {
|
|
1088
|
+
pluginName: string
|
|
1089
|
+
key: string | undefined
|
|
1090
|
+
mods: Modifiers
|
|
1091
|
+
} => {
|
|
1092
|
+
const [namePart, ...rawModifiers] = rawKey.split("__")
|
|
1093
|
+
const [pluginName, key] = namePart.split(/:(.+)/)
|
|
1094
|
+
const mods: Modifiers = new Map()
|
|
1095
|
+
|
|
1096
|
+
for (const rawMod of rawModifiers) {
|
|
1097
|
+
const [label, ...mod] = rawMod.split(".")
|
|
1098
|
+
mods.set(label, new Set(mod))
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
return { pluginName, key, mods }
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
export const isDocumentObserverActive = () =>
|
|
1105
|
+
observedRoots.has(document.documentElement)
|
|
1106
|
+
|
|
1107
|
+
export const apply = (
|
|
1108
|
+
root: HTMLOrSVG | ShadowRoot = document.documentElement,
|
|
1109
|
+
observeRoot = true,
|
|
1110
|
+
): void => {
|
|
1111
|
+
if (isHTMLOrSVG(root)) {
|
|
1112
|
+
applyEls([root], true)
|
|
1113
|
+
}
|
|
1114
|
+
applyEls(root.querySelectorAll<HTMLOrSVG>("*"), true)
|
|
1115
|
+
|
|
1116
|
+
if (observeRoot) {
|
|
1117
|
+
mutationObserver.observe(root, {
|
|
1118
|
+
subtree: true,
|
|
1119
|
+
childList: true,
|
|
1120
|
+
attributes: true,
|
|
1121
|
+
})
|
|
1122
|
+
observedRoots.add(root)
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
const applyAttributePlugin = (
|
|
1127
|
+
el: HTMLOrSVG,
|
|
1128
|
+
attrKey: string,
|
|
1129
|
+
value: string,
|
|
1130
|
+
onlyNew?: boolean,
|
|
1131
|
+
): void => {
|
|
1132
|
+
const rawKey = attrKey
|
|
1133
|
+
const { pluginName, key, mods } = parseAttributeKey(rawKey)
|
|
1134
|
+
const plugin = attributePlugins.get(pluginName)
|
|
1135
|
+
if ((!onlyNew || queuedAttributeNames.has(pluginName)) && plugin) {
|
|
1136
|
+
const ctx = {
|
|
1137
|
+
el,
|
|
1138
|
+
rawKey,
|
|
1139
|
+
mods,
|
|
1140
|
+
error: error.bind(0, {
|
|
1141
|
+
plugin: { type: "attribute", name: plugin.name },
|
|
1142
|
+
element: { id: el.id, tag: el.tagName },
|
|
1143
|
+
expression: { rawKey, key, value },
|
|
1144
|
+
}),
|
|
1145
|
+
key,
|
|
1146
|
+
value,
|
|
1147
|
+
loadedPluginNames: {
|
|
1148
|
+
actions: new Set(actionPlugins.keys()),
|
|
1149
|
+
attributes: new Set(attributePlugins.keys()),
|
|
1150
|
+
},
|
|
1151
|
+
rx: undefined,
|
|
1152
|
+
} as AttributeContext
|
|
1153
|
+
|
|
1154
|
+
const keyReq = (plugin.requirement
|
|
1155
|
+
&& (typeof plugin.requirement === "string"
|
|
1156
|
+
? plugin.requirement
|
|
1157
|
+
: plugin.requirement.key))
|
|
1158
|
+
|| "allowed"
|
|
1159
|
+
const valueReq = (plugin.requirement
|
|
1160
|
+
&& (typeof plugin.requirement === "string"
|
|
1161
|
+
? plugin.requirement
|
|
1162
|
+
: plugin.requirement.value))
|
|
1163
|
+
|| "allowed"
|
|
1164
|
+
|
|
1165
|
+
const keyProvided = key !== undefined && key !== null && key !== ""
|
|
1166
|
+
const valueProvided = value !== undefined && value !== null && value !== ""
|
|
1167
|
+
|
|
1168
|
+
if (keyProvided) {
|
|
1169
|
+
if (keyReq === "denied") {
|
|
1170
|
+
throw ctx.error("KeyNotAllowed")
|
|
1171
|
+
}
|
|
1172
|
+
} else if (keyReq === "must") {
|
|
1173
|
+
throw ctx.error("KeyRequired")
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
if (valueProvided) {
|
|
1177
|
+
if (valueReq === "denied") {
|
|
1178
|
+
throw ctx.error("ValueNotAllowed")
|
|
1179
|
+
}
|
|
1180
|
+
} else if (valueReq === "must") {
|
|
1181
|
+
throw ctx.error("ValueRequired")
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
if (keyReq === "exclusive" || valueReq === "exclusive") {
|
|
1185
|
+
if (keyProvided && valueProvided) {
|
|
1186
|
+
throw ctx.error("KeyAndValueProvided")
|
|
1187
|
+
}
|
|
1188
|
+
if (!keyProvided && !valueProvided) {
|
|
1189
|
+
throw ctx.error("KeyOrValueRequired")
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const cleanups = new Map<string, () => void>()
|
|
1194
|
+
if (valueProvided) {
|
|
1195
|
+
let cachedRx: GenRxFn
|
|
1196
|
+
ctx.rx = (...args: any[]) => {
|
|
1197
|
+
if (!cachedRx) {
|
|
1198
|
+
cachedRx = genRx(value, {
|
|
1199
|
+
returnsValue: plugin.returnsValue,
|
|
1200
|
+
argNames: plugin.argNames,
|
|
1201
|
+
cleanups,
|
|
1202
|
+
})
|
|
1203
|
+
}
|
|
1204
|
+
return cachedRx(el, ...args)
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
const cleanup = plugin.apply(ctx)
|
|
1209
|
+
if (cleanup) {
|
|
1210
|
+
cleanups.set("attribute", cleanup)
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
let elCleanups = removals.get(el)
|
|
1214
|
+
if (elCleanups) {
|
|
1215
|
+
const attrCleanups = elCleanups.get(rawKey)
|
|
1216
|
+
if (attrCleanups) {
|
|
1217
|
+
for (const oldCleanup of attrCleanups.values()) {
|
|
1218
|
+
oldCleanup()
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
} else {
|
|
1222
|
+
elCleanups = new Map()
|
|
1223
|
+
removals.set(el, elCleanups)
|
|
1224
|
+
}
|
|
1225
|
+
elCleanups.set(rawKey, cleanups)
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
type GenRxOptions = {
|
|
1230
|
+
returnsValue?: boolean
|
|
1231
|
+
argNames?: string[]
|
|
1232
|
+
cleanups?: Map<string, () => void>
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
type GenRxFn = <T>(el: HTMLOrSVG, ...args: any[]) => T
|
|
1236
|
+
|
|
1237
|
+
const genRx = (
|
|
1238
|
+
value: string,
|
|
1239
|
+
{
|
|
1240
|
+
returnsValue = false,
|
|
1241
|
+
argNames = [],
|
|
1242
|
+
cleanups = new Map(),
|
|
1243
|
+
}: GenRxOptions = {},
|
|
1244
|
+
): GenRxFn => {
|
|
1245
|
+
let expr = ""
|
|
1246
|
+
if (returnsValue) {
|
|
1247
|
+
const statementRe =
|
|
1248
|
+
/(\/(\\\/|[^/])*\/|"(\\"|[^"])*"|'(\\'|[^'])*'|`(\\`|[^`])*`|\(\s*((function)\s*\(\s*\)|(\(\s*\))\s*=>)\s*(?:\{[\s\S]*?\}|[^;){]*)\s*\)\s*\(\s*\)|[^;])+/gm
|
|
1249
|
+
const statements = value.trim().match(statementRe)
|
|
1250
|
+
if (statements) {
|
|
1251
|
+
const lastIdx = statements.length - 1
|
|
1252
|
+
const last = statements[lastIdx].trim()
|
|
1253
|
+
if (!last.startsWith("return")) {
|
|
1254
|
+
statements[lastIdx] = `return (${last});`
|
|
1255
|
+
}
|
|
1256
|
+
expr = statements.join(";\n")
|
|
1257
|
+
}
|
|
1258
|
+
} else {
|
|
1259
|
+
expr = value.trim()
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
const escaped = new Map<string, string>()
|
|
1263
|
+
const escapeRe = RegExp(`(?:${DSP})(.*?)(?:${DSS})`, "gm")
|
|
1264
|
+
let counter = 0
|
|
1265
|
+
for (const match of expr.matchAll(escapeRe)) {
|
|
1266
|
+
const k = match[1]
|
|
1267
|
+
const v = `__escaped${counter++}`
|
|
1268
|
+
escaped.set(v, k)
|
|
1269
|
+
expr = expr.replace(DSP + k + DSS, v)
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
expr = expr
|
|
1273
|
+
.replace(/\$\['([a-zA-Z_$\d][\w$]*)'\]/g, "$$$1")
|
|
1274
|
+
.replace(/\$([a-zA-Z_\d]\w*(?:[.-]\w+)*)/g, (_, signalName) =>
|
|
1275
|
+
signalName
|
|
1276
|
+
.split(".")
|
|
1277
|
+
.reduce((acc: string, part: string) => `${acc}['${part}']`, "$"))
|
|
1278
|
+
|
|
1279
|
+
expr = expr.replaceAll(/@([A-Za-z_$][\w$]*)\(/g, "__action(\"$1\",evt,")
|
|
1280
|
+
|
|
1281
|
+
for (const [k, v] of escaped) {
|
|
1282
|
+
expr = expr.replace(k, v)
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
try {
|
|
1286
|
+
const fn = Function("el", "$", "__action", "evt", ...argNames, expr)
|
|
1287
|
+
return (el: HTMLOrSVG, ...args: any[]) => {
|
|
1288
|
+
const action = (name: string, evt: Event | undefined, ...args: any[]) => {
|
|
1289
|
+
const err = error.bind(0, {
|
|
1290
|
+
plugin: { type: "action", name },
|
|
1291
|
+
element: { id: el.id, tag: el.tagName },
|
|
1292
|
+
expression: {
|
|
1293
|
+
fnContent: expr,
|
|
1294
|
+
value,
|
|
1295
|
+
},
|
|
1296
|
+
})
|
|
1297
|
+
const fn = actions[name]
|
|
1298
|
+
if (fn) {
|
|
1299
|
+
return fn(
|
|
1300
|
+
{
|
|
1301
|
+
el,
|
|
1302
|
+
evt,
|
|
1303
|
+
error: err,
|
|
1304
|
+
cleanups,
|
|
1305
|
+
},
|
|
1306
|
+
...args,
|
|
1307
|
+
)
|
|
1308
|
+
}
|
|
1309
|
+
throw err("UndefinedAction")
|
|
1310
|
+
}
|
|
1311
|
+
try {
|
|
1312
|
+
return fn(el, root, action, undefined, ...args)
|
|
1313
|
+
} catch (e: any) {
|
|
1314
|
+
console.error(e)
|
|
1315
|
+
throw error(
|
|
1316
|
+
{
|
|
1317
|
+
element: { id: el.id, tag: el.tagName },
|
|
1318
|
+
expression: {
|
|
1319
|
+
fnContent: expr,
|
|
1320
|
+
value,
|
|
1321
|
+
},
|
|
1322
|
+
error: e.message,
|
|
1323
|
+
},
|
|
1324
|
+
"ExecuteExpression",
|
|
1325
|
+
)
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
} catch (e: any) {
|
|
1329
|
+
console.error(e)
|
|
1330
|
+
throw error(
|
|
1331
|
+
{
|
|
1332
|
+
expression: {
|
|
1333
|
+
fnContent: expr,
|
|
1334
|
+
value,
|
|
1335
|
+
},
|
|
1336
|
+
error: e.message,
|
|
1337
|
+
},
|
|
1338
|
+
"GenerateExpression",
|
|
1339
|
+
)
|
|
1340
|
+
}
|
|
1341
|
+
}
|