@tanstack/form-core 0.23.2 → 0.24.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/dist/cjs/FieldApi.cjs +6 -4
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +220 -2
- package/dist/cjs/FormApi.cjs +6 -0
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +228 -0
- package/dist/cjs/mergeForm.cjs.map +1 -1
- package/dist/cjs/mergeForm.d.cts +3 -0
- package/dist/cjs/types.d.cts +14 -0
- package/dist/cjs/util-types.d.cts +18 -3
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +24 -0
- package/dist/esm/FieldApi.d.ts +220 -2
- package/dist/esm/FieldApi.js +6 -4
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +228 -0
- package/dist/esm/FormApi.js +6 -0
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/mergeForm.d.ts +3 -0
- package/dist/esm/mergeForm.js.map +1 -1
- package/dist/esm/types.d.ts +14 -0
- package/dist/esm/util-types.d.ts +18 -3
- package/dist/esm/utils.d.ts +24 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/FieldApi.ts +222 -9
- package/src/FormApi.ts +228 -12
- package/src/mergeForm.ts +3 -0
- package/src/types.ts +14 -2
- package/src/util-types.ts +18 -4
- package/src/utils.ts +24 -0
- package/src/tests/FieldApi.spec.ts +0 -1184
- package/src/tests/FieldApi.test-d.ts +0 -149
- package/src/tests/FormApi.spec.ts +0 -1523
- package/src/tests/formOptions.test.ts +0 -25
- package/src/tests/mutateMergeDeep.spec.ts +0 -32
- package/src/tests/util-types.test-d.ts +0 -171
- package/src/tests/utils.spec.ts +0 -131
- package/src/tests/utils.ts +0 -5
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { FormApi, formOptions } from '../index'
|
|
3
|
-
|
|
4
|
-
describe('formOptions', () => {
|
|
5
|
-
it('should allow default values to be set', async () => {
|
|
6
|
-
type Person = {
|
|
7
|
-
firstName: string
|
|
8
|
-
lastName: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const formOpts = formOptions<Person>({
|
|
12
|
-
defaultValues: {
|
|
13
|
-
firstName: 'FirstName',
|
|
14
|
-
lastName: 'LastName',
|
|
15
|
-
},
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const form = new FormApi({
|
|
19
|
-
...formOpts,
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
expect(form.state.values['firstName']).toBe('FirstName')
|
|
23
|
-
expect(form.state.values['lastName']).toBe('LastName')
|
|
24
|
-
})
|
|
25
|
-
})
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest'
|
|
2
|
-
import { mutateMergeDeep } from '../mergeForm'
|
|
3
|
-
|
|
4
|
-
describe('mutateMergeDeep', () => {
|
|
5
|
-
test('Should merge two objects by mutating', () => {
|
|
6
|
-
const a = { a: 1 }
|
|
7
|
-
const b = { b: 2 }
|
|
8
|
-
mutateMergeDeep(a, b)
|
|
9
|
-
expect(a).toStrictEqual({ a: 1, b: 2 })
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test('Should merge two objects including overwriting with undefined', () => {
|
|
13
|
-
const a = { a: 1 }
|
|
14
|
-
const b = { a: undefined }
|
|
15
|
-
mutateMergeDeep(a, b)
|
|
16
|
-
expect(a).toStrictEqual({ a: undefined })
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('Should merge two object by merging arrays', () => {
|
|
20
|
-
const a = { a: [1] }
|
|
21
|
-
const b = { a: [2] }
|
|
22
|
-
mutateMergeDeep(a, b)
|
|
23
|
-
expect(a).toStrictEqual({ a: [1, 2] })
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('Should merge two deeply nested objects', () => {
|
|
27
|
-
const a = { a: { a: 1 } }
|
|
28
|
-
const b = { a: { b: 2 } }
|
|
29
|
-
mutateMergeDeep(a, b)
|
|
30
|
-
expect(a).toStrictEqual({ a: { a: 1, b: 2 } })
|
|
31
|
-
})
|
|
32
|
-
})
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { assertType } from 'vitest'
|
|
2
|
-
import type { DeepKeys, DeepValue } from '../util-types'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Properly recognizes that `0` is not an object and should not have subkeys
|
|
6
|
-
*/
|
|
7
|
-
type TupleSupport = DeepKeys<{ topUsers: [User, 0, User] }>
|
|
8
|
-
assertType<
|
|
9
|
-
| 'topUsers'
|
|
10
|
-
| 'topUsers[0]'
|
|
11
|
-
| 'topUsers[0].name'
|
|
12
|
-
| 'topUsers[0].id'
|
|
13
|
-
| 'topUsers[0].age'
|
|
14
|
-
| 'topUsers[1]'
|
|
15
|
-
| 'topUsers[2]'
|
|
16
|
-
| 'topUsers[2].name'
|
|
17
|
-
| 'topUsers[2].id'
|
|
18
|
-
| 'topUsers[2].age'
|
|
19
|
-
>(0 as never as TupleSupport)
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Properly recognizes that a normal number index won't cut it and should be `[number]` prefixed instead
|
|
23
|
-
*/
|
|
24
|
-
type ArraySupport = DeepKeys<{ users: User[] }>
|
|
25
|
-
assertType<
|
|
26
|
-
| 'users'
|
|
27
|
-
| `users[${number}].name`
|
|
28
|
-
| `users[${number}].id`
|
|
29
|
-
| `users[${number}].age`
|
|
30
|
-
>(0 as never as ArraySupport)
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Properly handles deep object nesting like so:
|
|
34
|
-
*/
|
|
35
|
-
type NestedSupport = DeepKeys<{ meta: { mainUser: User } }>
|
|
36
|
-
assertType<
|
|
37
|
-
| 'meta'
|
|
38
|
-
| 'meta.mainUser'
|
|
39
|
-
| 'meta.mainUser.name'
|
|
40
|
-
| 'meta.mainUser.id'
|
|
41
|
-
| 'meta.mainUser.age'
|
|
42
|
-
>(0 as never as NestedSupport)
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Properly handles deep partial object nesting like so:
|
|
46
|
-
*/
|
|
47
|
-
type NestedPartialSupport = DeepKeys<{ meta?: { mainUser?: User } }>
|
|
48
|
-
assertType<
|
|
49
|
-
| 'meta'
|
|
50
|
-
| 'meta.mainUser'
|
|
51
|
-
| 'meta.mainUser.name'
|
|
52
|
-
| 'meta.mainUser.id'
|
|
53
|
-
| 'meta.mainUser.age'
|
|
54
|
-
>(0 as never as NestedPartialSupport)
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Properly handles `object` edgecase nesting like so:
|
|
58
|
-
*/
|
|
59
|
-
type ObjectNestedEdgecase = DeepKeys<{ meta: { mainUser: object } }>
|
|
60
|
-
assertType<'meta' | 'meta.mainUser' | `meta.mainUser.${string}`>(
|
|
61
|
-
0 as never as ObjectNestedEdgecase,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Properly handles `object` edgecase like so:
|
|
66
|
-
*/
|
|
67
|
-
type ObjectEdgecase = DeepKeys<object>
|
|
68
|
-
assertType<string>(0 as never as ObjectEdgecase)
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Properly handles `object` edgecase nesting like so:
|
|
72
|
-
*/
|
|
73
|
-
type UnknownNestedEdgecase = DeepKeys<{ meta: { mainUser: unknown } }>
|
|
74
|
-
assertType<'meta' | 'meta.mainUser' | `meta.mainUser.${string}`>(
|
|
75
|
-
0 as never as UnknownNestedEdgecase,
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Properly handles `object` edgecase like so:
|
|
80
|
-
*/
|
|
81
|
-
type UnknownEdgecase = DeepKeys<unknown>
|
|
82
|
-
assertType<string>(0 as never as UnknownEdgecase)
|
|
83
|
-
|
|
84
|
-
type NestedKeysExample = DeepValue<
|
|
85
|
-
{ meta: { mainUser: User } },
|
|
86
|
-
'meta.mainUser.age'
|
|
87
|
-
>
|
|
88
|
-
assertType<number>(0 as never as NestedKeysExample)
|
|
89
|
-
|
|
90
|
-
type NestedNullableKeys = DeepValue<
|
|
91
|
-
{
|
|
92
|
-
meta: { mainUser: 'hello' } | null
|
|
93
|
-
},
|
|
94
|
-
'meta.mainUser'
|
|
95
|
-
>
|
|
96
|
-
assertType<'hello' | null>(0 as never as NestedNullableKeys)
|
|
97
|
-
|
|
98
|
-
type NestedArrayExample = DeepValue<{ users: User[] }, 'users[0].age'>
|
|
99
|
-
assertType<number>(0 as never as NestedArrayExample)
|
|
100
|
-
|
|
101
|
-
type NestedLooseArrayExample = DeepValue<{ users: User[] }, 'users[number].age'>
|
|
102
|
-
assertType<number>(0 as never as NestedLooseArrayExample)
|
|
103
|
-
|
|
104
|
-
type NestedTupleExample = DeepValue<
|
|
105
|
-
{ topUsers: [User, 0, User] },
|
|
106
|
-
'topUsers[0].age'
|
|
107
|
-
>
|
|
108
|
-
assertType<number>(0 as never as NestedTupleExample)
|
|
109
|
-
|
|
110
|
-
type NestedTupleBroadExample = DeepValue<
|
|
111
|
-
{ topUsers: User[] },
|
|
112
|
-
`topUsers[${number}].age`
|
|
113
|
-
>
|
|
114
|
-
assertType<number>(0 as never as NestedTupleBroadExample)
|
|
115
|
-
|
|
116
|
-
type DeeplyNestedTupleBroadExample = DeepValue<
|
|
117
|
-
{ nested: { topUsers: User[] } },
|
|
118
|
-
`nested.topUsers[${number}].age`
|
|
119
|
-
>
|
|
120
|
-
assertType<number>(0 as never as DeeplyNestedTupleBroadExample)
|
|
121
|
-
|
|
122
|
-
type SimpleArrayExample = DeepValue<User[], `[${number}]`>
|
|
123
|
-
assertType<User>(0 as never as SimpleArrayExample)
|
|
124
|
-
|
|
125
|
-
type SimpleNestedArrayExample = DeepValue<User[], `[${number}].age`>
|
|
126
|
-
assertType<number>(0 as never as SimpleNestedArrayExample)
|
|
127
|
-
|
|
128
|
-
type NestedTupleItemExample = DeepValue<
|
|
129
|
-
{ topUsers: [User, 0, User] },
|
|
130
|
-
'topUsers[1]'
|
|
131
|
-
>
|
|
132
|
-
assertType<0>(0 as never as NestedTupleItemExample)
|
|
133
|
-
|
|
134
|
-
type ArrayExample = DeepValue<[1, 2, 3], '[1]'>
|
|
135
|
-
assertType<2>(0 as never as ArrayExample)
|
|
136
|
-
|
|
137
|
-
type NonNestedObjExample = DeepValue<{ a: 1 }, 'a'>
|
|
138
|
-
assertType<1>(0 as never as NonNestedObjExample)
|
|
139
|
-
|
|
140
|
-
interface User {
|
|
141
|
-
name: string
|
|
142
|
-
id: string
|
|
143
|
-
age: number
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
type FormDefinition = {
|
|
147
|
-
nested: {
|
|
148
|
-
people: User[]
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
type FormDefinitionValue = DeepValue<
|
|
153
|
-
FormDefinition,
|
|
154
|
-
`nested.people[${number}].name`
|
|
155
|
-
>
|
|
156
|
-
|
|
157
|
-
assertType<string>(0 as never as FormDefinitionValue)
|
|
158
|
-
|
|
159
|
-
type DoubleDeepArray = DeepValue<
|
|
160
|
-
{
|
|
161
|
-
people: {
|
|
162
|
-
parents: {
|
|
163
|
-
name: string
|
|
164
|
-
age: number
|
|
165
|
-
}[]
|
|
166
|
-
}[]
|
|
167
|
-
},
|
|
168
|
-
`people[${0}].parents[${0}].name`
|
|
169
|
-
>
|
|
170
|
-
|
|
171
|
-
assertType<string>(0 as never as DoubleDeepArray)
|
package/src/tests/utils.spec.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { deleteBy, getBy, makePathArray, setBy } from '../utils'
|
|
3
|
-
|
|
4
|
-
describe('getBy', () => {
|
|
5
|
-
const structure = {
|
|
6
|
-
name: 'Marc',
|
|
7
|
-
kids: [
|
|
8
|
-
{ name: 'Stephen', age: 10, hobbies: ['soccer', 'reading'] },
|
|
9
|
-
{ name: 'Taylor', age: 15, hobbies: ['swimming', 'gaming'] },
|
|
10
|
-
],
|
|
11
|
-
mother: {
|
|
12
|
-
name: 'Lisa',
|
|
13
|
-
},
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
it('should get subfields by path', () => {
|
|
17
|
-
expect(getBy(structure, 'name')).toBe(structure.name)
|
|
18
|
-
expect(getBy(structure, 'mother.name')).toBe(structure.mother.name)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should get array subfields by path', () => {
|
|
22
|
-
expect(getBy(structure, 'kids[0].name')).toBe(structure.kids[0]!.name)
|
|
23
|
-
expect(getBy(structure, 'kids[0].age')).toBe(structure.kids[0]!.age)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('should get nested array subfields by path', () => {
|
|
27
|
-
expect(getBy(structure, 'kids[0].hobbies[0]')).toBe(
|
|
28
|
-
structure.kids[0]!.hobbies[0],
|
|
29
|
-
)
|
|
30
|
-
expect(getBy(structure, 'kids[0].hobbies[1]')).toBe(
|
|
31
|
-
structure.kids[0]!.hobbies[1],
|
|
32
|
-
)
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
describe('setBy', () => {
|
|
37
|
-
const structure = {
|
|
38
|
-
name: 'Marc',
|
|
39
|
-
kids: [
|
|
40
|
-
{ name: 'Stephen', age: 10, hobbies: ['soccer', 'reading'] },
|
|
41
|
-
{ name: 'Taylor', age: 15, hobbies: ['swimming', 'gaming'] },
|
|
42
|
-
],
|
|
43
|
-
mother: {
|
|
44
|
-
name: 'Lisa',
|
|
45
|
-
},
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
it('should set subfields by path', () => {
|
|
49
|
-
expect(setBy(structure, 'name', 'Lisa').name).toBe('Lisa')
|
|
50
|
-
expect(setBy(structure, 'mother.name', 'Tina').mother.name).toBe('Tina')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('should set array subfields by path', () => {
|
|
54
|
-
expect(setBy(structure, 'kids[0].name', 'Taylor').kids[0].name).toBe(
|
|
55
|
-
'Taylor',
|
|
56
|
-
)
|
|
57
|
-
expect(setBy(structure, 'kids[0].age', 20).kids[0].age).toBe(20)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('should set nested array subfields by path', () => {
|
|
61
|
-
expect(
|
|
62
|
-
setBy(structure, 'kids[0].hobbies[0]', 'swimming').kids[0].hobbies[0],
|
|
63
|
-
).toBe('swimming')
|
|
64
|
-
expect(
|
|
65
|
-
setBy(structure, 'kids[0].hobbies[1]', 'gaming').kids[0].hobbies[1],
|
|
66
|
-
).toBe('gaming')
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
describe('deleteBy', () => {
|
|
71
|
-
const structure = {
|
|
72
|
-
name: 'Marc',
|
|
73
|
-
kids: [
|
|
74
|
-
{ name: 'Stephen', age: 10, hobbies: ['soccer', 'reading'] },
|
|
75
|
-
{ name: 'Taylor', age: 15, hobbies: ['swimming', 'gaming'] },
|
|
76
|
-
],
|
|
77
|
-
mother: {
|
|
78
|
-
name: 'Lisa',
|
|
79
|
-
},
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
it('should delete subfields by path', () => {
|
|
83
|
-
expect(deleteBy(structure, 'name').name).not.toBeDefined()
|
|
84
|
-
expect(deleteBy(structure, 'mother.name').mother.name).not.toBeDefined()
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('should delete array subfields by path', () => {
|
|
88
|
-
expect(deleteBy(structure, 'kids[0].name').kids[0].name).not.toBeDefined()
|
|
89
|
-
expect(deleteBy(structure, 'kids[0].age').kids[0].age).not.toBeDefined()
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('should delete nested array subfields by path', () => {
|
|
93
|
-
expect(deleteBy(structure, 'kids[0].hobbies[0]').kids[0].hobbies[0]).toBe(
|
|
94
|
-
'reading',
|
|
95
|
-
)
|
|
96
|
-
expect(
|
|
97
|
-
deleteBy(structure, 'kids[0].hobbies[1]').kids[0].hobbies[1],
|
|
98
|
-
).not.toBeDefined()
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should delete non-existent paths like a noop', () => {
|
|
102
|
-
expect(deleteBy(structure, 'nonexistent')).toEqual(structure)
|
|
103
|
-
expect(deleteBy(structure, 'nonexistent.nonexistent')).toEqual(structure)
|
|
104
|
-
expect(deleteBy(structure, 'kids[3].name')).toEqual(structure)
|
|
105
|
-
expect(deleteBy(structure, 'nonexistent[3].nonexistent')).toEqual(structure)
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
describe('makePathArray', () => {
|
|
110
|
-
it('should convert dot notation to array', () => {
|
|
111
|
-
expect(makePathArray('name')).toEqual(['name'])
|
|
112
|
-
expect(makePathArray('mother.name')).toEqual(['mother', 'name'])
|
|
113
|
-
expect(makePathArray('kids[0].name')).toEqual(['kids', 0, 'name'])
|
|
114
|
-
expect(makePathArray('kids[0].name[1]')).toEqual(['kids', 0, 'name', 1])
|
|
115
|
-
expect(makePathArray('kids[0].name[1].age')).toEqual([
|
|
116
|
-
'kids',
|
|
117
|
-
0,
|
|
118
|
-
'name',
|
|
119
|
-
1,
|
|
120
|
-
'age',
|
|
121
|
-
])
|
|
122
|
-
expect(makePathArray('kids[0].name[1].age[2]')).toEqual([
|
|
123
|
-
'kids',
|
|
124
|
-
0,
|
|
125
|
-
'name',
|
|
126
|
-
1,
|
|
127
|
-
'age',
|
|
128
|
-
2,
|
|
129
|
-
])
|
|
130
|
-
})
|
|
131
|
-
})
|