@effect-app/vue 4.0.0-beta.33 → 4.0.0-beta.36

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @effect-app/vue
2
2
 
3
+ ## 4.0.0-beta.36
4
+
5
+ ### Patch Changes
6
+
7
+ - effect-app@4.0.0-beta.36
8
+
9
+ ## 4.0.0-beta.35
10
+
11
+ ### Patch Changes
12
+
13
+ - effect-app@4.0.0-beta.35
14
+
15
+ ## 4.0.0-beta.34
16
+
17
+ ### Patch Changes
18
+
19
+ - 8c645d5: update to latest effect
20
+ - Updated dependencies [8c645d5]
21
+ - effect-app@4.0.0-beta.34
22
+
3
23
  ## 4.0.0-beta.33
4
24
 
5
25
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/vue",
3
- "version": "4.0.0-beta.33",
3
+ "version": "4.0.0-beta.36",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/effect-ts-app/libs/tree/main/packages/vue",
@@ -11,23 +11,23 @@
11
11
  "@vueuse/core": "^14.2.1",
12
12
  "change-case": "^5.4.4",
13
13
  "query-string": "^9.3.1",
14
- "effect-app": "4.0.0-beta.33"
14
+ "effect-app": "4.0.0-beta.36"
15
15
  },
16
16
  "peerDependencies": {
17
- "@effect/atom-vue": "^4.0.0-beta.37",
18
- "@effect/platform-browser": "^4.0.0-beta.37",
17
+ "@effect/atom-vue": "^4.0.0-beta.40",
18
+ "@effect/platform-browser": "^4.0.0-beta.40",
19
19
  "@sentry/browser": "^10.42.0",
20
- "effect": "^4.0.0-beta.37",
20
+ "effect": "^4.0.0-beta.40",
21
21
  "vue": "^3.5.29"
22
22
  },
23
23
  "devDependencies": {
24
- "@effect/vitest": "^4.0.0-beta.37",
24
+ "@effect/vitest": "^4.0.0-beta.40",
25
25
  "@formatjs/icu-messageformat-parser": "^3.5.1",
26
26
  "@types/node": "25.3.3",
27
27
  "@vitejs/plugin-vue": "^6.0.4",
28
28
  "intl-messageformat": "^11.1.2",
29
29
  "json5": "^2.2.3",
30
- "typescript": "~5.9.3",
30
+ "typescript": "~6.0.2",
31
31
  "vite": "^7.3.1",
32
32
  "vitest": "^4.0.18",
33
33
  "@effect-app/eslint-shared-config": "0.5.7-beta.2"
package/tsconfig.json CHANGED
@@ -32,7 +32,6 @@
32
32
  "outDir": "build/dist",
33
33
  "resolveJsonModule": true,
34
34
  "moduleResolution": "Node16",
35
- "downlevelIteration": true,
36
35
  "noErrorTruncation": true,
37
36
  "forceConsistentCasingInFileNames": true,
38
37
  "types": [
@@ -1,158 +0,0 @@
1
- import { Effect, S } from "effect-app"
2
- import { buildFieldInfoFromFieldsRoot, translate } from "../src/form.js"
3
-
4
- // test schema with integer field
5
- class TestSchema extends S.Class<TestSchema>("TestSchema")({
6
- integerField: S.Int,
7
- numberField: S.Finite,
8
- stringField: S.String
9
- }) {}
10
-
11
- // translation dictionaries
12
- const translations: Record<string, Record<string, string>> = {
13
- en: {
14
- "validation.integer.expected": "Expected an integer, actual {actualValue}",
15
- "validation.number.expected": "Expected a number, actual {actualValue}"
16
- },
17
- de: {
18
- "validation.integer.expected": "Es wird eine ganze Zahl erwartet, tatsächlich: {actualValue}",
19
- "validation.number.expected": "Es wird eine Zahl erwartet, tatsächlich: {actualValue}"
20
- }
21
- }
22
-
23
- // mock translate function to capture translation calls and return actual translated string
24
- const translationCalls: Array<{ id: string; defaultMessage: string; params?: any }> = []
25
- let currentLocale = "en"
26
-
27
- const mockTranslate = (msg: { id: string; defaultMessage: string }, params?: any) => {
28
- translationCalls.push({ id: msg.id, defaultMessage: msg.defaultMessage, params })
29
-
30
- // get the translation template
31
- const template = translations[currentLocale]?.[msg.id] || msg.defaultMessage
32
-
33
- // replace parameters in the template
34
- if (params) {
35
- return Object.entries(params).reduce((result, [key, value]) => {
36
- return result.replace(`{${key}}`, String(value))
37
- }, template)
38
- }
39
-
40
- return template
41
- }
42
-
43
- beforeEach(() => {
44
- translationCalls.length = 0
45
- currentLocale = "en"
46
- translate.value = mockTranslate as any
47
- })
48
-
49
- it("validates integer field with decimal value (English)", () =>
50
- Effect
51
- .gen(function*() {
52
- currentLocale = "en"
53
- const fieldInfo = buildFieldInfoFromFieldsRoot(TestSchema)
54
- const integerFieldInfo = fieldInfo.fields.integerField
55
-
56
- expect(integerFieldInfo._tag).toBe("FieldInfo")
57
- expect(integerFieldInfo.type).toBe("int")
58
-
59
- // test validation rules with a decimal value
60
- const result = integerFieldInfo.rules[1] ? integerFieldInfo.rules[1]("59.5") : undefined
61
-
62
- console.log("Validation result (EN):", result)
63
- console.log("Translation calls:", translationCalls)
64
-
65
- // the validation should fail
66
- expect(result).not.toBe(true)
67
- expect(typeof result).toBe("string")
68
-
69
- // check if the correct translation key was called
70
- const integerErrorCall = translationCalls.find((call) => call.id === "validation.integer.expected")
71
- expect(integerErrorCall).toBeDefined()
72
- expect(integerErrorCall?.params).toHaveProperty("actualValue")
73
- expect(integerErrorCall?.params.actualValue).toBe("59.5")
74
-
75
- // MOST IMPORTANT: verify the actual translated string returned
76
- expect(result).toBe("Expected an integer, actual 59.5")
77
- })
78
- .pipe(Effect.runPromise))
79
-
80
- it("validates integer field with decimal value (German)", () =>
81
- Effect
82
- .gen(function*() {
83
- currentLocale = "de"
84
- const fieldInfo = buildFieldInfoFromFieldsRoot(TestSchema)
85
- const integerFieldInfo = fieldInfo.fields.integerField
86
-
87
- expect(integerFieldInfo._tag).toBe("FieldInfo")
88
- expect(integerFieldInfo.type).toBe("int")
89
-
90
- // test validation rules with a decimal value
91
- const result = integerFieldInfo.rules[1] ? integerFieldInfo.rules[1]("59.5") : undefined
92
-
93
- console.log("Validation result (DE):", result)
94
-
95
- // the validation should fail
96
- expect(result).not.toBe(true)
97
- expect(typeof result).toBe("string")
98
-
99
- // MOST IMPORTANT: verify the actual German translated string returned
100
- expect(result).toBe("Es wird eine ganze Zahl erwartet, tatsächlich: 59.5")
101
- })
102
- .pipe(Effect.runPromise))
103
-
104
- it("validates string field parsed as number", () =>
105
- Effect
106
- .gen(function*() {
107
- const fieldInfo = buildFieldInfoFromFieldsRoot(TestSchema)
108
- const stringFieldInfo = fieldInfo.fields.stringField
109
-
110
- expect(stringFieldInfo._tag).toBe("FieldInfo")
111
- expect(stringFieldInfo.type).toBe("text")
112
-
113
- // test validation rules with a number that should fail string validation
114
- const result = stringFieldInfo.rules[0] ? stringFieldInfo.rules[0]("123") : undefined
115
-
116
- console.log("Validation result for string field:", result)
117
-
118
- // string field should accept "123" as a valid string
119
- expect(result).toBe(true)
120
- })
121
- .pipe(Effect.runPromise))
122
-
123
- it("validates integer field with valid integer", () =>
124
- Effect
125
- .gen(function*() {
126
- const fieldInfo = buildFieldInfoFromFieldsRoot(TestSchema)
127
- const integerFieldInfo = fieldInfo.fields.integerField
128
-
129
- // test validation rules with a valid integer
130
- const result = integerFieldInfo.rules[1] ? integerFieldInfo.rules[1]("42") : undefined
131
-
132
- console.log("Validation result for valid integer:", result)
133
-
134
- // the validation should pass
135
- expect(result).toBe(true)
136
- })
137
- .pipe(Effect.runPromise))
138
-
139
- it("error message format matches regex pattern", () => {
140
- // test the actual error message format from Effect Schema
141
- const errorMessage = `Int
142
- └─ From side refinement failure
143
- └─ Int
144
- └─ Predicate refinement failure
145
- └─ Expected an integer, actual 59.5`
146
-
147
- const integerMatch = errorMessage.match(/Expected.*integer.*actual\s+(.+)/i)
148
- expect(integerMatch).toBeTruthy()
149
- expect(integerMatch![1]).toBe("59.5")
150
-
151
- const numberErrorMessage = `Number
152
- └─ Type side transformation failure
153
- └─ Expected a number, actual "not-a-number"`
154
-
155
- const numberMatch = numberErrorMessage.match(/Expected.*number.*actual\s+(.+)/i)
156
- expect(numberMatch).toBeTruthy()
157
- expect(numberMatch![1]).toBe("\"not-a-number\"")
158
- })
package/test/form.test.ts DELETED
@@ -1,261 +0,0 @@
1
- import { Effect, S } from "effect-app"
2
- import { buildFieldInfoFromFieldsRoot, type DiscriminatedUnionFieldInfo, type FieldInfo, type NestedFieldInfo, type UnionFieldInfo } from "../src/form.js"
3
-
4
- export class NestedSchema extends S.Class<NestedSchema>("NestedSchema")({
5
- shallow: S.String,
6
- nested: S.Struct({
7
- deep: S.NonEmptyString,
8
- nested: S.Struct({
9
- deepest: S.Finite
10
- })
11
- }),
12
- age: S.Struct({ nfs: S.FiniteFromString.pipe(S.decodeTo(S.PositiveInt)) })
13
- }) {}
14
-
15
- export class SchemaContainsClass extends S.Class<SchemaContainsClass>("SchemaContainsClass")({
16
- inner: NestedSchema
17
- }) {}
18
-
19
- export class UnionSchema extends S.Class<UnionSchema>("UnionSchema")({
20
- generalUnion: S.Union([S.String, S.Struct({ unionNested: NestedSchema })]),
21
- structsUnion: S.Union([NestedSchema, SchemaContainsClass]),
22
- optional: S.optional(S.String),
23
- nullable: S.NullOr(S.String)
24
- }) {}
25
-
26
- class Circle extends S.TaggedClass<Circle>()("Circle", {
27
- radius: S.PositiveInt
28
- }) {}
29
-
30
- class Square extends S.TaggedClass<Square>()("Square", {
31
- sideLength: S.PositiveInt
32
- }) {}
33
-
34
- class Triangle extends S.TaggedClass<Triangle>()("Triangle", {
35
- base: S.PositiveInt,
36
- height: S.Finite
37
- }) {}
38
-
39
- const CircleStruct = S.Struct({
40
- _tag: S.Literal("CircleStruct"),
41
- radius: S.PositiveInt
42
- })
43
-
44
- const SquareStruct = S.Struct({
45
- _tag: S.Literal("SquareStruct"),
46
- sideLength: S.PositiveInt
47
- })
48
-
49
- const TriangleStruct = S.Struct({
50
- _tag: S.Literal("TriangleStruct"),
51
- base: S.PositiveInt,
52
- height: S.Finite
53
- })
54
-
55
- const ShapeWithStructs = S.Union([CircleStruct, SquareStruct, TriangleStruct])
56
- const ShapeWithClasses = S.Union([Circle, Square, Triangle])
57
-
58
- export class ShapeContainer extends S.Class<ShapeContainer>("ShapeContainer")({
59
- shapeWithStruct: ShapeWithStructs,
60
- shapeWithClasses: ShapeWithClasses
61
- }) {}
62
-
63
- function testFieldInfo<T>(fi: FieldInfo<T>) {
64
- expect(fi).toBeInstanceOf(Object)
65
- expect(fi._tag).toBe("FieldInfo")
66
- expect(["text", "float", "int"]).toContain(fi.type)
67
- expect(fi.rules).toBeInstanceOf(Array)
68
- fi.rules.forEach((r) => {
69
- expect(r).toBeInstanceOf(Function)
70
- })
71
- expect(fi.metadata).toBeInstanceOf(Object)
72
- expect(fi.metadata.maxLength === void 0 || typeof fi.metadata.maxLength === "number").toBeTruthy()
73
- expect(fi.metadata.minLength === void 0 || typeof fi.metadata.minLength === "number").toBeTruthy()
74
- expect(typeof fi.metadata.required === "boolean").toBeTruthy()
75
- }
76
-
77
- function testUnionFieldInfo<T>(ufi: UnionFieldInfo<T[]>) {
78
- expect(ufi).toBeInstanceOf(Object)
79
- expect(ufi._tag).toBe("UnionFieldInfo")
80
- expect(ufi.members).toBeInstanceOf(Array)
81
- ufi.members.forEach(
82
- (
83
- i: any
84
- ) => {
85
- switch (i._tag) {
86
- case "FieldInfo":
87
- testFieldInfo(i as FieldInfo<any>)
88
- break
89
- case "NestedFieldInfo":
90
- testNestedFieldInfo(i as NestedFieldInfo<any>)
91
- break
92
- case "UnionFieldInfo":
93
- testUnionFieldInfo(i as UnionFieldInfo<any>)
94
- break
95
- case "DiscriminatedUnionFieldInfo":
96
- testDiscriminatedUnionFieldInfo(i as DiscriminatedUnionFieldInfo<any>)
97
- break
98
- }
99
- }
100
- )
101
- }
102
-
103
- function testNestedFieldInfo<T extends Record<PropertyKey, any>>(nfi: NestedFieldInfo<T>) {
104
- expect(nfi).toBeInstanceOf(Object)
105
- expect(nfi._tag).toBe("NestedFieldInfo")
106
- expect(nfi.fields).toBeInstanceOf(Object)
107
-
108
- // remove the value of _infoTag from the object when it is undefined
109
- // when it isn't undefined, the followin switch will ignore it
110
- Object.values(nfi).filter(Boolean).forEach(
111
- (
112
- i: any
113
- ) => {
114
- switch (i._tag) {
115
- case "FieldInfo":
116
- testFieldInfo(i as FieldInfo<any>)
117
- break
118
- case "NestedFieldInfo":
119
- testNestedFieldInfo(i as NestedFieldInfo<any>)
120
- break
121
- case "UnionFieldInfo":
122
- testUnionFieldInfo(i as UnionFieldInfo<any>)
123
- break
124
- case "DiscriminatedUnionFieldInfo":
125
- testDiscriminatedUnionFieldInfo(i as DiscriminatedUnionFieldInfo<any>)
126
- break
127
- }
128
- }
129
- )
130
- }
131
-
132
- function testDiscriminatedUnionFieldInfo<T extends Record<PropertyKey, any>>(dufi: DiscriminatedUnionFieldInfo<T>) {
133
- expect(dufi).toBeInstanceOf(Object)
134
- expect(dufi._tag).toBe("DiscriminatedUnionFieldInfo")
135
- expect(dufi.members).toBeInstanceOf(Object)
136
-
137
- Object.values(dufi.members).forEach(
138
- (
139
- i: any
140
- ) => {
141
- switch (i._tag) {
142
- case "FieldInfo":
143
- testFieldInfo(i as FieldInfo<any>)
144
- break
145
- case "NestedFieldInfo":
146
- testNestedFieldInfo(i as NestedFieldInfo<any>)
147
- break
148
- case "UnionFieldInfo":
149
- testUnionFieldInfo(i as UnionFieldInfo<any>)
150
- break
151
- case "DiscriminatedUnionFieldInfo":
152
- testDiscriminatedUnionFieldInfo(i as DiscriminatedUnionFieldInfo<any>)
153
- break
154
- }
155
- }
156
- )
157
- }
158
-
159
- it("buildFieldInfo", () =>
160
- Effect
161
- .gen(function*() {
162
- const nestedFieldinfo = buildFieldInfoFromFieldsRoot(NestedSchema)
163
- expectTypeOf(nestedFieldinfo).toEqualTypeOf<NestedFieldInfo<NestedSchema>>()
164
- expectTypeOf(nestedFieldinfo.fields.shallow).toEqualTypeOf<FieldInfo<string>>()
165
- expectTypeOf(nestedFieldinfo.fields.age).toEqualTypeOf<NestedFieldInfo<NestedSchema["age"]>>()
166
- // TODO: v4 migration - type inference changed with S.decodeTo, investigate if this is correct
167
- // expectTypeOf(nestedFieldinfo.fields.age.fields.nfs).toEqualTypeOf<FieldInfo<number & S.PositiveIntBrand>>()
168
- expectTypeOf(nestedFieldinfo.fields.nested).toEqualTypeOf<NestedFieldInfo<NestedSchema["nested"]>>()
169
- expectTypeOf(nestedFieldinfo.fields.nested.fields.deep).toEqualTypeOf<FieldInfo<string & S.NonEmptyStringBrand>>()
170
- expectTypeOf(nestedFieldinfo.fields.nested.fields.nested).toEqualTypeOf<
171
- NestedFieldInfo<NestedSchema["nested"]["nested"]>
172
- >()
173
- expectTypeOf(nestedFieldinfo.fields.nested.fields.nested.fields.deepest).toEqualTypeOf<FieldInfo<number>>()
174
-
175
- // it's a recursive check on actual runtime structure
176
- testNestedFieldInfo(nestedFieldinfo)
177
- testNestedFieldInfo(nestedFieldinfo.fields.nested)
178
- testNestedFieldInfo(nestedFieldinfo.fields.age)
179
- })
180
- .pipe(Effect.runPromise))
181
-
182
- it("buildFieldInfo schema containing class", () =>
183
- Effect
184
- .gen(function*() {
185
- const fieldinfo = buildFieldInfoFromFieldsRoot(SchemaContainsClass)
186
-
187
- // the type system says that these are NestedFieldInfo<NestedSchema>s
188
- // are they really? let's check
189
- testNestedFieldInfo(fieldinfo.fields.inner)
190
- testNestedFieldInfo(fieldinfo.fields.inner.fields.nested.fields.nested)
191
- })
192
- .pipe(Effect.runPromise))
193
-
194
- it("buildFieldInfo with simple union", () =>
195
- Effect
196
- .gen(function*() {
197
- const unionFieldinfo = buildFieldInfoFromFieldsRoot(UnionSchema)
198
- expectTypeOf(unionFieldinfo).toEqualTypeOf<NestedFieldInfo<UnionSchema>>()
199
- expectTypeOf(unionFieldinfo.fields.nullable).toEqualTypeOf<
200
- FieldInfo<string | null>
201
- >()
202
- expectTypeOf(unionFieldinfo.fields.optional).toEqualTypeOf<
203
- FieldInfo<string | undefined>
204
- >()
205
- expectTypeOf(unionFieldinfo.fields.structsUnion).toEqualTypeOf<
206
- UnionFieldInfo<(NestedFieldInfo<NestedSchema> | NestedFieldInfo<SchemaContainsClass>)[]>
207
- >()
208
- expectTypeOf(unionFieldinfo.fields.generalUnion).toEqualTypeOf<
209
- FieldInfo<
210
- string | {
211
- readonly unionNested: NestedSchema
212
- }
213
- >
214
- >
215
-
216
- // it's a recursive check on actual runtime structure
217
- testNestedFieldInfo(unionFieldinfo)
218
- testFieldInfo(unionFieldinfo.fields.nullable)
219
- testFieldInfo(unionFieldinfo.fields.optional)
220
- console.log({ asd: unionFieldinfo.fields.structsUnion })
221
- testUnionFieldInfo(unionFieldinfo.fields.structsUnion)
222
- testFieldInfo(unionFieldinfo.fields.generalUnion)
223
- })
224
- .pipe(Effect.runPromise))
225
-
226
- it("buildFieldInfo with tagged unions", () =>
227
- Effect
228
- .gen(function*() {
229
- const shapeFieldinfo = buildFieldInfoFromFieldsRoot(ShapeContainer)
230
-
231
- // check at runtime if the structure is really an union
232
- testDiscriminatedUnionFieldInfo(shapeFieldinfo.fields.shapeWithClasses)
233
- testDiscriminatedUnionFieldInfo(shapeFieldinfo.fields.shapeWithStruct)
234
-
235
- testNestedFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Square)
236
- expect(shapeFieldinfo.fields.shapeWithClasses.members.Square._infoTag).toBe("Square")
237
- testFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Square.fields.sideLength)
238
-
239
- testNestedFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Triangle)
240
- expect(shapeFieldinfo.fields.shapeWithClasses.members.Triangle._infoTag).toBe("Triangle")
241
- testFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Triangle.fields.base)
242
- testFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Triangle.fields.height)
243
-
244
- testNestedFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Circle)
245
- expect(shapeFieldinfo.fields.shapeWithClasses.members.Circle._infoTag).toBe("Circle")
246
- testFieldInfo(shapeFieldinfo.fields.shapeWithClasses.members.Circle.fields.radius)
247
-
248
- testNestedFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.SquareStruct)
249
- expect(shapeFieldinfo.fields.shapeWithStruct.members.SquareStruct._infoTag).toBe("SquareStruct")
250
- testFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.SquareStruct.fields.sideLength)
251
-
252
- testNestedFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.TriangleStruct)
253
- expect(shapeFieldinfo.fields.shapeWithStruct.members.TriangleStruct._infoTag).toBe("TriangleStruct")
254
- testFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.TriangleStruct.fields.base)
255
- testFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.TriangleStruct.fields.height)
256
-
257
- testNestedFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.CircleStruct)
258
- expect(shapeFieldinfo.fields.shapeWithStruct.members.CircleStruct._infoTag).toBe("CircleStruct")
259
- testFieldInfo(shapeFieldinfo.fields.shapeWithStruct.members.CircleStruct.fields.radius)
260
- })
261
- .pipe(Effect.runPromise))