{"id":38054485,"url":"https://github.com/dortzur/renorm","last_synced_at":"2026-01-16T20:22:06.830Z","repository":{"id":57211901,"uuid":"132369366","full_name":"dortzur/renorm","owner":"dortzur","description":"A state selector to optimize the usage of React, Redux, Reselect \u0026 Normalizr.","archived":false,"fork":false,"pushed_at":"2018-05-30T10:36:25.000Z","size":114,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-24T20:53:00.993Z","etag":null,"topics":["normalizr","react","redux","renorm","reselect"],"latest_commit_sha":null,"homepage":"","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/dortzur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-06T19:27:27.000Z","updated_at":"2022-02-03T09:13:59.000Z","dependencies_parsed_at":"2022-09-13T05:11:38.604Z","dependency_job_id":null,"html_url":"https://github.com/dortzur/renorm","commit_stats":null,"previous_names":["dortzur/denormalize-selector"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/dortzur/renorm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dortzur%2Frenorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dortzur%2Frenorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dortzur%2Frenorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dortzur%2Frenorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dortzur","download_url":"https://codeload.github.com/dortzur/renorm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dortzur%2Frenorm/sbom","scorecard":{"id":352793,"data":{"date":"2025-08-11","repo":{"name":"github.com/dortzur/renorm","commit":"131fc376f914d0d5e562b0c10d034f76bc86c86a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.8,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":2,"reason":"badge detected: InProgress","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"85 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-c6rq-rjc2-86v2","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-rq8g-5pc5-wrhr","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-vh7m-p724-62c2","Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-44pw-h2cw-w3vq","Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-4xcv-9jjx-gfj3","Warn: Project is vulnerable to: GHSA-f9cm-qmx5-m98h","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-6g33-f262-xjp4","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-mf6x-7mm4-x2g7","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T08:45:06.215Z","repository_id":57211901,"created_at":"2025-08-18T08:45:06.215Z","updated_at":"2025-08-18T08:45:06.215Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28482267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["normalizr","react","redux","renorm","reselect"],"created_at":"2026-01-16T20:22:06.724Z","updated_at":"2026-01-16T20:22:06.816Z","avatar_url":"https://github.com/dortzur.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Renorm\n\nA state selector to optimize the usage of React, Redux, Reselect \u0026 Normalizr.\n\n[![CircleCI Status](https://circleci.com/gh/dortzur/renorm.svg?style=shield\u0026circle-token=:circle-token)](https://circleci.com/gh/dortzur/renorm) [![Coverage Status](https://img.shields.io/coveralls/dortzur/renorm.svg?style=flat)](https://coveralls.io/github/dortzur/renorm?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/98cfe3ff1fc90e570820/maintainability)](https://codeclimate.com/github/dortzur/renorm/maintainability) [![minzipped size](https://img.shields.io/bundlephobia/minzip/renorm.svg?colorB=44cc11\u0026style=square)](https://bundlephobia.com/result?p=renorm) [![npm version](https://img.shields.io/npm/v/renorm.svg?style=flat-square)](https://www.npmjs.com/package/renorm) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/dortzur/renorm/blob/master/LICENSE)\n\n## Table of Contents\n\n* [Motivation](#motivation)\n* [Solution](#solution)\n* [Documentation](#documentation)\n* [Installation](#installation)\n* [Features](#features)\n* [How It Works](#how-it-works)\n  * [Memoization Strategy](#memoization-strategy)\n    * [Basic Memoization. Based on Reselect's existing defaultMemoize](#basic-memoization-based-on-reselects-existing-defaultmemoize)\n    * [Advanced Memoization](#advanced-memoization)\n* [Examples](#examples)\n  * [Basic Usage](#basic-usage)\n* [Performance](#performance)\n* [Options](#options)\n* [Dependencies](#dependencies)\n* [License](#license)\n\n## Motivation\n\nAn avoidable re-render happens when a React component receives\na shallow copy of one of it's properties, however the object didn't \"really\" change.\nMeaning A deep comparison of all of the object's primitives would find them identical.\nThis causes a React component to run it's render\nmethod needlessly, since the render result would be identical to the last one.\n\n## Solution\n\n## Documentation\n\n## Installation\n\n```shell\nyarn add renorm\n```\n\n```shell\nnpm install --save renorm\n```\n\n## Features\n\n* Discovers entities used in your selector automatically.\n* Significant performance boost when selecting a list of entities.\n* Developer friendly syntax.\n\n## How It Works\n\n`renorm(inputSelector, schema)`\nWhen you create a renorm selector this is what happens:\n\n1.  A new reselect [selectorCreator](https://github.com/reduxjs/reselect#createselectorcreatormemoize-memoizeoptions)\n    is created with the schema you provided.\n    Renorm uses a [customized version](#memoization-strategy) of Reselect's `defaultMemoize` optimized for normalizr entities.\n2.  Renorm traverses the schema you provided and saves all unique entities found.\n3.  Renorm creates an entities selector with only the relevant schema entities\n4.  Renorm now uses the Reselect selector creator from #1 which uses input, schema and relevant entities to invoke Normalizr's `denormalize` method.\n    This is the return value when invoking `renorm`\n\n### Memoization Strategy\n\nRenorm has a two phase memoization strategy\n\n#### Basic Memoization. Based on Reselect's existing `defaultMemoize`\n\n1.  Check arguments length and null check\n2.  Shallow equality of of the input ids and each one of the relevant entity maps (stocks, companies, etc.)\n    if all the checks return true the memoized version is returned, otherwise the function is invoked.\n    This the exact same process Reselect already does by default.\n\nif the function is invoked Renorm switches to advanced memoization\n\n#### Advanced Memoization\n\nFor each the denormalized object, check all underlying entities:\n\n1.  If all underlying entities are shallowly equal to the previous ones, return previous denormalized object.\n2.  Else return the denormalized object\n3.  Cache results for next run\n\nThe big advantage here is that only newly returned objects will trigger React's render.\nWithout Renorm's advanced memoization every item on the list would trigger React's render, even if you only a single entity was changed!\n\n## Examples\n\n### Basic Usage\n\n```javascript\n// schema\nimport { schema } from 'normalizr';\nconst stockSchema = new schema.Entity('stocks');\nconst companySchema = new schema.Entity('companies', {\n  stock: stockSchema,\n});\nexport const Schemas = {\n  STOCK: stockSchema,\n  STOCK_ARRAY: [stockSchema],\n  COMPANY: companySchema,\n  COMPANY_ARRAY: [companySchema],\n};\n\n// redux state\nconst state = {\n  companyIds: ['COMP_A', 'COMP_B', 'COMP_C' /*...*/],\n\n  entities: {\n    companies: {\n      /*company entities...*/\n    },\n  },\n  stocks: {\n    /*stock entities...*/\n  },\n};\n\n//renorm selector\nimport renorm from 'renorm';\nconst getCompanyIds = (state) =\u003e state.companyIds;\nconst getCompanies = renorm(getCompanyIds, Schemas.COMPANY_ARRAY);\n```\n\nFor comparison, here's the same selector without using renorm:\n\n```javascript\nimport { denormalize } from 'normalizr';\nimport { createSelector } from 'reselect';\nconst getCompanyIds = (state) =\u003e state.companyIds;\nconst getCompanyEntities = (state) =\u003e state.entities.companies;\nconst getStockEntities = (state) =\u003e state.entities.stocks;\nexport const getCompanies = createSelector(\n  getCompanyIds,\n  getCompanyEntities,\n  getStockEntities,\n  (stockList, companies, stocks) =\u003e\n    denormalize(stockList, Schemas.COMPANY_ARRAY, {\n      companies,\n      stocks,\n    })\n);\n```\n\n## Performance\n\n## Options\n\nRenorm's third parameter is an optional options object that contains the following props:\n\n| Name         | Type     | Default Value      | Description                                                           |\n| ------------ | -------- | ------------------ | --------------------------------------------------------------------- |\n| entitiesPath | string   | \"entities\"         | Path to the entities object in the state                              |\n| process      | function | (result) =\u003e result | A function to perform mutation operations before results are returned |\n\n## Dependencies\n\n* [Reselect](https://github.com/reduxjs/reselect/)\n* [Normalizr](https://github.com/paularmstrong/normalizr)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdortzur%2Frenorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdortzur%2Frenorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdortzur%2Frenorm/lists"}