-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6998fba
Showing
14 changed files
with
4,372 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
# mutant | ||
|
||
A lightweight and flexible TypeScript library for transforming data structures using declarative schemas. | ||
|
||
## Installation | ||
|
||
```bash | ||
npm install mutant | ||
``` | ||
|
||
## Features | ||
|
||
- 🚀 Transform objects from one shape to another using a simple schema | ||
- 💪 Full TypeScript support with strong type inference | ||
- 🛠️ Support for direct property mapping and custom transformation functions | ||
- 📦 Zero dependencies | ||
- 🔍 Additional context data support for complex transformations | ||
|
||
## Usage | ||
|
||
### Basic Example | ||
|
||
```typescript | ||
import { mutate } from 'mutant'; | ||
|
||
const schema = [ | ||
{ | ||
from: 'firstName', | ||
to: 'givenName' | ||
}, | ||
{ | ||
from: 'lastName', | ||
to: 'familyName' | ||
} | ||
]; | ||
|
||
const source = { | ||
firstName: 'John', | ||
lastName: 'Doe' | ||
}; | ||
|
||
const result = mutate(schema, source); | ||
// Result: { givenName: 'John', familyName: 'Doe' } | ||
``` | ||
|
||
### Custom Transformation Functions | ||
|
||
```typescript | ||
const schema = [ | ||
{ | ||
to: 'fullName', | ||
fn: ({ entity }) => `${entity.firstName} ${entity.lastName}` | ||
}, | ||
{ | ||
from: 'age', | ||
to: 'isAdult', | ||
fn: ({ entity }) => entity.age >= 18 | ||
} | ||
]; | ||
|
||
const source = { | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
age: 25 | ||
}; | ||
|
||
const result = mutate(schema, source); | ||
// Result: { fullName: 'John Doe', isAdult: true } | ||
``` | ||
|
||
### Using Extra Context | ||
|
||
```typescript | ||
const schema = [ | ||
{ | ||
to: 'greeting', | ||
fn: ({ entity, extra }) => | ||
`${extra.greeting}, ${entity.firstName}!` | ||
} | ||
]; | ||
|
||
const source = { | ||
firstName: 'John' | ||
}; | ||
|
||
const result = mutate(schema, source, { greeting: 'Hello' }); | ||
// Result: { greeting: 'Hello, John!' } | ||
``` | ||
|
||
## API Reference | ||
|
||
### `mutate<From, To, TExtra>(schema, entity, extra?)` | ||
|
||
The main function for transforming data structures. | ||
|
||
#### Parameters | ||
|
||
- `schema`: `Schema<From, To>[]` - Array of transformation rules | ||
- `entity`: `From` - Source object to transform | ||
- `extra?`: `Extra` - Optional additional context data | ||
|
||
#### Returns | ||
|
||
- `To` - Transformed object matching the target shape | ||
|
||
### Schema Types | ||
|
||
#### Direct Property Mapping | ||
```typescript | ||
{ | ||
from: keyof From; | ||
to: keyof To; | ||
} | ||
``` | ||
|
||
#### Custom Transform Function | ||
```typescript | ||
{ | ||
to: keyof To; | ||
fn: (args: MutateFnArgs<From>) => unknown; | ||
} | ||
``` | ||
|
||
#### Combined Property Mapping and Transform | ||
```typescript | ||
{ | ||
from: keyof From; | ||
to: keyof To; | ||
fn: (args: MutateFnArgs<From>) => unknown; | ||
} | ||
``` | ||
|
||
### Types | ||
|
||
#### `MutateFnArgs<From>` | ||
|
||
Arguments passed to mutation functions: | ||
|
||
```typescript | ||
interface MutateFnArgs<From> { | ||
/** Source object being mutated */ | ||
entity: From; | ||
/** Source property key if using direct property mapping */ | ||
from?: keyof From; | ||
/** Additional context data */ | ||
extra?: Extra; | ||
} | ||
``` | ||
|
||
#### `Extra` | ||
|
||
Type for additional context data: | ||
|
||
```typescript | ||
type Extra = Record<string, unknown> | ||
``` | ||
## Best Practices | ||
1. **Type Safety**: Always define your input and output types for better type inference: | ||
```typescript | ||
interface Source { | ||
firstName: string; | ||
lastName: string; | ||
} | ||
|
||
interface Target { | ||
fullName: string; | ||
} | ||
|
||
const schema: Schema<Source, Target>[] = [/*...*/]; | ||
``` | ||
|
||
2. **Immutability**: The library maintains immutability by default. Each transformation creates a new object. | ||
|
||
3. **Modular Transformations**: Break down complex transformations into smaller, reusable functions: | ||
```typescript | ||
const formatName = ({ entity }: MutateFnArgs<Source>) => | ||
`${entity.firstName} ${entity.lastName}`; | ||
|
||
const schema = [ | ||
{ | ||
to: 'fullName', | ||
fn: formatName | ||
} | ||
]; | ||
``` | ||
|
||
## License | ||
|
||
MIT | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Please feel free to submit a Pull Request. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Extra, Schema } from './types'; | ||
export * from './types'; | ||
/** | ||
* Transforms data from one shape to another using a declarative schema. | ||
* The schema defines how properties should be mapped or transformed from | ||
* the source object to create the target object. | ||
* | ||
* @typeParam From - The type of the source object | ||
* @typeParam To - The type of the target object | ||
* @typeParam TExtra - The type of any extra context data (defaults to Extra) | ||
* | ||
* @param schema - Array of transformation rules defining the mapping between source and target | ||
* @param entity - Source object to transform | ||
* @param extra - Optional additional context data available to transformation functions | ||
* | ||
* @returns A new object matching the target type specification | ||
* | ||
* @example | ||
* Basic property mapping: | ||
* ```typescript | ||
* import { mutate } from 'mutant'; | ||
* | ||
* const schema = [ | ||
* { from: 'firstName', to: 'givenName' }, | ||
* { from: 'lastName', to: 'familyName' } | ||
* ]; | ||
* | ||
* const result = mutate(schema, { | ||
* firstName: 'John', | ||
* lastName: 'Doe' | ||
* }); | ||
* // Result: { givenName: 'John', familyName: 'Doe' } | ||
* ``` | ||
* | ||
* @example | ||
* Using transformation functions: | ||
* ```typescript | ||
* import { mutate } from 'mutant'; | ||
* | ||
* const schema = [ | ||
* { | ||
* to: 'fullName', | ||
* fn: ({ entity }) => `${entity.firstName} ${entity.lastName}` | ||
* }, | ||
* { | ||
* from: 'age', | ||
* to: 'isAdult', | ||
* fn: ({ entity }) => entity.age >= 18 | ||
* } | ||
* ]; | ||
* | ||
* const result = mutate(schema, { | ||
* firstName: 'John', | ||
* lastName: 'Doe', | ||
* age: 25 | ||
* }); | ||
* // Result: { fullName: 'John Doe', isAdult: true } | ||
* ``` | ||
* | ||
* @example | ||
* Using extra context: | ||
* ```typescript | ||
* import { mutate } from 'mutant'; | ||
* | ||
* const schema = [ | ||
* { | ||
* to: 'greeting', | ||
* fn: ({ entity, extra }) => | ||
* `${extra.greeting}, ${entity.firstName}!` | ||
* } | ||
* ]; | ||
* | ||
* const result = mutate(schema, | ||
* { firstName: 'John' }, | ||
* { greeting: 'Hello' } | ||
* ); | ||
* // Result: { greeting: 'Hello, John!' } | ||
* ``` | ||
* | ||
* @throws {TypeError} If schema or entity are null/undefined | ||
* @throws {Error} If schema contains invalid transformation rules | ||
*/ | ||
export declare const mutate: <From, To, TExtra extends Extra = Extra>(schema: Schema<From, To>[], entity: From, extra?: TExtra) => To; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.mutate = void 0; | ||
__exportStar(require("./types"), exports); | ||
/** | ||
* Transforms data from one shape to another using a declarative schema. | ||
* The schema defines how properties should be mapped or transformed from | ||
* the source object to create the target object. | ||
* | ||
* @typeParam From - The type of the source object | ||
* @typeParam To - The type of the target object | ||
* @typeParam TExtra - The type of any extra context data (defaults to Extra) | ||
* | ||
* @param schema - Array of transformation rules defining the mapping between source and target | ||
* @param entity - Source object to transform | ||
* @param extra - Optional additional context data available to transformation functions | ||
* | ||
* @returns A new object matching the target type specification | ||
* | ||
* @example | ||
* Basic property mapping: | ||
* ```typescript | ||
* import { mutate } from 'mutant'; | ||
* | ||
* const schema = [ | ||
* { from: 'firstName', to: 'givenName' }, | ||
* { from: 'lastName', to: 'familyName' } | ||
* ]; | ||
* | ||
* const result = mutate(schema, { | ||
* firstName: 'John', | ||
* lastName: 'Doe' | ||
* }); | ||
* // Result: { givenName: 'John', familyName: 'Doe' } | ||
* ``` | ||
* | ||
* @example | ||
* Using transformation functions: | ||
* ```typescript | ||
* import { mutate } from 'mutant'; | ||
* | ||
* const schema = [ | ||
* { | ||
* to: 'fullName', | ||
* fn: ({ entity }) => `${entity.firstName} ${entity.lastName}` | ||
* }, | ||
* { | ||
* from: 'age', | ||
* to: 'isAdult', | ||
* fn: ({ entity }) => entity.age >= 18 | ||
* } | ||
* ]; | ||
* | ||
* const result = mutate(schema, { | ||
* firstName: 'John', | ||
* lastName: 'Doe', | ||
* age: 25 | ||
* }); | ||
* // Result: { fullName: 'John Doe', isAdult: true } | ||
* ``` | ||
* | ||
* @example | ||
* Using extra context: | ||
* ```typescript | ||
* import { mutate } from 'mutant'; | ||
* | ||
* const schema = [ | ||
* { | ||
* to: 'greeting', | ||
* fn: ({ entity, extra }) => | ||
* `${extra.greeting}, ${entity.firstName}!` | ||
* } | ||
* ]; | ||
* | ||
* const result = mutate(schema, | ||
* { firstName: 'John' }, | ||
* { greeting: 'Hello' } | ||
* ); | ||
* // Result: { greeting: 'Hello, John!' } | ||
* ``` | ||
* | ||
* @throws {TypeError} If schema or entity are null/undefined | ||
* @throws {Error} If schema contains invalid transformation rules | ||
*/ | ||
const mutate = (schema, entity, extra) => schema.reduce((acc, rule) => { | ||
const value = 'fn' in rule | ||
? rule.fn({ entity, from: 'from' in rule ? rule.from : undefined, extra }) | ||
: entity[rule.from]; | ||
return { | ||
...acc, | ||
[rule.to]: value | ||
}; | ||
}, {}); | ||
exports.mutate = mutate; |
Oops, something went wrong.