{"id":24334748,"url":"https://github.com/superkalo/super-repo","last_synced_at":"2026-04-10T10:02:27.969Z","repository":{"id":57374576,"uuid":"104066833","full_name":"superKalo/super-repo","owner":"superKalo","description":"📦 Repository-ish pattern for working with and storing client-side data!","archived":false,"fork":false,"pushed_at":"2019-02-15T17:30:28.000Z","size":116,"stargazers_count":57,"open_issues_count":3,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-02-24T18:22:16.710Z","etag":null,"topics":["javascript"],"latest_commit_sha":null,"homepage":"https://css-tricks.com/importance-javascript-abstractions-working-remote-data","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/superKalo.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-09-19T11:35:10.000Z","updated_at":"2023-12-27T03:14:52.000Z","dependencies_parsed_at":"2022-08-27T11:03:05.589Z","dependency_job_id":null,"html_url":"https://github.com/superKalo/super-repo","commit_stats":null,"previous_names":["superkalo/repository"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/superKalo/super-repo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superKalo%2Fsuper-repo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superKalo%2Fsuper-repo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superKalo%2Fsuper-repo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superKalo%2Fsuper-repo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/superKalo","download_url":"https://codeload.github.com/superKalo/super-repo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/superKalo%2Fsuper-repo/sbom","scorecard":{"id":859265,"data":{"date":"2025-08-11","repo":{"name":"github.com/superKalo/super-repo","commit":"2d425ec703fbd6b5fc653e0eb955894519b8d696"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/18 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":"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":"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":"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":"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":"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":"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":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"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":"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":"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 15 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T00:46:31.649Z","repository_id":57374576,"created_at":"2025-08-24T00:46:31.649Z","updated_at":"2025-08-24T00:46:31.649Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31637748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"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":["javascript"],"created_at":"2025-01-18T04:19:21.294Z","updated_at":"2026-04-10T10:02:27.947Z","avatar_url":"https://github.com/superKalo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"https://user-images.githubusercontent.com/2548061/30693332-c07f5844-9ed7-11e7-970d-17498f7c8e62.png\" height=\"24\" alt=\"Super R\" /\u003e SuperRepo\n\nRepository-ish pattern for your data, that implements **best practices** for working with and storing data on the client-side. **Please read [my CSS-Tricks post first](https://css-tricks.com/importance-javascript-abstractions-working-remote-data/).**\n\n\u003e TL;DR: Get ready to make the way you work with and store remote data more maintainable \u0026 scalable! :dark_sunglasses: \n\n## :package: Install\n\nThis package can be installed with:\n\n- [npm](https://www.npmjs.com/package/super-repo): `npm install --save super-repo`\n- [bower](https://bower.io/search/?q=super-repo): `bower install --save super-repo`\n- ... or simply download the [latest release](https://github.com/superKalo/repository/releases).\n\n\n## :rocket: Load\n\n- Static HTML:\n\n    ```html\n    \u003cscript src=\"node_modules/super-repo/lib/index.js\"\u003e\u003c/script\u003e\n    ```\n\n- Using ES6 Imports:\n\n    ```javascript\n    // If a transpiler is configured (like Traceur Compiler, Babel, Rollup or Webpack):\n    import SuperRepo from 'super-repo';\n    ```\n\n- Using CommonJS Imports:\n    ```javascript\n    // If a module loader is configured (like RequireJS, Browserify or Neuter):\n    const SuperRepo = require('super-repo');\n    ```\n\n## :bulb: Usage\n\nLet's assume we have a weather API. It returns the temperature, feels-like, wind speed (m/s), pressure (hPa) and humidity (%). A common pattern, in order for the JSON response to be as slim as possible, attributes are compressed up to the first letter. So here’s what we receive from the server:\n\n```json\n{\n    \"t\": 31,\n    \"w\": 32,\n    \"p\": 1011,\n    \"h\": 38,\n    \"f\": 32\n}\n```\n\nNow let's define a function responsible for getting data from the server. It doesn't matter how, as long as your function returns a Promise.\n\n- You can use jQuery's `$.ajax()` (as of v1.5, jQuery implements the Promise interface):\n\n    ```javascript\n    const requestWeatherData = () =\u003e $.ajax( {url:'weather.json'} );\n    ```\n\n- ... or FetchAPI:\n\n    ```javascript\n    const requestWeatherData = () =\u003e fetch('weather.json').then(r =\u003e r.json());\n    ```\n\n- ... or plain XMLHttpRequest or whatever you want. **As long as you return a Promise it will work!**\n\nWe're ready to define our `SuperRepo`sitory:\n\n```javascript\n/**\n * 1. Define where you want to store the data, in this example, in the LocalStorage.\n *\n * 2. Then - define a name of your data repository, it's used for the LocalStorage key.\n *    Should be unique!\n *\n * 3. Define when the data will get out of date.\n *\n * 4. Define your data model and set custom attribute names for each response items.\n *    In the example, server returns the params 't', 'w', 'p',\n *    we map them to 'temperature', 'windspeed', and 'pressure' instead.\n *    Remember why? See below.\n */\nconst WeatherRepository = new SuperRepo({\n    storage: 'LOCAL_STORAGE',                   // [1]\n    name: 'weather',                            // [2]\n    outOfDateAfter: 5 * 60 * 1000, // 5 min     // [3]\n    request: requestWeatherData,                // Function that returns a Promise\n    dataModel: {                                // [4]\n        temperature: 't',\n        windspeed: 'w',\n        pressure: 'p'\n    }\n});\n\n/**\n * From here on, you can use the `.getData()` method to access your data.\n * It will first check if out data outdated (based on the `outOfDateAfter`).\n * If so - it will do a server request to get fresh data,\n * otherwise - it will get it from the cache (Local Storage).\n */\nWeatherRepository.getData().then( data =\u003e {\n    // Do something awesome.\n    console.log(`It is ${data.temperature} degrees`);\n});\n```\n\nWhy **`[4]`** this is a good idea (best practice):\n\n- Throughout your codebase via `WeatherRepository.getData()` you access meaningful and semantic attributes like `.temperature` and `.windspeed` instead of `t` and `s`.\n- You expose only parameters you need and simply don't include the others.\n- If the response attributes names change (or you need to wire-up another API with different response structure), you only need to tweak it here - in only 1 place of your codebase.\n\n## :dark_sunglasses: Features\n\nThe library brings the following benefits:\n\n- Performance:\n  - Gets data from the server (if it’s missing or outdated on our side) or otherwise - gets it from the cache.\n  - If `WeatherRepository.getData()` is called multiple times from different parts of our app, only 1 server request is triggered.\n- Scalability:\n  - Applies the data model to our rough data (see **`[4]`** above).\n  - You can store the data in the Local Storage or in the Browser (local) Storage (if you’re building a browser extension) or in a local variable (if you don't want to store data across browser sessions). See the options for the `storage` setting.\n  - You can initiate an automatic data sync with `WeatherRepository.initSyncer()`. This will initiate a setInterval, which will countdown to the point when the data is out of date (based on the `outOfDateAfter` value) and will trigger a server request to get fresh data. Sweet.\n\n... and a few more. Read the documentation for advanced usage.\n\n## :scream: Dependencies\n\nNone.\n\n## :open_book: Documentation\n\n### Options\n\n#### `name` [required]\nType: `String`\n\nName of the Repository. Should be unique! It's used for Local Storage or Browser Local Storage item name.\n\n#### `request` [required]\nType: `Function` that returns a `Promise`, that resolves to `Array` or `Object`, based on your server response :nerd_face: \n\nThe request that does the actual API call. It must be a Promise. Use FetchAPI or jQuery's $.ajax() or plain XMLHttpRequest or whatever you want, but wrap it in a Promise (if it isn't).\n    \n- You can use jQuery's `$.ajax()` (as of v1.5, jQuery implements the Promise interface):\n\n    ```javascript\n    const requestWeatherData = () =\u003e $.ajax( {url:'weather.json'} );\n    \n    const WeatherRepository = new SuperRepo({\n        /* ... */\n        request: requestWeatherData\n    });\n    ```\n\n- ... or FetchAPI:\n\n    ```javascript\n    const requestWeatherData = () =\u003e fetch('weather.json').then(r =\u003e r.json());\n    \n    const WeatherRepository = new SuperRepo({\n        /* ... */\n        request: requestWeatherData\n    });\n    ```\n\n- ... or plain XMLHttpRequest or whatever you want. **As long as you return a Promise it will work!**\n\n#### `storage` [optional]\nDefault: `'LOCAL_STORAGE'` | All options: `'LOCAL_STORAGE'`, `'BROWSER_STORAGE'` or `'LOCAL_VARIABLE'`\n\nThe preferred client-side storage.\n\n- `'LOCAL_STORAGE'`: Stores data in the [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), if you're building a web app.\n- `'BROWSER_STORAGE'`: Stores data in the [Browser (local) Storage](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/), if you're building a browser extension.\n- `'LOCAL_VARIABLE'`: Stores the data in a local `.data` variable, attached to the class instance, if you don’t want to store data across browser sessions.\n\n#### `dataModel` [optional, but recommended]\nType: `Object` or `Array`\n\nThe mapping of the attribute names you'd like to use across your codebase with the attribute names coming from the server response.\n\n- In case the server response is a single Object or an Array of Objects:\n\n  - Syntax 1: In case the server returns a single Object, you can use the following syntax:\n\n    ```javascript\n    const WeatherRepository = new SuperRepo({\n        /* ... */\n        dataModel: {\n            temperature: 't',\n            windspeed: 'w',\n            pressure: 'p'\n        }\n    });\n    ```\n\n  - Syntax 2: In case the server returns an Array of items, you can use the following syntax:\n\n    ```javascript\n    const WeatherRepository = new SuperRepo({\n        /* ... */\n        dataModel: [{\n            temperature: 't',\n            windspeed: 'w',\n            pressure: 'p'\n        }]\n    });\n    ```\n\n- In case the server response is more complex or nested a bit more, use [`mapData`](https://github.com/superKalo/super-repo#mapdata-optional) to apply your data model manually. Here's an example.\n  Let's say our Weather API response is:\n\n    ```json\n    {\n        \"current\": {\n            \"main\": {\n                \"t\": 31,\n                \"w\": 32,\n                \"h\": 38\n            },\n            \"additional\": {\n                \"f\": 32,\n                \"p\": 1011\n            }\n        }\n    }\n    ```\n\n    Here's how we handle this case:\n\n    ```javascript\n    const WeatherRepository = new SuperRepo({\n        /* ... */\n        mapData( data =\u003e {\n            return {\n                temperature: data.current.main.t,\n                windspeed: data.current.main.w,\n                pressure: data.current.additional.p\n            }\n        });\n        // ... and simply don't pass `dataModel`\n    });\n    ```\n\n#### `outOfDateAfter` [optional]\nDefault: `-1` | Type: `Number`, in milliseconds\n\nDefines when the data will get out of date.\n\n- Set to `0` if the data will always be up to date once cached.\n- Set to `-1` if the data will always be outdated when fetched. If so, probably it will make the most sense to store it in a local variable, instead of in the local storage (the default). Like so:\n    ```javascript\n    const WeatherRepository = new SuperRepo({\n        /* ... */\n        storage: 'LOCAL_VARIABLE',\n        outOfDateAfter: 0\n    });\n    ```\n\n#### `mapData` [optional]\nType: `Function`\n\nAfter the `dataModel` is applied, if you need any further manipulation data manipulation, you can hook on this method. For example, let's say the server sends the temperature in Celsius and you want to convert it to Fahrenheit:\n\n```javascript\nconst WeatherRepository = new SuperRepo({\n    /* ... */\n    dataModel: {\n        temperature: 't',\n        windspeed: 'w',\n        pressure: 'p'\n    },\n    mapData: data =\u003e {\n        // Convert to Fahrenheit\n        const temperature = (data.temperature * 1.8) + 32;\n\n        // These two stays the same\n        const { windspeed, pressure } = data;\n\n        return { temperature, windspeed, pressure };\n    }\n});\n```\n\n### Methods\n\n#### `.getData()`\nReturns: `Promise`, that resolves to `Array` or `Object`, based on your server response :nerd_face: \n\nThis is how you can access data. It triggers a server request if data is missing or invalidated or out of date. It returns the data from the cache (local storage, browser local storage or local variable) if the data is up to date.\n\n```javascript\nconst WeatherRepository = new SuperRepo({ /* ... */ });\n\nWeatherRepository.getData().then( data =\u003e {\n    // Do something.\n    console.log(`It is ${data.temperature} degrees`);\n});\n```\n\n#### `.invalidateData()`\nReturns: `Promise`,  that resolves to {Object} that has `prevData` {Object} and the `nextData` {Object}\n\nInvalidates data by setting a flag. It **doesn't delete the data from the storage**. However, the very next time when the `.getData()` method is invoked, it will directly call the server to get fresh data.\n\n```javascript\nconst WeatherRepository = new SuperRepo({ /* ... */ });\n\nWeatherRepository.invalidateData().then( _response =\u003e {\n    console.log('Previous data', _response.prevData);\n    console.log('Next data', _response.nextData);\n});\n```\n\n#### `.clearData()`\nReturns: `Promise`, that resolves to `prevData` {Object} - the previous (just deleted) data\n\nDeletes the data from the storage. Therefore, the very next time when the `.getData()` method is invoked, it will directly call the server to get fresh data.\n\n```javascript\nconst WeatherRepository = new SuperRepo({ /* ... */ });\n\nWeatherRepository.clearData().then( _prevData =\u003e {\n    console.log('Previous (just deleted data) data', _prevData);\n});\n```\n\n#### `.getDataUpToDateStatus()`\nReturns: `Promise`, that resolves to an {Object} with `isDataUpToDate` {Boolean}, `lastFetched` {TimeStamp}, `isInvalid` {Boolean} and `localData` - the currently cached data.\n\n```javascript\nconst WeatherRepository = new SuperRepo({ /* ... */ });\n\nWeatherRepository.getDataUpToDateStatus().then( _res =\u003e {\n    const { isDataUpToDate, lastFetched, isInvalid, localData } = _res;\n\n    console.log('Is data up to date?', isDataUpToDate);\n    console.log('When the data was last fetched?', lastFetched);\n    console.log('Is data marked as invalid?', isInvalid);\n    console.log('Currently cached data', localData);\n});\n```\n\n#### `.initSyncer()`\nReturns: `Void`\n\nInitiates a countdown-er to the point when the data gets out of date (based on the `outOfDateAfter` value) and triggers a (network) request to get fresh data.\n\n```javascript\nconst WeatherRepository = new SuperRepo({\n    outOfDateAfter: 5 * 60 * 1000 // 5 min\n    /* ... */\n});\n\nWeatherRepository.initSyncer();\n```\n\nThere are 3 edge cases that prevent network (performance) overhead:\n\n- if `outOfDateAfter` value is not set (default value is `-1`), it will trigger a sync on every 1 second.\n- if `outOfDateAfter` value is `0`, it will trigger a sync on every 1 second.\n- if `outOfDateAfter` value is less than `1000` (1 second), it will trigger a sync on every 1 second instead.\n\n#### `.destroySyncer()`\nReturns: `Void`\n\nDestroys the setInterval, initiated by the `.initSyncer()` method.\n\n```javascript\nconst WeatherRepository = new SuperRepo({\n    outOfDateAfter: 5 * 60 * 1000 // 5 min\n    /* ... */\n});\n\nWeatherRepository.initSyncer();\n\n// La la la la la\n\n// Do not sync anymore.\nWeatherRepository.destroySyncer();\n```\n\n\n## :tv: Browser Support\n\nSuperRepo is compiled using [Babel](https://babeljs.io/) to enable support for [ES5 browsers](http://caniuse.com/#feat=es5).\n\nAt present, we officially aim to support the last two versions of the following browsers:\n\n- Chrome\n- Firefox\n- Safari\n- Opera\n- Edge\n\nIf you need to support Internet Explorer 11 or any older browser, you need to include a polyfill like [polyfill.io](https://polyfill.io/v2/docs/) or [babel-polyfill](https://babeljs.io/docs/usage/polyfill/) that emulates a full ES2015+ environment. Make sure you import the polyfill upfront.\n\n```html\n\u003cscript src=\"https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"/node_modules/super-repo/lib/index.js\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n    const WeatherRepository = new SuperRepo({ /* ... */ });\n\u003c/script\u003e\n```\n\nEven though SuperRepo can be used in older browsers, please note that our focus will always be on the modern-ish browsers listed above.\n\n\n## :+1: Contributing\nI'm open to ideas and suggestions! If you want to contribute or simply you've caught a bug - you can either open an issue or clone the repository, tweak the `src/index.js` file and fire a Pull Request.\n\nTo install the project, first make sure you have NodeJS and NPM installed. Preferably, the latest versions, but anything not extremely old should work too. Then, simply run `npm install`.\n\nTo generate the distribution files (in the `lib/` directory), do `npm run build`.\n\nTo run the tests and generate a test report (both, as output in the CLI and as HTML in the `coverage/` directory), do `npm run test`.\n\n\u003e One little gotcha: in order for the test report to show the actual code line numbers (from `src/index.js`), rather than the code lines of the compiled one (from `src/index.js`), the test command first generates a build with a sourcemap inlined (in `lib/index.js`), then runs the actual tests and finally - undoes the changes into `lib/index.js` (`git checkout lib/index.js`).\n\u003e \n\u003e Therefore, do not wonder why in case you do any changes to the distribution file in `lib/index.js`, after running the tests - they disappear!\n\n## :zap: Projects Powered by \u003cimg src=\"https://user-images.githubusercontent.com/2548061/30693332-c07f5844-9ed7-11e7-970d-17498f7c8e62.png\" height=\"20\" alt=\"Super R\" /\u003e SuperRepo\n- [Irrationally Yours Chrome Extension](https://www.producthunt.com/posts/irrationally-yours-chrome-extension)\n- [Crypto Tab](https://crypto-tab.com)\n- [WeatherTab](https://chrome.google.com/webstore/detail/weathertab-new-tab-browse/ndmbacelaedejokjkolgipmdkblnibbo)\n- [Child Care \u0026 Before-After School Program Locator in the City of Toronto, Canada](https://www.toronto.ca/community-people/children-parenting/children-programs-activities/licensed-child-care/child-care-locator/)\n- ... want your project showcased here? Just shoot me an [e-mail](mailto://me@superkalo.com)!\n\n## :oncoming_police_car: License\nThe code and the documentation are released under the [MIT License](https://github.com/superKalo/repository/blob/master/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuperkalo%2Fsuper-repo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuperkalo%2Fsuper-repo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuperkalo%2Fsuper-repo/lists"}