{"id":16482621,"url":"https://github.com/mfix22/morphmorph","last_synced_at":"2025-07-31T09:39:56.191Z","repository":{"id":23386486,"uuid":"98832251","full_name":"mfix22/morphmorph","owner":"mfix22","description":":scream: Isomorphic transformations. Map, transform, filter, and morph your objects","archived":false,"fork":false,"pushed_at":"2023-01-03T23:25:21.000Z","size":1830,"stargazers_count":28,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-30T07:04:43.243Z","etag":null,"topics":["filter","function-composition","functional","isomorphic","isomorphic-transformations","mapping","morph","reduce","transformations"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/morphmorph","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mfix22.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-31T00:11:11.000Z","updated_at":"2023-07-19T06:16:11.000Z","dependencies_parsed_at":"2023-01-13T23:13:39.556Z","dependency_job_id":null,"html_url":"https://github.com/mfix22/morphmorph","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mfix22/morphmorph","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mfix22%2Fmorphmorph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mfix22%2Fmorphmorph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mfix22%2Fmorphmorph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mfix22%2Fmorphmorph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mfix22","download_url":"https://codeload.github.com/mfix22/morphmorph/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mfix22%2Fmorphmorph/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268017357,"owners_count":24181669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-31T02:00:08.723Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filter","function-composition","functional","isomorphic","isomorphic-transformations","mapping","morph","reduce","transformations"],"created_at":"2024-10-11T13:11:27.778Z","updated_at":"2025-07-31T09:39:56.163Z","avatar_url":"https://github.com/mfix22.png","language":"JavaScript","readme":"# Morph Morph\n##### Isomorphic transformations. Map, transform, filter, reduce, and morph your objects\n\n[![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest)\n[![linted with XO](https://img.shields.io/badge/linted_with_-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\n## Getting Started\n```bash\n$ npm i --save morphmorph\n```\nand then\n```javascript\nconst Mapper = require('morphmorph')\n\nconst mapper = new Mapper(/* [config] */)\n\nconst old = {\n  here: {\n    there: {\n      anywhere: 'Earth'\n    }\n  }\n}\n\nconst mappings = [ 'here.there.anywhere:location' ]\n\nconst transformation = mapper.map(mappings, old)\n// -\u003e { location: 'Earth' }\n```\n\n## Creating Transformations\nEvery transformation can be represented by a mapping passed in as the first parameter\nto `mapper.map()`. Mappings can either be of type `String` or `Object`. A mapping such as `'before:after'`\nis equivalent to: `{ field: 'before:after' }`\n\n### Basic\n```javascript\nconst mappings = [\n  'before:after',\n  'egg:they.can.be.deeply.nested', // deeply nested target\n  'data.user.updated:updated'      // deeply nested source\n]\nreturn mapper.map(mappings, obj)\n```\n\n### Functions\nWhen creating a mapping, if you pass a function as the `type` parameter,\nthe function you passed will be called with the following properties to produce\nthe result:\n\n```javascript\nconst mapping = {\n  field: 'name',\n  type: function (value, mapping, options, sourceObj, targetObj) {\n    // value: the value grabbed from the source object\n    // mapping: this specific mapping\n    // options: config you specified by `new Mapper(options)`\n    // sourceObj: object you passed as mapper.map(mapping, sourceObj)\n    // targetObj: object you passed as mapper.map(m, sourceObj, targetObj). Default to `{}`\n  }\n}\n```\n\n#### Arrays\nYou can also pass an Array of functions and `MapLib` will perform a right-to-left\nfunction composition:\n```javascript\nconst mapping = {\n  field: 'id:pin',\n  type: [\n    Number,                   // called last\n    v =\u003e v.substr(0, 4)\n    v =\u003e v.replace(/\\D/g, '') // called first\n  ]\n}\n\nmapper.map([mapping], { id: 'U1234342'}) // -\u003e 1234\n```\n\n#### Function Compositions\nIf you want to do function compositions the traditional way, you can use `Mapper.compose(...myFilterFunctions)`. Again it will be a right-to-left composition.\n\n### Reductions\nBy specifying your `field` property as an array, you can reduce multiple values into a single one. The values will be included as the first parameter of your `type` function. The target field is specified by the last mapping in your array\n\n##### Example\n```javascript\nconst response = {\n  user: {\n    firstName: 'Mike',\n    lastName: 'Fix',\n    professionInfo: {\n      title: 'Mr',\n      occupation: 'Software Engineer'\n    }\n  }\n}\n\nconst mapping = {\n  field: [\n    'user.firstName',\n    'user.lastName',\n    'user.professionInfo.title',\n    'user.professionInfo.occupation',\n    'description'\n  ],\n  type: ([name1, name2, title, occ]) =\u003e\n    `${title}. ${name1} ${name2} is a ${occ}`\n}\n\nmapper.map([mapping], response).description // -\u003e 'Mr. Mike Fix is a Software Engineer'\n```\n\n### Types\nYou can specify a type system by passing in the `types` option:\n```javascript\nconst types = {\n  number: Number,\n  notNullString: v =\u003e (v || '')\n}\n\nconst mapper = new Mapper({ types })\n```\n\nand then specify which type to use as a string for each mapping:\n```javascript\nconst mappings = [\n  { field: 'haircolor', type: 'notNullString' },\n  { field: 'daysRemaining': type: 'number' }\n]\n\nreturn mapper.map(mappings, hairSubscriptionResponse)\n```\n\n**Note:** each function in the type specification is passed the same parameters as\nthe [normal type functions](#functions)\n\n## Config\nYou can pass in a config object to `Mapper` to create your own mapping system:\n##### Options\n\n| Field          | Type           | Default        |\n| :------------- | :------------- | :------------- |\n| `types`        | `Object`       | `{}`           |\n| `objDelimiter` | `String`       | `\".\"`          |\n| `mapDelimiter` | `String`       | `\":\"`          |\n| `preFilters`   | `Array`        | `[]`           |\n| `postFilters`  | `Array`        | `[]`           |\n\n##### Example\n```javascript\nconst mapper = new Mapper({\n  objDelimiter: '|',\n  mapDelimiter: '-\u003e',\n  types: { bool: Boolean },\n  preFilters: [ FILTER_NULL ],\n  postFilters: [ REMOVE_PASSWORD ]\n  // add other fields to your config here\n})\n```\n\n## Static methods\n##### `Mapper.get`\nMethod used to grab a deeply nested field from an object.\n```javascript\nconst get = Mapper.get('key'/*, delimiter */)\nconst field = get({ key: true })\n// -\u003e true\n```\n##### `Mapper.assign`\nMethod used to apply a deeply nested field to an object.\n```javascript\nconst set = Mapper.assign('user.id'/*, delimiter */)\nconst targetObject = set({}, 1)\n// -\u003e { user: { id: 1 } }\n```\n##### `Mapper.compose`\nMethod used to apply function compositions\n```javascript\nconst fun1 = v =\u003e `${v}!`\nconst fun2 = v =\u003e v.toUpperCase()\nconst fun3 = String\n\nconst exclaim = Mapper.compose(fun1, fun2, fun3)\nexclaim('hey') // -\u003e HEY!\n```\n\n## Bonus\nDependencies: None!\u003cbr\u003e\nSize: \u003c2KB gzipped\n\n## Examples\nSee [/examples](https://github.com/mfix22/morphmorph/tree/master/examples) or [`test/index.spec.js`](https://github.com/mfix22/morphmorph/tree/master/test/index.spec.js) for many examples of how to use `MorphMorph`.\n\n### Thanks\n* [Mostly Adequate Guide to Functional Programming](https://mostly-adequate.gitbooks.io/) for examples and reference implementations\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmfix22%2Fmorphmorph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmfix22%2Fmorphmorph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmfix22%2Fmorphmorph/lists"}