@effect-app/vue 4.0.0-beta.160 → 4.0.0-beta.162
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/CHANGELOG.md +14 -0
- package/dist/commander.d.ts +1 -1
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +18 -14
- package/dist/lib.d.ts +2 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +32 -1
- package/package.json +2 -2
- package/src/commander.ts +9 -7
- package/src/lib.ts +43 -0
- package/test/dist/lib.test.d.ts.map +1 -0
- package/test/lib.test.ts +240 -0
package/src/commander.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { asResult, type MissingDependencies, reportRuntimeError } from "@effect-app/vue"
|
|
2
|
+
import { asResult, deepToRaw, type MissingDependencies, reportRuntimeError } from "@effect-app/vue"
|
|
3
3
|
import { reportMessage } from "@effect-app/vue/errorReporter"
|
|
4
4
|
import { Cause, Context, Effect, type Exit, type Fiber, flow, Layer, Match, MutableHashMap, Option, Predicate, S } from "effect-app"
|
|
5
5
|
import { SupportedErrors } from "effect-app/client"
|
|
@@ -2156,7 +2156,7 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
2156
2156
|
const runFork = Effect.runForkWith(rt)
|
|
2157
2157
|
|
|
2158
2158
|
const handle = Object.assign((arg: Arg) => {
|
|
2159
|
-
arg = toRaw(arg) //
|
|
2159
|
+
arg = toRaw(arg) // remove outside vue proxy bs
|
|
2160
2160
|
// we capture the call site stack here
|
|
2161
2161
|
const limit = Error.stackTraceLimit
|
|
2162
2162
|
Error.stackTraceLimit = 2
|
|
@@ -2187,15 +2187,17 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
2187
2187
|
}
|
|
2188
2188
|
}
|
|
2189
2189
|
|
|
2190
|
-
const command = currentState.pipe(Effect.flatMap((state) =>
|
|
2191
|
-
|
|
2190
|
+
const command = currentState.pipe(Effect.flatMap((state) => {
|
|
2191
|
+
const rawArg = deepToRaw(arg)
|
|
2192
|
+
const rawState = deepToRaw(state)
|
|
2193
|
+
return Effect.withSpan(
|
|
2192
2194
|
exec(arg, { ...context.value, state } as any),
|
|
2193
2195
|
id,
|
|
2194
2196
|
{
|
|
2195
2197
|
captureStackTrace,
|
|
2196
2198
|
attributes: {
|
|
2197
|
-
input:
|
|
2198
|
-
state,
|
|
2199
|
+
input: rawArg,
|
|
2200
|
+
state: rawState,
|
|
2199
2201
|
action: initialContext.action,
|
|
2200
2202
|
label: initialContext.label,
|
|
2201
2203
|
id: initialContext.id,
|
|
@@ -2203,7 +2205,7 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
2203
2205
|
}
|
|
2204
2206
|
}
|
|
2205
2207
|
)
|
|
2206
|
-
))
|
|
2208
|
+
}))
|
|
2207
2209
|
|
|
2208
2210
|
return runFork(command)
|
|
2209
2211
|
}, { action, label })
|
package/src/lib.ts
CHANGED
|
@@ -85,3 +85,46 @@ export const mapHandler: {
|
|
|
85
85
|
? (i: any) => map(self.handler as (i: any) => Effect.Effect<any, any, any>)(i)
|
|
86
86
|
: map(self.handler)
|
|
87
87
|
})
|
|
88
|
+
|
|
89
|
+
import { isProxy, isReactive, isRef, toRaw } from "vue"
|
|
90
|
+
|
|
91
|
+
export function deepToRaw<T>(sourceObj: T): T {
|
|
92
|
+
const objectIterator = (input: any): any => {
|
|
93
|
+
if (isRef(input)) {
|
|
94
|
+
return objectIterator(input.value)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const rawInput = isReactive(input) || isProxy(input)
|
|
98
|
+
? toRaw(input)
|
|
99
|
+
: input
|
|
100
|
+
|
|
101
|
+
if (Array.isArray(rawInput)) {
|
|
102
|
+
return rawInput.map((item) => objectIterator(item))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (rawInput instanceof Map) {
|
|
106
|
+
return new Map(
|
|
107
|
+
Array.from(rawInput.entries(), ([key, value]) => [objectIterator(key), objectIterator(value)])
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (rawInput instanceof Set) {
|
|
112
|
+
return new Set(Array.from(rawInput.values(), (value) => objectIterator(value)))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (rawInput instanceof Date) {
|
|
116
|
+
return new Date(rawInput)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (rawInput && typeof rawInput === "object") {
|
|
120
|
+
return Object.keys(rawInput).reduce((acc, key) => {
|
|
121
|
+
acc[key] = objectIterator(rawInput[key])
|
|
122
|
+
return acc
|
|
123
|
+
}, {} as Record<string, unknown>)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return rawInput
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return objectIterator(sourceObj)
|
|
130
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.test.d.ts","sourceRoot":"","sources":["../lib.test.ts"],"names":[],"mappings":""}
|
package/test/lib.test.ts
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import { computed, isProxy, isReactive, isRef, reactive, ref } from "vue"
|
|
3
|
+
import { deepToRaw } from "../src/lib.js"
|
|
4
|
+
|
|
5
|
+
type DeepMapKey = { id: string } | "list"
|
|
6
|
+
type DeepMapValue = { nestedSet: Set<{ ok: boolean } | Date> } | Array<{ count: number }>
|
|
7
|
+
type DeepSetValue = Map<string, { value: number }> | Array<{ value: number }>
|
|
8
|
+
|
|
9
|
+
const expectPlainDeep = (value: unknown): void => {
|
|
10
|
+
expect(isRef(value)).toBe(false)
|
|
11
|
+
expect(isReactive(value)).toBe(false)
|
|
12
|
+
expect(isProxy(value)).toBe(false)
|
|
13
|
+
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
value.forEach(expectPlainDeep)
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (value instanceof Map) {
|
|
20
|
+
value.forEach((entryValue, entryKey) => {
|
|
21
|
+
expectPlainDeep(entryKey)
|
|
22
|
+
expectPlainDeep(entryValue)
|
|
23
|
+
})
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (value instanceof Set) {
|
|
28
|
+
value.forEach((entry) => {
|
|
29
|
+
expectPlainDeep(entry)
|
|
30
|
+
})
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (value instanceof Date) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (value && typeof value === "object") {
|
|
39
|
+
Object.values(value).forEach(expectPlainDeep)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("deepToRaw", () => {
|
|
44
|
+
it("supports non-object root inputs", () => {
|
|
45
|
+
expect(deepToRaw(1)).toBe(1)
|
|
46
|
+
expect(deepToRaw("x")).toBe("x")
|
|
47
|
+
expect(deepToRaw(null)).toBe(null)
|
|
48
|
+
expect(deepToRaw(undefined)).toBe(undefined)
|
|
49
|
+
expect(deepToRaw(ref(123))).toBe(123)
|
|
50
|
+
|
|
51
|
+
const rootArray = deepToRaw(reactive([reactive({ n: 1 }), ref(2)]))
|
|
52
|
+
expect(rootArray).toEqual([{ n: 1 }, 2])
|
|
53
|
+
expect(Array.isArray(rootArray)).toBe(true)
|
|
54
|
+
|
|
55
|
+
const rootMap = deepToRaw(
|
|
56
|
+
reactive(new Map<string, unknown>([["k", reactive({ n: 1 })], ["r", ref(2)]]))
|
|
57
|
+
)
|
|
58
|
+
expect(rootMap).toBeInstanceOf(Map)
|
|
59
|
+
expect(rootMap.get("k")).toEqual({ n: 1 })
|
|
60
|
+
expect(rootMap.get("r")).toBe(2)
|
|
61
|
+
|
|
62
|
+
const rootSet = deepToRaw(reactive(new Set([reactive({ n: 1 }), ref(2)])))
|
|
63
|
+
expect(rootSet).toBeInstanceOf(Set)
|
|
64
|
+
expect(Array.from(rootSet)).toEqual([{ n: 1 }, 2])
|
|
65
|
+
|
|
66
|
+
const date = new Date("2024-02-03T00:00:00.000Z")
|
|
67
|
+
const rootDate = deepToRaw(date)
|
|
68
|
+
expect(rootDate).toBeInstanceOf(Date)
|
|
69
|
+
expect(rootDate).not.toBe(date)
|
|
70
|
+
expect(rootDate.toISOString()).toBe(date.toISOString())
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("unwraps nested objects and arrays without leaving vue proxies behind", () => {
|
|
74
|
+
const source = reactive({
|
|
75
|
+
list: [
|
|
76
|
+
reactive({
|
|
77
|
+
nested: reactive({
|
|
78
|
+
count: 1,
|
|
79
|
+
items: [reactive({ label: "a" }), reactive({ label: "b" })]
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
],
|
|
83
|
+
plain: reactive({ ok: true })
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const result = deepToRaw(source)
|
|
87
|
+
|
|
88
|
+
expect(Array.isArray(result.list)).toBe(true)
|
|
89
|
+
expect(Array.isArray(result.list[0]?.nested.items)).toBe(true)
|
|
90
|
+
expect(result).toEqual({
|
|
91
|
+
list: [{ nested: { count: 1, items: [{ label: "a" }, { label: "b" }] } }],
|
|
92
|
+
plain: { ok: true }
|
|
93
|
+
})
|
|
94
|
+
expectPlainDeep(result)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it("preserves maps and sets while deeply unwrapping nested entries", () => {
|
|
98
|
+
const key = reactive({ id: "key" })
|
|
99
|
+
const nestedDate = new Date("2024-01-02T03:04:05.000Z")
|
|
100
|
+
const map = reactive(
|
|
101
|
+
new Map<DeepMapKey, DeepMapValue>([
|
|
102
|
+
[key, reactive({ nestedSet: reactive(new Set([{ ok: true }, nestedDate])) })],
|
|
103
|
+
["list", reactive([{ count: 2 }])]
|
|
104
|
+
])
|
|
105
|
+
)
|
|
106
|
+
const set = reactive(
|
|
107
|
+
new Set<DeepSetValue>([
|
|
108
|
+
reactive(new Map([["deep", reactive({ value: 3 })]])),
|
|
109
|
+
reactive([{ value: 4 }])
|
|
110
|
+
])
|
|
111
|
+
)
|
|
112
|
+
const source = reactive({
|
|
113
|
+
map,
|
|
114
|
+
set
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
const result = deepToRaw(source)
|
|
118
|
+
|
|
119
|
+
expect(result.map).toBeInstanceOf(Map)
|
|
120
|
+
expect(result.set).toBeInstanceOf(Set)
|
|
121
|
+
|
|
122
|
+
const entries = Array.from(result.map.entries())
|
|
123
|
+
expect(entries[0]?.[0]).toEqual({ id: "key" })
|
|
124
|
+
expect(entries[0]?.[0]).not.toBe(key)
|
|
125
|
+
expect(entries[0]?.[1]).toEqual({ nestedSet: new Set([{ ok: true }, nestedDate]) })
|
|
126
|
+
expect(entries[1]?.[1]).toEqual([{ count: 2 }])
|
|
127
|
+
|
|
128
|
+
const setValues = Array.from(result.set.values())
|
|
129
|
+
expect(setValues[0]).toBeInstanceOf(Map)
|
|
130
|
+
expect(setValues[1]).toEqual([{ value: 4 }])
|
|
131
|
+
expect((setValues[0] as Map<string, { value: number }>).get("deep")).toEqual({ value: 3 })
|
|
132
|
+
|
|
133
|
+
expectPlainDeep(result)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it("keeps nested dates as dates, including dates reached through refs", () => {
|
|
137
|
+
const date = new Date("2025-06-07T08:09:10.000Z")
|
|
138
|
+
const source = reactive({
|
|
139
|
+
createdAt: date,
|
|
140
|
+
nested: reactive({
|
|
141
|
+
updatedAt: ref(date),
|
|
142
|
+
list: [ref(date)],
|
|
143
|
+
map: reactive(new Map([["at", ref(date)]])),
|
|
144
|
+
set: reactive(new Set([ref(date)]))
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const result = deepToRaw(source)
|
|
149
|
+
|
|
150
|
+
expect(result.createdAt).toBeInstanceOf(Date)
|
|
151
|
+
expect(result.nested.updatedAt).toBeInstanceOf(Date)
|
|
152
|
+
expect(result.nested.list[0]).toBeInstanceOf(Date)
|
|
153
|
+
expect(result.nested.map).toBeInstanceOf(Map)
|
|
154
|
+
expect(result.nested.set).toBeInstanceOf(Set)
|
|
155
|
+
|
|
156
|
+
const updatedAt = result.nested.updatedAt
|
|
157
|
+
const firstListDate = result.nested.list[0]
|
|
158
|
+
const mappedDate = result.nested.map.get("at")
|
|
159
|
+
const firstSetDate = Array.from(result.nested.set)[0]
|
|
160
|
+
|
|
161
|
+
if (!(updatedAt instanceof Date)) {
|
|
162
|
+
throw new Error("expected updatedAt to be a Date")
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!(firstListDate instanceof Date)) {
|
|
166
|
+
throw new Error("expected first list item to be a Date")
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!(mappedDate instanceof Date)) {
|
|
170
|
+
throw new Error("expected mapped date to be a Date")
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!(firstSetDate instanceof Date)) {
|
|
174
|
+
throw new Error("expected first set item to be a Date")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
expect(result.createdAt.toISOString()).toBe(date.toISOString())
|
|
178
|
+
expect(updatedAt.toISOString()).toBe(date.toISOString())
|
|
179
|
+
expect(firstListDate.toISOString()).toBe(date.toISOString())
|
|
180
|
+
expect(mappedDate.toISOString()).toBe(date.toISOString())
|
|
181
|
+
expect(firstSetDate.toISOString()).toBe(date.toISOString())
|
|
182
|
+
|
|
183
|
+
expectPlainDeep(result)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it("unwraps computed values nested in refs/plain objects and deepToRawes the computed result", () => {
|
|
187
|
+
const source = {
|
|
188
|
+
innerRef: ref({
|
|
189
|
+
computedValue: computed(() =>
|
|
190
|
+
reactive({
|
|
191
|
+
list: [reactive({ n: 1 }), reactive({ n: 2 })],
|
|
192
|
+
map: reactive(new Map([["k", reactive({ nested: true })]])),
|
|
193
|
+
set: reactive(new Set([reactive({ fromSet: true })]))
|
|
194
|
+
})
|
|
195
|
+
)
|
|
196
|
+
}),
|
|
197
|
+
plainComputed: computed(() => reactive({ date: ref(new Date("2025-01-01T00:00:00.000Z")) }))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const result = deepToRaw(source)
|
|
201
|
+
|
|
202
|
+
expect(result).toEqual({
|
|
203
|
+
innerRef: {
|
|
204
|
+
computedValue: {
|
|
205
|
+
list: [{ n: 1 }, { n: 2 }],
|
|
206
|
+
map: new Map([["k", { nested: true }]]),
|
|
207
|
+
set: new Set([{ fromSet: true }])
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
plainComputed: {
|
|
211
|
+
date: new Date("2025-01-01T00:00:00.000Z")
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
const innerRefValue = Reflect.get(result, "innerRef")
|
|
216
|
+
if (!innerRefValue || typeof innerRefValue !== "object") {
|
|
217
|
+
throw new Error("expected innerRef to be an object")
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const computedValue = Reflect.get(innerRefValue, "computedValue")
|
|
221
|
+
if (!computedValue || typeof computedValue !== "object") {
|
|
222
|
+
throw new Error("expected computedValue to be an object")
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const computedMap = Reflect.get(computedValue, "map")
|
|
226
|
+
const computedSet = Reflect.get(computedValue, "set")
|
|
227
|
+
|
|
228
|
+
const plainComputedValue = Reflect.get(result, "plainComputed")
|
|
229
|
+
if (!plainComputedValue || typeof plainComputedValue !== "object") {
|
|
230
|
+
throw new Error("expected plainComputed to be an object")
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const computedDate = Reflect.get(plainComputedValue, "date")
|
|
234
|
+
|
|
235
|
+
expect(computedMap).toBeInstanceOf(Map)
|
|
236
|
+
expect(computedSet).toBeInstanceOf(Set)
|
|
237
|
+
expect(computedDate).toBeInstanceOf(Date)
|
|
238
|
+
expectPlainDeep(result)
|
|
239
|
+
})
|
|
240
|
+
})
|