rfhook 1.0.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/.vscode/settings.json +5 -0
- package/README.md +270 -0
- package/dist/index.cjs +65 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +63 -0
- package/dist/useForm.hook.d.ts +8 -0
- package/dist/utils/parseFormData.d.ts +1 -0
- package/package.json +28 -0
- package/rollup.config.js +18 -0
- package/src/index.ts +1 -0
- package/src/useForm.hook.ts +25 -0
- package/src/utils/parseFormData.ts +60 -0
- package/tsconfig.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# @eji/form-hook
|
|
2
|
+
|
|
3
|
+
A lightweight React hook for handling form submissions with advanced form data parsing capabilities. Supports nested objects, arrays, and dot notation for complex form structures.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Simple API** - Just one hook to handle all your form needs
|
|
8
|
+
- 🎯 **TypeScript Support** - Fully typed with generic support
|
|
9
|
+
- 🔧 **Nested Objects** - Parse nested form data with dot notation (`user.name`)
|
|
10
|
+
- 📋 **Array Support** - Handle arrays with indexed notation (`items[0]`)
|
|
11
|
+
- 📦 **Lightweight** - Zero dependencies (except React)
|
|
12
|
+
- 🎨 **Framework Agnostic** - Works with any form structure
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @eji/form-hook
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @eji/form-hook
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
yarn add @eji/form-hook
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import React from 'react';
|
|
32
|
+
import { useForm } from '@eji/form-hook';
|
|
33
|
+
|
|
34
|
+
interface FormData {
|
|
35
|
+
email: string;
|
|
36
|
+
password: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function LoginForm() {
|
|
40
|
+
const { ref, submit } = useForm<FormData>({
|
|
41
|
+
handleSubmit: (data) => {
|
|
42
|
+
console.log(data); // { email: "user@example.com", password: "secret" }
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<form ref={ref} onSubmit={submit}>
|
|
48
|
+
<input name="email" type="email" />
|
|
49
|
+
<input name="password" type="password" />
|
|
50
|
+
<button type="submit">Login</button>
|
|
51
|
+
</form>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Advanced Usage
|
|
57
|
+
|
|
58
|
+
### Nested Objects
|
|
59
|
+
|
|
60
|
+
Use dot notation to create nested objects:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
interface UserForm {
|
|
64
|
+
user: {
|
|
65
|
+
profile: {
|
|
66
|
+
name: string;
|
|
67
|
+
age: number;
|
|
68
|
+
};
|
|
69
|
+
preferences: {
|
|
70
|
+
theme: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function UserForm() {
|
|
76
|
+
const { ref, submit } = useForm<UserForm>({
|
|
77
|
+
handleSubmit: (data) => {
|
|
78
|
+
console.log(data);
|
|
79
|
+
// {
|
|
80
|
+
// user: {
|
|
81
|
+
// profile: {
|
|
82
|
+
// name: "John Doe",
|
|
83
|
+
// age: "30"
|
|
84
|
+
// },
|
|
85
|
+
// preferences: {
|
|
86
|
+
// theme: "dark"
|
|
87
|
+
// }
|
|
88
|
+
// }
|
|
89
|
+
// }
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<form ref={ref} onSubmit={submit}>
|
|
95
|
+
<input name="user.profile.name" placeholder="Name" />
|
|
96
|
+
<input name="user.profile.age" type="number" placeholder="Age" />
|
|
97
|
+
<select name="user.preferences.theme">
|
|
98
|
+
<option value="light">Light</option>
|
|
99
|
+
<option value="dark">Dark</option>
|
|
100
|
+
</select>
|
|
101
|
+
<button type="submit">Submit</button>
|
|
102
|
+
</form>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Arrays
|
|
108
|
+
|
|
109
|
+
Use bracket notation to handle arrays:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
interface TodoForm {
|
|
113
|
+
todos: Array<{
|
|
114
|
+
title: string;
|
|
115
|
+
completed: boolean;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function TodoForm() {
|
|
120
|
+
const { ref, submit } = useForm<TodoForm>({
|
|
121
|
+
handleSubmit: (data) => {
|
|
122
|
+
console.log(data);
|
|
123
|
+
// {
|
|
124
|
+
// todos: [
|
|
125
|
+
// { title: "Buy groceries", completed: false },
|
|
126
|
+
// { title: "Walk the dog", completed: true }
|
|
127
|
+
// ]
|
|
128
|
+
// }
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<form ref={ref} onSubmit={submit}>
|
|
134
|
+
<input name="todos[0].title" placeholder="First todo" />
|
|
135
|
+
<input name="todos[0].completed" type="checkbox" />
|
|
136
|
+
|
|
137
|
+
<input name="todos[1].title" placeholder="Second todo" />
|
|
138
|
+
<input name="todos[1].completed" type="checkbox" />
|
|
139
|
+
|
|
140
|
+
<button type="submit">Submit</button>
|
|
141
|
+
</form>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## API Reference
|
|
147
|
+
|
|
148
|
+
### `useForm<T>(options)`
|
|
149
|
+
|
|
150
|
+
#### Parameters
|
|
151
|
+
|
|
152
|
+
- `options.handleSubmit: (data: T) => void` - Callback function called when form is submitted
|
|
153
|
+
|
|
154
|
+
#### Returns
|
|
155
|
+
|
|
156
|
+
- `ref: RefObject<HTMLFormElement>` - React ref to attach to your form element
|
|
157
|
+
- `submit: (event: React.FormEvent) => void` - Submit handler to attach to form's `onSubmit`
|
|
158
|
+
|
|
159
|
+
### Form Data Parsing Rules
|
|
160
|
+
|
|
161
|
+
The `parseFormData` utility converts FormData into structured objects using these rules:
|
|
162
|
+
|
|
163
|
+
1. **Dot notation** creates nested objects: `user.name` → `{ user: { name: "value" } }`
|
|
164
|
+
2. **Bracket notation** creates arrays: `items[0]` → `{ items: ["value"] }`
|
|
165
|
+
3. **Combined notation** works: `users[0].name` → `{ users: [{ name: "value" }] }`
|
|
166
|
+
|
|
167
|
+
## Examples
|
|
168
|
+
|
|
169
|
+
### Contact Form
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
import { useForm } from '@eji/form-hook';
|
|
173
|
+
|
|
174
|
+
interface ContactData {
|
|
175
|
+
name: string;
|
|
176
|
+
email: string;
|
|
177
|
+
message: string;
|
|
178
|
+
preferences: {
|
|
179
|
+
newsletter: boolean;
|
|
180
|
+
notifications: boolean;
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function ContactForm() {
|
|
185
|
+
const { ref, submit } = useForm<ContactData>({
|
|
186
|
+
handleSubmit: async (data) => {
|
|
187
|
+
try {
|
|
188
|
+
const response = await fetch('/api/contact', {
|
|
189
|
+
method: 'POST',
|
|
190
|
+
headers: { 'Content-Type': 'application/json' },
|
|
191
|
+
body: JSON.stringify(data)
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (response.ok) {
|
|
195
|
+
alert('Message sent successfully!');
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error('Failed to send message:', error);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<form ref={ref} onSubmit={submit}>
|
|
205
|
+
<input name="name" placeholder="Your Name" required />
|
|
206
|
+
<input name="email" type="email" placeholder="Your Email" required />
|
|
207
|
+
<textarea name="message" placeholder="Your Message" required />
|
|
208
|
+
|
|
209
|
+
<fieldset>
|
|
210
|
+
<legend>Preferences</legend>
|
|
211
|
+
<label>
|
|
212
|
+
<input name="preferences.newsletter" type="checkbox" />
|
|
213
|
+
Subscribe to newsletter
|
|
214
|
+
</label>
|
|
215
|
+
<label>
|
|
216
|
+
<input name="preferences.notifications" type="checkbox" />
|
|
217
|
+
Enable notifications
|
|
218
|
+
</label>
|
|
219
|
+
</fieldset>
|
|
220
|
+
|
|
221
|
+
<button type="submit">Send Message</button>
|
|
222
|
+
</form>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## TypeScript Support
|
|
228
|
+
|
|
229
|
+
The hook is fully typed and supports generic type parameters for form data:
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
interface MyFormData {
|
|
233
|
+
// Define your form structure here
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const { ref, submit } = useForm<MyFormData>({
|
|
237
|
+
handleSubmit: (data) => {
|
|
238
|
+
// data is typed as MyFormData
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Browser Support
|
|
244
|
+
|
|
245
|
+
- All modern browsers that support ES2020
|
|
246
|
+
- React 16.8+ (hooks support required)
|
|
247
|
+
|
|
248
|
+
## Contributing
|
|
249
|
+
|
|
250
|
+
1. Fork the repository
|
|
251
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
252
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
253
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
254
|
+
5. Open a Pull Request
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
ISC
|
|
259
|
+
|
|
260
|
+
## Development
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Install dependencies
|
|
264
|
+
pnpm install
|
|
265
|
+
|
|
266
|
+
# Build the package
|
|
267
|
+
pnpm run build
|
|
268
|
+
|
|
269
|
+
# The built files will be in the `dist/` directory
|
|
270
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
const ARRAY_KEY_REGEX = /^(\w+)\[(\d+)\]$/;
|
|
6
|
+
function parseFormData(formData) {
|
|
7
|
+
const data = Object.fromEntries(formData.entries());
|
|
8
|
+
const result = {};
|
|
9
|
+
for (const [path, value] of Object.entries(data)) {
|
|
10
|
+
const keys = path.split('.');
|
|
11
|
+
let current = result;
|
|
12
|
+
for (let i = 0; i < keys.length; i++) {
|
|
13
|
+
const key = keys[i];
|
|
14
|
+
const isLastKey = i === keys.length - 1;
|
|
15
|
+
const arrayMatch = key.match(ARRAY_KEY_REGEX);
|
|
16
|
+
// Handle array notation like items[0]
|
|
17
|
+
if (arrayMatch) {
|
|
18
|
+
const [, arrayKey, indexStr] = arrayMatch;
|
|
19
|
+
const index = parseInt(indexStr, 10);
|
|
20
|
+
// Initialize array if it doesn't exist
|
|
21
|
+
if (!Array.isArray(current[arrayKey])) {
|
|
22
|
+
current[arrayKey] = [];
|
|
23
|
+
}
|
|
24
|
+
const array = current[arrayKey];
|
|
25
|
+
// Set value and continue if this is the last key
|
|
26
|
+
if (isLastKey) {
|
|
27
|
+
array[index] = value;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
// Initialize nested object and move to it
|
|
31
|
+
if (!array[index] || typeof array[index] !== 'object') {
|
|
32
|
+
array[index] = {};
|
|
33
|
+
}
|
|
34
|
+
current = array[index];
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Handle regular keys - set value and continue if this is the last key
|
|
38
|
+
if (isLastKey) {
|
|
39
|
+
current[key] = value;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Initialize nested object and move to it
|
|
43
|
+
if (!current[key] || typeof current[key] !== 'object' || Array.isArray(current[key])) {
|
|
44
|
+
current[key] = {};
|
|
45
|
+
}
|
|
46
|
+
current = current[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function useForm({ handleSubmit }) {
|
|
53
|
+
const ref = react.useRef(null);
|
|
54
|
+
const submit = (event) => {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
if (!ref.current)
|
|
57
|
+
return;
|
|
58
|
+
const formData = new FormData(ref.current);
|
|
59
|
+
const data = parseFormData(formData);
|
|
60
|
+
handleSubmit(data);
|
|
61
|
+
};
|
|
62
|
+
return { ref, submit };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.useForm = useForm;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useForm } from './useForm.hook';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
const ARRAY_KEY_REGEX = /^(\w+)\[(\d+)\]$/;
|
|
4
|
+
function parseFormData(formData) {
|
|
5
|
+
const data = Object.fromEntries(formData.entries());
|
|
6
|
+
const result = {};
|
|
7
|
+
for (const [path, value] of Object.entries(data)) {
|
|
8
|
+
const keys = path.split('.');
|
|
9
|
+
let current = result;
|
|
10
|
+
for (let i = 0; i < keys.length; i++) {
|
|
11
|
+
const key = keys[i];
|
|
12
|
+
const isLastKey = i === keys.length - 1;
|
|
13
|
+
const arrayMatch = key.match(ARRAY_KEY_REGEX);
|
|
14
|
+
// Handle array notation like items[0]
|
|
15
|
+
if (arrayMatch) {
|
|
16
|
+
const [, arrayKey, indexStr] = arrayMatch;
|
|
17
|
+
const index = parseInt(indexStr, 10);
|
|
18
|
+
// Initialize array if it doesn't exist
|
|
19
|
+
if (!Array.isArray(current[arrayKey])) {
|
|
20
|
+
current[arrayKey] = [];
|
|
21
|
+
}
|
|
22
|
+
const array = current[arrayKey];
|
|
23
|
+
// Set value and continue if this is the last key
|
|
24
|
+
if (isLastKey) {
|
|
25
|
+
array[index] = value;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// Initialize nested object and move to it
|
|
29
|
+
if (!array[index] || typeof array[index] !== 'object') {
|
|
30
|
+
array[index] = {};
|
|
31
|
+
}
|
|
32
|
+
current = array[index];
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
// Handle regular keys - set value and continue if this is the last key
|
|
36
|
+
if (isLastKey) {
|
|
37
|
+
current[key] = value;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Initialize nested object and move to it
|
|
41
|
+
if (!current[key] || typeof current[key] !== 'object' || Array.isArray(current[key])) {
|
|
42
|
+
current[key] = {};
|
|
43
|
+
}
|
|
44
|
+
current = current[key];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function useForm({ handleSubmit }) {
|
|
51
|
+
const ref = useRef(null);
|
|
52
|
+
const submit = (event) => {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
if (!ref.current)
|
|
55
|
+
return;
|
|
56
|
+
const formData = new FormData(ref.current);
|
|
57
|
+
const data = parseFormData(formData);
|
|
58
|
+
handleSubmit(data);
|
|
59
|
+
};
|
|
60
|
+
return { ref, submit };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { useForm };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseFormData(formData: FormData): Record<string, unknown>;
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rfhook",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"react": "^19.2.3",
|
|
14
|
+
"react-dom": "^19.2.3"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
18
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
19
|
+
"@types/react": "^19.2.8",
|
|
20
|
+
"@types/react-dom": "^19.2.3",
|
|
21
|
+
"rollup": "^4.55.2",
|
|
22
|
+
"tslib": "^2.8.1",
|
|
23
|
+
"typescript": "^5.9.3"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "rollup -c"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import typescript from '@rollup/plugin-typescript';
|
|
2
|
+
import nodeResolve from '@rollup/plugin-node-resolve';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
input: 'src/index.ts',
|
|
6
|
+
external: ['react'],
|
|
7
|
+
plugins: [typescript(), nodeResolve()],
|
|
8
|
+
output: [
|
|
9
|
+
{
|
|
10
|
+
file: 'dist/index.js',
|
|
11
|
+
format: 'esm'
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
file: 'dist/index.cjs',
|
|
15
|
+
format: 'cjs'
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useForm } from './useForm.hook';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { parseFormData } from './utils/parseFormData';
|
|
4
|
+
|
|
5
|
+
interface UseForm<T> {
|
|
6
|
+
handleSubmit: (data: T) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function useForm<T = object>({ handleSubmit }: UseForm<T>) {
|
|
10
|
+
const ref = useRef<HTMLFormElement>(null);
|
|
11
|
+
|
|
12
|
+
const submit = (event: React.FormEvent) => {
|
|
13
|
+
event.preventDefault();
|
|
14
|
+
|
|
15
|
+
if (!ref.current) return
|
|
16
|
+
|
|
17
|
+
const formData = new FormData(ref.current);
|
|
18
|
+
|
|
19
|
+
const data: object = parseFormData(formData);
|
|
20
|
+
|
|
21
|
+
handleSubmit(data as T);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return { ref, submit };
|
|
25
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const ARRAY_KEY_REGEX = /^(\w+)\[(\d+)\]$/;
|
|
2
|
+
|
|
3
|
+
export function parseFormData(formData: FormData): Record<string, unknown> {
|
|
4
|
+
const data = Object.fromEntries(formData.entries());
|
|
5
|
+
const result: Record<string, unknown> = {};
|
|
6
|
+
|
|
7
|
+
for (const [path, value] of Object.entries(data)) {
|
|
8
|
+
const keys = path.split('.')
|
|
9
|
+
let current = result;
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < keys.length; i++) {
|
|
12
|
+
const key = keys[i];
|
|
13
|
+
const isLastKey = i === keys.length - 1;
|
|
14
|
+
const arrayMatch = key.match(ARRAY_KEY_REGEX);
|
|
15
|
+
|
|
16
|
+
// Handle array notation like items[0]
|
|
17
|
+
if (arrayMatch) {
|
|
18
|
+
const [, arrayKey, indexStr] = arrayMatch;
|
|
19
|
+
const index = parseInt(indexStr, 10);
|
|
20
|
+
|
|
21
|
+
// Initialize array if it doesn't exist
|
|
22
|
+
if (!Array.isArray(current[arrayKey])) {
|
|
23
|
+
current[arrayKey] = [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const array = current[arrayKey] as unknown[];
|
|
27
|
+
|
|
28
|
+
// Set value and continue if this is the last key
|
|
29
|
+
if (isLastKey) {
|
|
30
|
+
array[index] = value;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Initialize nested object and move to it
|
|
35
|
+
if (!array[index] || typeof array[index] !== 'object') {
|
|
36
|
+
array[index] = {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
current = array[index] as Record<string, unknown>;
|
|
40
|
+
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Handle regular keys - set value and continue if this is the last key
|
|
45
|
+
if (isLastKey) {
|
|
46
|
+
current[key] = value;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Initialize nested object and move to it
|
|
51
|
+
if (!current[key] || typeof current[key] !== 'object' || Array.isArray(current[key])) {
|
|
52
|
+
current[key] = {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
current = current[key] as Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"outDir": "dist",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"jsx": "react-jsx"
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src/**/*"
|
|
18
|
+
],
|
|
19
|
+
"exclude": [
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist"
|
|
22
|
+
]
|
|
23
|
+
}
|