|
1 | 1 | # @sovgut/allocate |
2 | 2 |
|
3 | | -A powerful utility for transforming the keys of objects or arrays of objects according to a specified schema. This package allows you to replace keys in deeply nested structures with ease. |
| 3 | +<p align="center"> |
| 4 | + <b>A lightweight TypeScript utility for transforming object and array structures by remapping keys according to a schema. Perfect for API response transformation, data migration, and object restructuring.</b> |
| 5 | +</p> |
| 6 | + |
| 7 | +<p align="center"> |
| 8 | + <img src="https://img.shields.io/npm/v/@sovgut/allocate" alt="npm version" /> |
| 9 | + <img src="https://img.shields.io/npm/dm/@sovgut/allocate" alt="npm downloads" /> |
| 10 | + <img src="https://img.shields.io/github/license/sovgut/allocate" alt="license" /> |
| 11 | +</p> |
4 | 12 |
|
5 | 13 | ## Features |
6 | 14 |
|
7 | | -- **Key Replacement:** Easily replace keys in objects or arrays based on a schema. |
8 | | -- **Nested Structures:** Supports nested objects and arrays, even with complex paths. |
9 | | -- **Array Handling:** Seamlessly process arrays of objects, applying key replacement to each item. |
| 15 | +- 🔄 **Key Remapping**: Transform object keys based on a simple schema |
| 16 | +- 🎯 **Deep Path Support**: Navigate and transform deeply nested properties using dot notation |
| 17 | +- 📦 **Array Handling**: Process arrays of objects with special `[]` notation |
| 18 | +- 🌳 **Nested Transformations**: Handle complex nested structures with ease |
| 19 | +- 🚀 **Zero Dependencies**: Lightweight and fast |
10 | 20 |
|
11 | 21 | ## Installation |
12 | 22 |
|
13 | | -Install the package via npm: |
14 | | - |
15 | 23 | ```bash |
16 | 24 | npm install @sovgut/allocate |
17 | 25 | ``` |
18 | 26 |
|
19 | | -Or via yarn: |
20 | | - |
21 | 27 | ```bash |
22 | 28 | yarn add @sovgut/allocate |
23 | 29 | ``` |
24 | 30 |
|
25 | | -## Usage |
| 31 | +```bash |
| 32 | +pnpm add @sovgut/allocate |
| 33 | +``` |
26 | 34 |
|
27 | | -### Basic Key Replacement |
| 35 | +## Table of Contents |
28 | 36 |
|
29 | | -Replace keys in a simple object: |
| 37 | +- [Quick Start](#quick-start) |
| 38 | +- [Usage](#usage) |
| 39 | + - [Basic Example](#basic-example) |
| 40 | + - [Working with Nested Objects](#working-with-nested-objects) |
| 41 | + - [Array Transformations](#array-transformations) |
| 42 | + - [Complex Nested Arrays](#complex-nested-arrays) |
| 43 | + - [Root-Level Arrays](#root-level-arrays) |
| 44 | +- [API Reference](#api-reference) |
| 45 | +- [Important Notes](#important-notes) |
| 46 | +- [Contributing](#-contributing) |
| 47 | +- [License](#-license) |
30 | 48 |
|
31 | | -```typescript |
32 | | -import { Allocate } from '@sovgut/allocate' |
| 49 | +## Quick Start |
33 | 50 |
|
34 | | -const source = { foo: true, qux: false } |
35 | | -const schema = { foo: 'bar' } |
| 51 | +Get started with `@sovgut/allocate` in seconds: |
36 | 52 |
|
37 | | -allocate(source, schema) // { bar: true } |
| 53 | +```typescript |
| 54 | +import { allocate } from '@sovgut/allocate'; |
| 55 | + |
| 56 | +// Transform a simple object |
| 57 | +const user = { firstName: 'John', lastName: 'Doe' }; |
| 58 | +const result = allocate(user, { |
| 59 | + firstName: 'name.first', |
| 60 | + lastName: 'name.last' |
| 61 | +}); |
| 62 | +// Output: { name: { first: 'John', last: 'Doe' } } |
| 63 | + |
| 64 | +// Transform an array of objects |
| 65 | +const users = [{ id: 1, email: 'john@example.com' }]; |
| 66 | +const transformed = allocate(users, { |
| 67 | + '[].id': '[].userId', |
| 68 | + '[].email': '[].contact.email' |
| 69 | +}); |
| 70 | +// Output: [{ userId: 1, contact: { email: 'john@example.com' } }] |
38 | 71 | ``` |
39 | 72 |
|
40 | | -### Nested Key Replacement |
| 73 | +## Usage |
41 | 74 |
|
42 | | -Handle nested structures with dot notation: |
| 75 | +### Basic Example |
43 | 76 |
|
44 | 77 | ```typescript |
45 | | -import { Allocate } from '@sovgut/allocate' |
| 78 | +import { allocate } from '@sovgut/allocate'; |
| 79 | + |
| 80 | +const user = { |
| 81 | + firstName: 'John', |
| 82 | + lastName: 'Doe' |
| 83 | +}; |
46 | 84 |
|
47 | | -const source = { foo: { bar: true, baz: false } } |
48 | | -const schema = { 'foo.baz': 'bar.qux' } |
| 85 | +const schema = { |
| 86 | + firstName: 'name.first', |
| 87 | + lastName: 'name.last' |
| 88 | +}; |
49 | 89 |
|
50 | | -allocate(source, schema) // { bar: { qux: false } } |
| 90 | +const result = allocate(user, schema); |
| 91 | +// Result: { name: { first: 'John', last: 'Doe' } } |
51 | 92 | ``` |
52 | 93 |
|
53 | | -### Array of Objects |
| 94 | +### Working with Nested Objects |
54 | 95 |
|
55 | | -Apply key replacement to each object in an array: |
| 96 | +Use dot notation to access and transform nested properties: |
56 | 97 |
|
57 | 98 | ```typescript |
58 | | -import { Allocate } from '@sovgut/allocate' |
59 | | - |
60 | | -const source = [{ foo: true }, { foo: true, bar: 123 }] |
61 | | -const schema = { '[].foo': '[].bar' } |
62 | | - |
63 | | -allocate(source, schema) // [{ bar: true }, { bar: true }] |
| 99 | +const data = { |
| 100 | + user: { |
| 101 | + details: { |
| 102 | + email: 'john@example.com', |
| 103 | + phone: '123-456-7890' |
| 104 | + } |
| 105 | + } |
| 106 | +}; |
| 107 | + |
| 108 | +const schema = { |
| 109 | + 'user.details.email': 'contact.email', |
| 110 | + 'user.details.phone': 'contact.phone' |
| 111 | +}; |
| 112 | + |
| 113 | +const result = allocate(data, schema); |
| 114 | +// Result: { |
| 115 | +// contact: { email: 'john@example.com', phone: '123-456-7890' }, |
| 116 | +// user: { details: {} } |
| 117 | +// } |
64 | 118 | ``` |
65 | 119 |
|
66 | | -### Complex Nested Structures |
| 120 | +### Array Transformations |
67 | 121 |
|
68 | | -Work with deeply nested arrays and objects: |
| 122 | +Transform arrays of objects using the `[]` notation: |
69 | 123 |
|
70 | 124 | ```typescript |
71 | | -import { allocate } from '@sovgut/allocate' |
| 125 | +const data = { |
| 126 | + users: [ |
| 127 | + { id: 1, name: 'John' }, |
| 128 | + { id: 2, name: 'Jane' } |
| 129 | + ] |
| 130 | +}; |
| 131 | + |
| 132 | +const schema = { |
| 133 | + 'users[].id': 'people[].userId', |
| 134 | + 'users[].name': 'people[].fullName' |
| 135 | +}; |
| 136 | + |
| 137 | +const result = allocate(data, schema); |
| 138 | +// Result: { |
| 139 | +// people: [ |
| 140 | +// { userId: 1, fullName: 'John' }, |
| 141 | +// { userId: 2, fullName: 'Jane' } |
| 142 | +// ], |
| 143 | +// users: [{}, {}] |
| 144 | +// } |
| 145 | +``` |
| 146 | + |
| 147 | +### Complex Nested Arrays |
72 | 148 |
|
73 | | -const source = { foo: { bar: [{ baz: true }, { baz: true }] } } |
74 | | -const schema = { 'foo.bar[].baz': 'foo.bar[].qux' } |
| 149 | +Handle deeply nested array structures: |
75 | 150 |
|
76 | | -allocate(source, schema) // { foo: { bar: [{ qux: true }, { qux: true }] } } |
| 151 | +```typescript |
| 152 | +const data = { |
| 153 | + departments: [ |
| 154 | + { |
| 155 | + name: 'Engineering', |
| 156 | + teams: [ |
| 157 | + { id: 1, lead: 'Alice' }, |
| 158 | + { id: 2, lead: 'Bob' } |
| 159 | + ] |
| 160 | + } |
| 161 | + ] |
| 162 | +}; |
| 163 | + |
| 164 | +const schema = { |
| 165 | + 'departments[].teams[].lead': 'departments[].teams[].manager' |
| 166 | +}; |
| 167 | + |
| 168 | +const result = allocate(data, schema); |
| 169 | +// Result: { |
| 170 | +// departments: [{ |
| 171 | +// name: 'Engineering', |
| 172 | +// teams: [ |
| 173 | +// { id: 1, manager: 'Alice' }, |
| 174 | +// { id: 2, manager: 'Bob' } |
| 175 | +// ] |
| 176 | +// }] |
| 177 | +// } |
77 | 178 | ``` |
78 | 179 |
|
79 | | -## API |
| 180 | +### Root-Level Arrays |
| 181 | + |
| 182 | +Transform arrays at the root level: |
80 | 183 |
|
81 | 184 | ```typescript |
82 | | -/** |
83 | | - * Transforms the keys of an object or an array of objects according to a specified schema. |
84 | | - * |
85 | | - * The `allocate` function takes a source object (or array of objects) and a schema that defines |
86 | | - * how the keys in the source should be transformed. It returns a new object (or array) with |
87 | | - * the keys replaced as specified by the schema. |
88 | | - * |
89 | | - * @template TResult - The type of the resulting object or array after key allocation. |
90 | | - * @param {NonNullable<object | object[]>} source - The source object or array to be transformed. It must be a non-null object or array of objects. |
91 | | - * @param {AllocateSchema} schema - An object where each key-value pair defines the mapping from the old key to the new key. |
92 | | - * @returns {TResult} - The transformed object or array with the keys replaced according to the schema. |
93 | | - * |
94 | | - * @throws {TypeError} Throws an error if the schema is not an object or if the source is not an object or an array. |
95 | | - */ |
96 | | -export declare function allocate<TResult>(source: NonNullable<object | object[]>, schema: AllocateSchema): TResult |
97 | | - |
98 | | -/** |
99 | | - * A map of key-value pairs that define how to replace keys in the source. |
100 | | - * |
101 | | - * The keys of this record represent the current keys in the source object, |
102 | | - * and the values represent the required keys that will replace them in the allocated object. |
103 | | - * |
104 | | - * @type {Record<string, string>} |
105 | | - */ |
106 | | -export declare type AllocateSchema = Record<string, string> |
| 185 | +const users = [ |
| 186 | + { firstName: 'John', age: 30 }, |
| 187 | + { firstName: 'Jane', age: 25 } |
| 188 | +]; |
| 189 | + |
| 190 | +const schema = { |
| 191 | + '[].firstName': '[].name', |
| 192 | + '[].age': '[].years' |
| 193 | +}; |
| 194 | + |
| 195 | +const result = allocate(users, schema); |
| 196 | +// Result: [ |
| 197 | +// { name: 'John', years: 30 }, |
| 198 | +// { name: 'Jane', years: 25 } |
| 199 | +// ] |
107 | 200 | ``` |
108 | 201 |
|
109 | | -#### Parameters: |
110 | | -- `source`: The source object or array of objects to be transformed. |
111 | | -- `schema`: An object defining the mapping between old keys and new keys. Use dot notation for nested keys and `*` to indicate array elements. |
| 202 | +## API Reference |
| 203 | + |
| 204 | +### `allocate(source, schema)` |
| 205 | + |
| 206 | +Transforms an object or array structure according to the provided schema. |
| 207 | + |
| 208 | +#### Parameters |
| 209 | + |
| 210 | +- **source**: `T` - The source object or array to transform. Can be: |
| 211 | + - A plain object |
| 212 | + - An array of objects |
| 213 | + - `null` or `undefined` (returns as-is) |
| 214 | + |
| 215 | +- **schema**: `Record<string, string>` - A mapping of source paths to destination paths |
| 216 | + |
| 217 | +#### Returns |
| 218 | + |
| 219 | +Returns the transformed object/array with keys remapped according to the schema. The original source remains unchanged. |
| 220 | + |
| 221 | +#### Path Syntax |
| 222 | + |
| 223 | +- **Dot notation**: Access nested properties (e.g., `'user.profile.name'`) |
| 224 | +- **Array notation**: Use `[]` to indicate array iteration (e.g., `'users[].name'`) |
| 225 | +- **Combined**: Mix both notations (e.g., `'data[].items[].value'`) |
| 226 | + |
| 227 | +## Important Notes |
| 228 | + |
| 229 | +1. **Original Structure**: The function preserves parts of the original structure that aren't explicitly transformed |
| 230 | +2. **Empty Objects**: After moving properties, empty parent objects remain in the result |
| 231 | +3. **Type Preservation**: All value types are preserved during transformation |
| 232 | +4. **Non-existent Paths**: Accessing non-existent paths results in `undefined` values |
| 233 | +5. **Self-referencing**: Mapping a path to itself keeps the value in place |
| 234 | + |
| 235 | +## 🤝 Contributing |
| 236 | + |
| 237 | +If you find any issues or have suggestions for improvements, feel free to open an issue or submit a pull request on [GitHub](https://github.com/sovgut/allocate). |
| 238 | + |
| 239 | +## 📄 License |
| 240 | + |
| 241 | +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. |
112 | 242 |
|
113 | | -#### Returns: |
114 | | -- A new object or array with keys replaced according to the schema. |
| 243 | +--- |
115 | 244 |
|
116 | | -## License |
| 245 | +<p align="center"> |
| 246 | + Made with ❤️ by <a href="https://github.com/sovgut">sovgut</a> |
| 247 | +</p> |
117 | 248 |
|
118 | | -This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details. |
| 249 | +<p align="center"> |
| 250 | + <a href="https://github.com/sovgut/allocate">GitHub</a> • |
| 251 | + <a href="https://www.npmjs.com/package/@sovgut/allocate">npm</a> • |
| 252 | + <a href="#-api-reference">Documentation</a> |
| 253 | +</p> |
0 commit comments