├── .editorconfig ├── .gitattributes ├── .gitignore ├── .gitmodules ├── .prettierrc.js ├── .vscode └── settings.json ├── README.md ├── package.json ├── packages ├── deferred │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── Deferred.ts │ │ ├── main.spec.ts │ │ └── main.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── either │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── examples │ │ └── getAuthenticatedUser │ │ │ └── getAuthenticatedUser.ts │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── Either.ts │ │ ├── Left.spec.ts │ │ ├── Left.ts │ │ ├── Right.spec.ts │ │ ├── Right.ts │ │ ├── fromFalsy.spec.ts │ │ ├── fromFalsy.ts │ │ ├── fromNullish.spec.ts │ │ ├── fromNullish.ts │ │ ├── fromPredicate.spec.ts │ │ ├── fromPredicate.ts │ │ ├── index.ts │ │ ├── isEither.spec.ts │ │ ├── isEither.ts │ │ ├── tryCatch.spec.ts │ │ └── tryCatch.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── falsy │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── main.spec.ts │ │ └── main.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── json │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── Json.spec.ts │ │ ├── Json.ts │ │ ├── ReadonlyJson.spec.ts │ │ ├── ReadonlyJson.ts │ │ ├── fromJSON.spec.ts │ │ ├── fromJSON.ts │ │ ├── main.ts │ │ ├── toJSON.spec.ts │ │ └── toJSON.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── nullish │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── main.spec.ts │ │ └── main.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── pipe │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── pipe.spec.ts │ │ └── pipe.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json └── predicate │ ├── .gitignore │ ├── .prettierrc.js │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ ├── main.spec.ts │ └── main.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts └── bump.sh ├── tsconfig.build.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Settings for editors and IDEs. 2 | # References at https://editorconfig.org/. 3 | 4 | root = true 5 | 6 | # Settings for any file. 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 2 11 | indent_style = space 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # File attributes for Git repository. 2 | # References at https://git-scm.com/docs/gitattributes. 3 | 4 | # Handle files as text and ensure Unix line endings. 5 | * text=auto eol=lf 6 | 7 | # Ignore differences on PNPM's lockfile. 8 | # Since version 5.11.0, PNPM automatically resolve its merge conflicts. 9 | pnpm-lock.yaml -diff 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js modules. 2 | node_modules/ 3 | 4 | # Log files. 5 | *.log 6 | 7 | # Finder settings files (MacOS). 8 | .DS_Store 9 | 10 | # npm's lockfiles. 11 | # We're using pnpm and it provides its own lockfile. 12 | package-lock.json 13 | npm-shrinkwrap.json 14 | 15 | # Yarn's lockfile, Plug'n'Play, folder and settings. 16 | # We're using pnpm and it provide its own lockfile and settings. 17 | yarn.lock 18 | .pnp.* 19 | .yarn/ 20 | .yarnrc 21 | .yarnrc.yaml 22 | 23 | # pnpm's lockfile. 24 | # The only allowed pnpm lockfile is the root one. 25 | **/pnpm-lock.yaml 26 | !/pnpm-lock.yaml 27 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "packages/animate"] 2 | path = packages/animate 3 | url = git@github.com:VitorLuizC/animate.git 4 | [submodule "packages/format-date"] 5 | path = packages/format-date 6 | url = git@github.com:VitorLuizC/format-date.git 7 | [submodule "packages/maybe"] 8 | path = packages/maybe 9 | url = git@github.com:VitorLuizC/maybe.git 10 | [submodule "packages/create-request"] 11 | path = packages/create-request 12 | url = git@github.com:VitorLuizC/create-request.git 13 | [submodule "packages/event-emitter"] 14 | path = packages/event-emitter 15 | url = git@github.com:VitorLuizC/event-emitter.git 16 | [submodule "packages/insist"] 17 | path = packages/insist 18 | url = git@github.com:VitorLuizC/insist.git 19 | [submodule "packages/get"] 20 | path = packages/get 21 | url = git@github.com:VitorLuizC/get.git 22 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | endOfLine: 'lf', 4 | printWidth: 80, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "packages/*/src/**/*.js": true, 4 | "packages/*/src/**/*.js.map": true, 5 | "packages/*/types/**/*.ts.map": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🗃 `@bitty` 2 | 3 | A mono-repository with functional programming helpers, algebraic data types, util functions, types and even some micro-frameworks in TypeScript. They were designed to support multiple environments (even older browsers and ESM Node.js). 4 | 5 | - 📦 Packages distributed in ESM, CommonJS, UMD and UMD _minified_ formats. 6 | 7 | - ⚡ Lightweight, tree-shakeable and side-effects free packages. 8 | 9 | - 🔋 Bateries included: 10 | 11 | - Little to none dependencies. 12 | 13 | - Almost every package work independently. 14 | 15 | ## Packages 16 | 17 | Package | Description 18 | ------- | ----------- 19 | [`@bitty/animate`](https://github.com/VitorLuizC/animate) | Create and manage animation functions with browser's AnimationFrame API. 20 | [`@bitty/create-request`](https://github.com/VitorLuizC/create-request) | Apply interceptors to `fetch` and create a custom request function. 21 | [`@bitty/deferred`](./packages/deferred/README.md) | It provides a function to create [Deferred](https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred/README.md) objects. They contain a Promise and methods to imperatively resolve or reject it. 22 | [`@bitty/either`](./packages/either/README.md) | An algebraic data type that represents a value of one of two possible types (a disjoint union). 23 | [`@bitty/event-emitter`](https://github.com/VitorLuizC/event-emitter) | Emit and listen events in any class, object or function without messing them extending classes. 24 | [`@bitty/falsy`](./packages/falsy/README.md) | Falsy helper functions and types for TypeScript. 25 | [`@bitty/format-date`](https://github.com/VitorLuizC/format-date) | A small library (around 400 B when gziped & minified) to format JavaScript `Date` object using same tokens as moment. 26 | [`@bitty/get`](https://github.com/VitorLuizC/get) | A really small and type-safe (requires TypeScript >= 4.1.3) function, that gets a nested value from an object using a path string (like "a.b[0].d"). If value is 'undefined' or unreachable returns the placeholder instead. 27 | [`@bitty/insist`](https://github.com/VitorLuizC/insist) | Insistently runs a callback and only resolves the promise when its result is truthy. 28 | [`@bitty/json`](./packages/json/README.md) | Types and type-safe functions for JSON. 29 | [`@bitty/maybe`](https://github.com/VitorLuizC/maybe) | An algebraic data type that is a container for an optional values. 30 | [`@bitty/nullish`](./packages/nullish/README.md) | Nullish helper functions and types for TypeScript. 31 | [`@bitty/pipe`](./packages/pipe/README.md) | A pipe function to perform function composition in LTR (Left-To-Right) direction. 32 | [`@bitty/predicate`](./packages/predicate/README.md) | `Predicate` and `Refinement` types for TypeScript. 33 | 34 | ## License 35 | 36 | All the packages are released under **MIT License**. 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/root", 3 | "private": true, 4 | "scripts": { 5 | "test": "pnpm --filter ./packages run test", 6 | "build": "pnpm run build -r" 7 | }, 8 | "devDependencies": { 9 | "pnpm": "^6.25.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/deferred/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/deferred/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/deferred/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/deferred/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/deferred` 2 | 3 | [![Bundle minified size](https://badgen.net/bundlephobia/min/@bitty/deferred)](https://bundlephobia.com/result?p=@bitty/deferred) 4 | [![Bundle minified and gzipped size](https://badgen.net/bundlephobia/minzip/@bitty/deferred)](https://bundlephobia.com/result?p=@bitty/deferred) 5 | 6 | It provides a function to create [Deferred](https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred) objects. They contain a Promise and methods to imperatively resolve or reject it. 7 | 8 | - 📦 Distributions in ESM, CommonJS, UMD and UMD _minified_ formats. 9 | 10 | - ⚡ Lightweight: 11 | - Weighs less than 1KB (min + gzip). 12 | - Tree-shakeable. 13 | - Side-effects free. 14 | 15 | - 🔋 Bateries included: 16 | - No dependencies. 17 | - Only requires `Promise`, but you can use a polyfill in unsupported environments. 18 | - Isn't based in other es2015+ features or APIs. 19 | 20 | - 🏷 Safe: 21 | - JSDocs and type declarations for IDEs and editor's autocomplete/intellisense. 22 | - Made with TypeScript as strict as possible. 23 | - Unit tests with AVA. 24 | 25 | ## Installation 26 | 27 | This library is published in the NPM registry and can be installed using any compatible package manager. 28 | 29 | ```sh 30 | npm install @bitty/deferred --save 31 | 32 | # For Yarn, use the command below. 33 | yarn add @bitty/deferred 34 | ``` 35 | 36 | ### Installation from CDN 37 | 38 | This module has a UMD bundle available through JSDelivr and Unpkg CDNs. 39 | 40 | ```html 41 | 42 | 43 | 44 | 45 | 46 | 47 | 60 | ``` 61 | 62 | ## Getting Stated 63 | 64 | This module default exports `createDeferred`, which is a factory function that creates `Deferred` objects. 65 | 66 | ```ts 67 | import createDeferred from '@bitty/deferred'; 68 | 69 | const deferred = createDeferred(); 70 | ``` 71 | 72 | `Deferred` objects exposes a `Promise` and methods to reject or resolve it. 73 | 74 | ```ts 75 | import createDeferred, { Deferred } from '@bitty/deferred'; 76 | 77 | let deferred: Deferred; 78 | 79 | // ... 80 | 81 | deferred.promise 82 | .then(value => console.log(`You received $ ${value.toFixed(2)}!`)) 83 | .catch(reason => console.error(`Couldn't receive because of `, reason)); 84 | 85 | deferred.resolve(10); 86 | //=> It logs "You received $ 50.00!" in the console. 87 | 88 | deferred.reject(new Error('The account number is invalid.')); 89 | //=> Won't log anything because promise is already resolved. 90 | ``` 91 | 92 | We also export the `Deferred` interface. Which simply defines the promise property (an instance of `Promise`) and the methods that change it. 93 | 94 | ```ts 95 | interface Deferred { 96 | readonly promise: Promise; 97 | reject(reason: unknown): void; 98 | resolve(value: T | PromiseLike): void; 99 | } 100 | ``` 101 | 102 | ## License 103 | 104 | Released under [MIT License](./LICENSE). 105 | -------------------------------------------------------------------------------- /packages/deferred/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/deferred", 3 | "version": "0.1.0", 4 | "description": "It provides a function to create Deferred objects. They contains a Promise and methods to imperatively resolve or reject it.", 5 | "sideEffects": false, 6 | "cdn": "./dist/main.umd.min.js", 7 | "main": "./dist/main.js", 8 | "types": "./types/main.d.ts", 9 | "unpkg": "./dist/main.umd.min.js", 10 | "module": "./dist/main.esm.js", 11 | "jsdelivr": "./dist/main.umd.min.js", 12 | "umd:main": "./dist/main.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/main.mjs", 17 | "require": "./dist/main.js", 18 | "default": "./dist/main.js" 19 | }, 20 | "./dist/main.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "deferred", 29 | "deferreds", 30 | "promise", 31 | "promises", 32 | "promises-a", 33 | "Promises/A+", 34 | "promises-aplus", 35 | "future", 36 | "futures", 37 | "resolve", 38 | "reject", 39 | "async", 40 | "asynchronous", 41 | "flow", 42 | "flow control", 43 | "typescript" 44 | ], 45 | "scripts": { 46 | "test": "pnpm run test:code-style && pnpm run test:unit", 47 | "test:transpile": "tsc --project ./tsconfig.test.json", 48 | "test:unit": "pnpm run test:transpile && ava", 49 | "test:code-style": "prettier --check \"./src/**/*.ts\"", 50 | "build": "pnpm run build:transpile && pnpm run build:bundle", 51 | "build:transpile": "tsc --project ./tsconfig.build.json", 52 | "build:bundle": "rollup --config rollup.config.js", 53 | "prepublishOnly": "pnpm run test && pnpm run build" 54 | }, 55 | "repository": { 56 | "type": "git", 57 | "url": "git+https://github.com/VitorLuizC/bitty.git", 58 | "directory": "packages/deferred" 59 | }, 60 | "author": { 61 | "url": "https://vitorluizc.github.io/", 62 | "name": "Vitor Luiz Cavalcanti", 63 | "email": "vitorluizc@outlook.com" 64 | }, 65 | "bugs": { 66 | "url": "https://github.com/VitorLuizC/bitty/issues" 67 | }, 68 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/deferred", 69 | "license": "MIT", 70 | "devDependencies": { 71 | "ava": "^4.0.1", 72 | "prettier": "^2.5.1", 73 | "rollup": "^2.63.0", 74 | "rollup-plugin-terser": "^7.0.2", 75 | "typescript": "^4.5.4" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /packages/deferred/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | 3 | /** 4 | * Creates an output options object. 5 | * @param {import('rollup').OutputOptions} options 6 | * @returns {import('rollup').OutputOptions} 7 | */ 8 | const Option = (options) => ({ 9 | exports: 'named', 10 | sourcemap: true, 11 | ...options, 12 | }); 13 | 14 | /** 15 | * An object with all configuration for `Rollup.js`. 16 | * @type {import('rollup').RollupOptions} 17 | */ 18 | const options = { 19 | input: './src/main.js', 20 | output: [ 21 | Option({ 22 | file: './dist/main.js', 23 | format: 'commonjs', 24 | }), 25 | Option({ 26 | file: './dist/main.esm.js', 27 | format: 'esm', 28 | }), 29 | Option({ 30 | file: './dist/main.mjs', 31 | format: 'esm', 32 | }), 33 | Option({ 34 | file: './dist/main.umd.js', 35 | name: 'createDeferred', 36 | format: 'umd', 37 | }), 38 | Option({ 39 | file: './dist/main.umd.min.js', 40 | name: 'createDeferred', 41 | format: 'umd', 42 | plugins: [terser()], 43 | }), 44 | ], 45 | }; 46 | 47 | export default options; 48 | -------------------------------------------------------------------------------- /packages/deferred/src/Deferred.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Based on the obsolete `Deferred` object, that came long before Promises/A+ 3 | * spec. It's an object returned by `createdDeferred` function, that provide a 4 | * new promise along with methods to change its state. 5 | * 6 | * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred|MDN} for more information. 7 | */ 8 | export default interface Deferred { 9 | readonly promise: Promise; 10 | 11 | reject(reason?: unknown): void; 12 | 13 | resolve(value: T | PromiseLike): void; 14 | } 15 | -------------------------------------------------------------------------------- /packages/deferred/src/main.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import createDeferred from './main'; 3 | 4 | test('module default exports a function', (context) => { 5 | context.is(typeof createDeferred, 'function'); 6 | }); 7 | 8 | test('createDeferred creates a Deferred object', (context) => { 9 | const deferred = createDeferred(); 10 | 11 | context.is(typeof deferred, 'object'); 12 | 13 | context.true(deferred.promise instanceof Promise); 14 | 15 | context.is(typeof deferred.reject, 'function'); 16 | 17 | context.is(typeof deferred.resolve, 'function'); 18 | }); 19 | 20 | test('deferred.reject rejects deferred promise', async (context) => { 21 | const deferred = createDeferred(); 22 | 23 | deferred.promise 24 | .then(() => { 25 | context.fail(); 26 | }) 27 | .catch((reason) => { 28 | context.deepEqual(reason, new Error('No reason')); 29 | }); 30 | 31 | deferred.reject(new Error('No reason')); 32 | }); 33 | 34 | test('deferred.resolve resolves deferred promise', async (context) => { 35 | const deferred = createDeferred(); 36 | 37 | const VALUE = Math.random(); 38 | 39 | deferred.promise 40 | .then((value) => { 41 | context.is(value, VALUE); 42 | }) 43 | .catch(() => { 44 | context.fail(); 45 | }); 46 | 47 | deferred.resolve(VALUE); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/deferred/src/main.ts: -------------------------------------------------------------------------------- 1 | import type Deferred from './Deferred.js'; 2 | 3 | export type { Deferred }; 4 | 5 | /** 6 | * Creates a `Deferred` object that provides a new promise along with methods to 7 | * change its state. 8 | * @template T 9 | * @returns {Deferred.} 10 | */ 11 | export default function createDeferred(): Deferred { 12 | let reject: (reason?: unknown) => void; 13 | let resolve: (value: T | PromiseLike) => void; 14 | 15 | return { 16 | promise: new Promise((_resolve, _reject) => { 17 | reject = _reject; 18 | resolve = _resolve; 19 | }), 20 | 21 | // reject was assigned, because Promise initialization is eager (sync). 22 | // @ts-expect-error 23 | reject, 24 | 25 | // resolve was assigned, because Promise initialization is eager (sync). 26 | // @ts-expect-error 27 | resolve, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /packages/deferred/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5", "ES2015.Promise"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/deferred/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": ["ES5", "ES2015.Promise"], 5 | "types": ["node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/deferred/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "exclude": [] 7 | } 8 | -------------------------------------------------------------------------------- /packages/either/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/either/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/either/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/either/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/either` 2 | 3 | ## Examples 4 | 5 | - [`getAuthenticatedUser`](./examples/getAuthenticatedUser/getAuthenticatedUser.ts) is a function used to get an authenticated user. Its a pretty common case and it was implemented in the way I think we should use `Either`. 6 | -------------------------------------------------------------------------------- /packages/either/examples/getAuthenticatedUser/getAuthenticatedUser.ts: -------------------------------------------------------------------------------- 1 | import * as Either from '../../'; 2 | // The import statement in your application would be: 3 | // import * as Either from '@bitty/either'; 4 | 5 | import decodeJWT from 'jwt-decode'; 6 | import isNullish from '@bitty/nullish'; 7 | 8 | // ..:: Context ::.. 9 | 10 | const BASE_URL = 'https://angularsp.com/api/1.0'; 11 | 12 | const JWT_KEY = 'JWT'; 13 | 14 | enum SignInErrorCodeEnum { 15 | JWT_NOT_FOUND = 'JWT_NOT_FOUND', 16 | JWT_INVALID = 'JWT_INVALID', 17 | JWT_EXPIRED = 'JWT_EXPIRED', 18 | CANT_GET_USER = 'CANT_GET_USER', 19 | } 20 | 21 | class SignInError extends Error { 22 | code: SignInErrorCodeEnum; 23 | 24 | constructor(code: SignInErrorCodeEnum, message = 'No message.') { 25 | super(message); 26 | this.code = code; 27 | this.name = 'JWTError'; 28 | this.message = message; 29 | } 30 | } 31 | 32 | type JWTPayload = { 33 | iat: number; 34 | exp?: null | number; 35 | userId: string; 36 | }; 37 | 38 | type User = { 39 | id: string; 40 | name: string; 41 | email: string; 42 | }; 43 | 44 | // ..:: Business rules ::.. 45 | 46 | // 1. Get persisted JWT from `window.localStorage`. 47 | // 2. With JWT, decode its payload with `jwt-decode`. 48 | // 3. With payload, check if it wasn't expired. 49 | // 4. With payload (not expired yet), get its userId. 50 | // 5. With userId, do a request to `/user`. 51 | // 6. With response, return the user. 52 | 53 | // ..:: Implementation ::.. 54 | 55 | const getAuthenticatedJWT = () => { 56 | const error = new SignInError(SignInErrorCodeEnum.JWT_NOT_FOUND); 57 | return Either.fromFalsy(error)(window.localStorage.getItem(JWT_KEY)); 58 | }; 59 | 60 | const decodeAuthenticationJWT = (token: string) => 61 | Either.tryCatch( 62 | () => decodeJWT(token), 63 | () => new SignInError(SignInErrorCodeEnum.JWT_INVALID), 64 | ); 65 | 66 | const wasNotJWTExpired = (payload: JWTPayload) => 67 | isNullish(payload.exp) || payload.exp > Date.now() / 1000; 68 | 69 | const checkJWTExpiration = Either.fromPredicate(wasNotJWTExpired, (payload) => { 70 | const date = new Date(payload.exp! * 1000); 71 | return new SignInError( 72 | SignInErrorCodeEnum.JWT_EXPIRED, 73 | `Authentication expired at ${date.toISOString()}`, 74 | ); 75 | }); 76 | 77 | const getUserById = (userId: string): Promise => 78 | fetch(BASE_URL + '/user/' + userId, { 79 | method: 'GET', 80 | headers: { 81 | Authorization: `Bearer ${window.localStorage.getItem(JWT_KEY)!}`, 82 | }, 83 | }) 84 | .then((response) => response.json()) 85 | .catch((error) => { 86 | const message = String(error?.message); 87 | return new SignInError(SignInErrorCodeEnum.CANT_GET_USER, message); 88 | }); 89 | 90 | const getAuthenticatedUser = () => 91 | getAuthenticatedJWT() 92 | .chain(decodeAuthenticationJWT) 93 | .chain(checkJWTExpiration) 94 | .map((payload) => payload.userId) 95 | .fold(Promise.reject, getUserById); 96 | 97 | export default getAuthenticatedUser; 98 | -------------------------------------------------------------------------------- /packages/either/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/either", 3 | "version": "0.2.0", 4 | "description": "Either monad implementation.", 5 | "sideEffects": false, 6 | "cdn": "./dist/Either.umd.js", 7 | "main": "./dist/Either.js", 8 | "types": "./types/index.d.ts", 9 | "unpkg": "./dist/Either.umd.js", 10 | "module": "./dist/Either.esm.js", 11 | "jsdelivr": "./dist/Either.umd.js", 12 | "umd:main": "./dist/Either.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/Either.mjs", 17 | "require": "./dist/Either.js", 18 | "default": "./dist/Either.js" 19 | }, 20 | "./dist/Either.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "fp", 29 | "functional programming", 30 | "function", 31 | "functional" 32 | ], 33 | "scripts": { 34 | "test": "pnpm run test:code-style && pnpm run test:unit", 35 | "test:code-style": "prettier --check \"./src/**/*.ts\"", 36 | "test:transpile": "tsc --project ./tsconfig.test.json", 37 | "test:unit": "pnpm run test:transpile && ava", 38 | "build": "pnpm run build:transpile && pnpm run build:bundle", 39 | "build:transpile": "tsc --project ./tsconfig.build.json", 40 | "build:bundle": "rollup --config rollup.config.js", 41 | "prepublishOnly": "pnpm run test && pnpm run build" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/VitorLuizC/bitty.git", 46 | "directory": "packages/either" 47 | }, 48 | "author": { 49 | "url": "https://vitorluizc.github.io/", 50 | "name": "Vitor Luiz Cavalcanti", 51 | "email": "vitorluizc@outlook.com" 52 | }, 53 | "bugs": { 54 | "url": "https://github.com/VitorLuizC/bitty/issues" 55 | }, 56 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/pipe", 57 | "license": "MIT", 58 | "devDependencies": { 59 | "@rollup/plugin-node-resolve": "^13.1.3", 60 | "ava": "^4.0.1", 61 | "jwt-decode": "^3.1.2", 62 | "prettier": "^2.5.1", 63 | "rollup": "^2.63.0", 64 | "rollup-plugin-terser": "^7.0.2", 65 | "typescript": "^4.5.4" 66 | }, 67 | "dependencies": { 68 | "@bitty/falsy": "workspace:*", 69 | "@bitty/nullish": "workspace:*", 70 | "@bitty/predicate": "workspace:*" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/either/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | 4 | /** 5 | * Creates an output options object. 6 | * @param {import('rollup').OutputOptions} options 7 | * @returns {import('rollup').OutputOptions} 8 | */ 9 | const Option = (options) => ({ 10 | exports: 'named', 11 | sourcemap: true, 12 | ...options, 13 | }); 14 | 15 | /** 16 | * An object with all configuration for `Rollup.js`. 17 | * @type {import('rollup').RollupOptions} 18 | */ 19 | const options = { 20 | input: './src/index.js', 21 | plugins: [resolve()], 22 | output: [ 23 | Option({ 24 | file: './dist/Either.js', 25 | format: 'commonjs', 26 | }), 27 | Option({ 28 | file: './dist/Either.esm.js', 29 | format: 'esm', 30 | }), 31 | Option({ 32 | file: './dist/Either.mjs', 33 | format: 'esm', 34 | }), 35 | Option({ 36 | file: './dist/Either.umd.js', 37 | name: 'Either', 38 | format: 'umd', 39 | }), 40 | Option({ 41 | file: './dist/Either.umd.min.js', 42 | name: 'Either', 43 | format: 'umd', 44 | plugins: [terser()], 45 | }), 46 | ], 47 | }; 48 | 49 | export default options; 50 | -------------------------------------------------------------------------------- /packages/either/src/Either.ts: -------------------------------------------------------------------------------- 1 | import type Left from './Left.js'; 2 | import type Right from './Right.js'; 3 | 4 | type Either = Left | Right; 5 | 6 | export type EitherPattern = { 7 | left: (value: L) => T; 8 | right: (value: R) => T; 9 | }; 10 | 11 | export interface EitherMethods { 12 | alt(fn: () => Either): Either; 13 | 14 | map(fn: (value: R) => R2): Either; 15 | 16 | then(fn: (value: R) => R2 | Either): Either; 17 | 18 | chain(fn: (value: R) => Either): Either; 19 | 20 | mapLeft(fn: (value: L) => L2): Either; 21 | 22 | isLeft(): this is Left; 23 | 24 | isRight(): this is Right; 25 | 26 | match(pattern: EitherPattern): T; 27 | 28 | fold(onLeft: (value: L) => T, onRight: (value: R) => T): T; 29 | 30 | orElse(fn: (value: L) => Either): Either; 31 | 32 | getOrElse(fn: (value: L) => R): R; 33 | 34 | unwrap(): L | R; 35 | } 36 | 37 | export default Either; 38 | -------------------------------------------------------------------------------- /packages/either/src/Left.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Left from './Left.js'; 3 | 4 | test('Left.unwrap returns value wrapped by `Left`', (context) => { 5 | const VALUE = Math.random(); 6 | const value = Left(VALUE); 7 | context.is(value.unwrap(), VALUE); 8 | }); 9 | 10 | test("Left.map don't apply function to the value", (context) => { 11 | let wasCalled = false; 12 | 13 | Left(null).map(() => { 14 | wasCalled = true; 15 | return null; 16 | }); 17 | 18 | context.false(wasCalled); 19 | }); 20 | 21 | test("Left.then don't apply function to the value", (context) => { 22 | let wasCalled = false; 23 | 24 | Left(null).then(() => { 25 | wasCalled = true; 26 | return null; 27 | }); 28 | 29 | context.false(wasCalled); 30 | }); 31 | 32 | test("Left.chain don't apply function to the value", (context) => { 33 | let wasCalled = false; 34 | 35 | Left(Math.random()).chain((value) => { 36 | wasCalled = true; 37 | return Left(value * 2); 38 | }); 39 | 40 | context.false(wasCalled); 41 | }); 42 | 43 | test('Left.mapLeft morphs `Left` value', (context) => { 44 | const VALUE = Math.random(); 45 | const value = Left(VALUE).mapLeft((number) => number * 2); 46 | 47 | context.is(value.unwrap(), VALUE * 2); 48 | }); 49 | 50 | test('Left.isLeft returns `true`', (context) => { 51 | context.true(Left(0).isLeft()); 52 | }); 53 | 54 | test('Left.isRight returns `false`', (context) => { 55 | context.false(Left(0).isRight()); 56 | }); 57 | 58 | test('Left.match morphs left value and return it', (context) => { 59 | const formatToMoney = (value: number) => `$ ${value.toFixed(2)}`; 60 | 61 | const money = Left(0).match({ 62 | left: formatToMoney, 63 | right: formatToMoney, 64 | }); 65 | 66 | context.is(money, '$ 0.00'); 67 | }); 68 | 69 | test('Left.match only call `left` leaf', (context) => { 70 | let leftWasCalled = false; 71 | let rightWasCalled = false; 72 | 73 | Left(0).match({ 74 | left: () => { 75 | leftWasCalled = true; 76 | }, 77 | right: () => { 78 | rightWasCalled = true; 79 | }, 80 | }); 81 | 82 | context.true(leftWasCalled); 83 | context.false(rightWasCalled); 84 | }); 85 | 86 | test('Left.fold morphs left value and return it', (context) => { 87 | const formatToMoney = (value: number) => `$ ${value.toFixed(2)}`; 88 | 89 | const money = Left(0).fold(formatToMoney, formatToMoney); 90 | 91 | context.is(money, '$ 0.00'); 92 | }); 93 | 94 | test('Left.fold only call `left` function', (context) => { 95 | let leftWasCalled = false; 96 | let rightWasCalled = false; 97 | 98 | Left(0).fold( 99 | () => { 100 | leftWasCalled = true; 101 | }, 102 | () => { 103 | rightWasCalled = true; 104 | }, 105 | ); 106 | 107 | context.true(leftWasCalled); 108 | context.false(rightWasCalled); 109 | }); 110 | 111 | test('Left.getOrElse morphs value and return it', (context) => { 112 | const value = Left(new Error('Not a valid number')).getOrElse( 113 | () => 0, 114 | ); 115 | 116 | context.is(value, 0); 117 | }); 118 | 119 | test('Left.orElse morphs value and return a new Left', (context) => { 120 | const value = Left(new TypeError('Not a valid number')).orElse( 121 | (error) => { 122 | if (error instanceof TypeError) return Left(0); 123 | return Left(NaN); 124 | }, 125 | ); 126 | 127 | context.is(value.unwrap(), 0); 128 | }); 129 | -------------------------------------------------------------------------------- /packages/either/src/Left.ts: -------------------------------------------------------------------------------- 1 | import type { EitherMethods } from './Either.js'; 2 | 3 | interface Left extends EitherMethods { 4 | _kind: 'Left'; 5 | } 6 | 7 | /** 8 | * Creates a `Left` instance that implements `Either` methods. It generally 9 | * represents an error because `Either` is right-oriented. 10 | * @param {L} value - The value used as `Left`. 11 | * @returns {Left.} 12 | * @template L 13 | */ 14 | function Left(value: L): Left { 15 | return { 16 | _kind: 'Left', 17 | alt: (fn) => fn(), 18 | map: () => Left(value), 19 | then: () => Left(value), 20 | chain: () => Left(value), 21 | mapLeft: (fn) => Left(fn(value)), 22 | isLeft: () => true, 23 | isRight: () => false, 24 | match: ({ left }) => left(value), 25 | fold: (onLeft) => onLeft(value), 26 | getOrElse: (fn) => fn(value), 27 | orElse: (fn) => fn(value), 28 | unwrap: () => value, 29 | }; 30 | } 31 | 32 | export default Left; 33 | -------------------------------------------------------------------------------- /packages/either/src/Right.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Right from './Right.js'; 3 | import Left from './Left.js'; 4 | 5 | test('Right.unwrap returns value wrapped by `Right`', (context) => { 6 | const VALUE = Math.random(); 7 | const value = Right(VALUE); 8 | context.is(value.unwrap(), VALUE); 9 | }); 10 | 11 | test('Right.map morphs wrapped value', (context) => { 12 | const VALUE = Math.random(); 13 | const value1 = Right(VALUE); 14 | const value2 = value1.map((value) => value * 2); 15 | 16 | context.is(value1.unwrap(), VALUE); 17 | context.is(value2.unwrap(), VALUE * 2); 18 | context.not(value1, value2); 19 | }); 20 | 21 | test('Right.then morphs wrapped value', (context) => { 22 | const VALUE = Math.random(); 23 | const value1 = Right(VALUE); 24 | const value2 = value1.then((value) => value * 2); 25 | 26 | context.is(value1.unwrap(), VALUE); 27 | context.is(value2.unwrap(), VALUE * 2); 28 | context.not(value1, value2); 29 | }); 30 | 31 | test('Right.then morphs wrapped value and return a new `Right`', (context) => { 32 | const VALUE = Math.random(); 33 | const value1 = Right(VALUE); 34 | const value2 = value1.then((value) => Right(value * 2)); 35 | 36 | context.is(value1.unwrap(), VALUE); 37 | context.is(value2.unwrap(), VALUE * 2); 38 | context.not(value1, value2); 39 | }); 40 | 41 | test('Right.chain morphs wrapped value and return a new `Right`', (context) => { 42 | const VALUE = Math.random(); 43 | const value1 = Right(VALUE); 44 | const value2 = value1.chain((value) => Right(value * 2)); 45 | 46 | context.is(value1.unwrap(), VALUE); 47 | context.is(value2.unwrap(), VALUE * 2); 48 | context.not(value1, value2); 49 | }); 50 | 51 | test("Right.mapLeft don't apply function to the value", (context) => { 52 | let wasCalled = false; 53 | 54 | Right(1298).mapLeft(() => { 55 | wasCalled = true; 56 | return null; 57 | }); 58 | 59 | context.false(wasCalled); 60 | }); 61 | 62 | test('Right.mapLeft returns new `Right` with same wrapped value', (context) => { 63 | const VALUE = Math.random(); 64 | 65 | const value = Right(VALUE).mapLeft(() => Math.random()); 66 | 67 | context.is(value.unwrap(), VALUE); 68 | }); 69 | 70 | test('Right.isLeft returns `false`', (context) => { 71 | context.false(Right(0).isLeft()); 72 | }); 73 | 74 | test('Right.isRight returns `true`', (context) => { 75 | context.true(Right(0).isRight()); 76 | }); 77 | 78 | test('Right.match morphs wrapped value and return it', (context) => { 79 | const formatToMoney = (value: number) => `$ ${value.toFixed(2)}`; 80 | 81 | const money = Right(100).match({ 82 | left: formatToMoney, 83 | right: formatToMoney, 84 | }); 85 | 86 | context.is(money, '$ 100.00'); 87 | }); 88 | 89 | test('Right.match only call `Right` leaf', (context) => { 90 | let leftWasCalled = false; 91 | let rightWasCalled = false; 92 | 93 | Right(0).match({ 94 | left: () => { 95 | leftWasCalled = true; 96 | }, 97 | right: () => { 98 | rightWasCalled = true; 99 | }, 100 | }); 101 | 102 | context.false(leftWasCalled); 103 | context.true(rightWasCalled); 104 | }); 105 | 106 | test('Right.fold morphs wrapped value and return it', (context) => { 107 | const formatToMoney = (value: number) => `$ ${value.toFixed(2)}`; 108 | 109 | const money = Right(100).fold(formatToMoney, formatToMoney); 110 | 111 | context.is(money, '$ 100.00'); 112 | }); 113 | 114 | test('Right.fold only call `Right` function', (context) => { 115 | let leftWasCalled = false; 116 | let rightWasCalled = false; 117 | 118 | Right(0).fold( 119 | () => { 120 | leftWasCalled = true; 121 | }, 122 | () => { 123 | rightWasCalled = true; 124 | }, 125 | ); 126 | 127 | context.false(leftWasCalled); 128 | context.true(rightWasCalled); 129 | }); 130 | 131 | test('Right.getOrElse just returns wrapped value', (context) => { 132 | const VALUE = Math.random(); 133 | const value = Right(VALUE).getOrElse(() => 0); 134 | 135 | context.is(value, VALUE); 136 | }); 137 | 138 | test("Right.orElse don't even execute the callback", (context) => { 139 | let wasCalled = false; 140 | 141 | Right(100).orElse((error) => { 142 | wasCalled = true; 143 | if (error instanceof TypeError) return Left(0); 144 | return Left(NaN); 145 | }); 146 | 147 | context.false(wasCalled); 148 | }); 149 | -------------------------------------------------------------------------------- /packages/either/src/Right.ts: -------------------------------------------------------------------------------- 1 | import type { EitherMethods } from './Either.js'; 2 | 3 | import isEither from './isEither.js'; 4 | 5 | interface Right extends EitherMethods { 6 | _kind: 'Right'; 7 | } 8 | 9 | /** 10 | * Creates a `Right` instance that implements `Either` methods. It generally 11 | * represents an successful value because `Either` is right-oriented. 12 | * @param {R} value - The value used as `Right`. 13 | * @returns {Left.<*, R>} 14 | * @template R 15 | */ 16 | function Right(value: R): Right { 17 | return { 18 | _kind: 'Right', 19 | alt: () => Right(value), 20 | map: (fn) => Right(fn(value)), 21 | then: (fn) => { 22 | const valueOrEither = fn(value); 23 | return isEither(valueOrEither) ? valueOrEither : Right(valueOrEither); 24 | }, 25 | chain: (fn) => fn(value), 26 | mapLeft: () => Right(value), 27 | isLeft: () => false, 28 | isRight: () => true, 29 | match: ({ right }) => right(value), 30 | fold: (_, onRight) => onRight(value), 31 | getOrElse: () => value, 32 | orElse: () => Right(value), 33 | unwrap: () => value, 34 | }; 35 | } 36 | 37 | export default Right; 38 | -------------------------------------------------------------------------------- /packages/either/src/fromFalsy.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | import fromFalsy from './fromFalsy.js'; 4 | 5 | test('fromFalsy returns `Left` for falsy values', (context) => { 6 | const from = fromFalsy(new Error('Not defined')); 7 | 8 | context.true(from(null).isLeft()); 9 | context.true(from(undefined).isLeft()); 10 | context.true(from(0n).isLeft()); 11 | context.true(from(-0).isLeft()); 12 | context.true(from(0).isLeft()); 13 | context.true(from('').isLeft()); 14 | context.true(from(NaN).isLeft()); 15 | context.true(from(false).isLeft()); 16 | }); 17 | 18 | test('fromFalsy returns `Right` for non-falsy values', (context) => { 19 | const name = fromFalsy(new Error('Not defined'))('Karl'); 20 | 21 | context.true(name.isRight()); 22 | }); 23 | 24 | test('fromFalsy uses default value as returned `Left` for falsy values', (context) => { 25 | const DEFAULT_VALUE = Math.random(); 26 | 27 | const fromNull = fromFalsy(DEFAULT_VALUE)(null); 28 | 29 | context.is(fromNull.unwrap(), DEFAULT_VALUE); 30 | }); 31 | 32 | test('fromFalsy uses value as returned `Right` for non-falsy values', (context) => { 33 | const VALUE = Math.random(); 34 | const value = fromFalsy(new Error('Value is not defined'))(VALUE); 35 | 36 | context.is(value.unwrap(), VALUE); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/either/src/fromFalsy.ts: -------------------------------------------------------------------------------- 1 | import type Either from './Either.js'; 2 | 3 | import isFalsy, { Falsy, NonFalsy } from '@bitty/falsy'; 4 | 5 | import Left from './Left.js'; 6 | import Right from './Right.js'; 7 | 8 | /** 9 | * Receives a default value and returns a function to create `Either` instances 10 | * from values that can be falsy (`""`, `null`, `false`, `0`, `-0`, `0n`, `NaN` 11 | * or `undefined`). If so, it returns a `Left` with the received default value, 12 | * otherwise a `Right` with non-falsy value. 13 | * @param {L} defaultValue - The value used as `Left` if value is falsy. 14 | * @returns {function(R | Falsy): Either.} 15 | * @template L, R 16 | */ 17 | export default function fromFalsy(defaultValue: L) { 18 | return (value?: Falsy | R): Either> => 19 | isFalsy(value) ? Left(defaultValue) : Right(value as NonFalsy); 20 | } 21 | -------------------------------------------------------------------------------- /packages/either/src/fromNullish.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | import fromNullish from './fromNullish.js'; 4 | 5 | test('fromNullish returns `Left` for nullish values', (context) => { 6 | const from = fromNullish(new Error('Not defined')); 7 | 8 | context.true(from().isLeft()); 9 | context.true(from(null).isLeft()); 10 | context.true(from(undefined).isLeft()); 11 | context.true(from(undefined as void).isLeft()); 12 | }); 13 | 14 | test('fromNullish returns `Right` for non-nullish values', (context) => { 15 | const name = fromNullish(new Error('Not defined'))('Karl'); 16 | 17 | context.true(name.isRight()); 18 | }); 19 | 20 | test('fromNullish uses default value as returned `Left` for nullish values', (context) => { 21 | const DEFAULT_VALUE = Math.random(); 22 | 23 | const from = fromNullish(DEFAULT_VALUE); 24 | 25 | context.is(from(null).unwrap(), DEFAULT_VALUE); 26 | context.is(from(undefined).unwrap(), DEFAULT_VALUE); 27 | }); 28 | 29 | test('fromNullish uses value as returned `Right` for non-nullish values', (context) => { 30 | const VALUE = Math.random(); 31 | const value = fromNullish(new Error('Value is not defined'))(VALUE); 32 | 33 | context.is(value.unwrap(), VALUE); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/either/src/fromNullish.ts: -------------------------------------------------------------------------------- 1 | import type Either from './Either.js'; 2 | 3 | import isNullish, { Nullish, NonNullish } from '@bitty/nullish'; 4 | 5 | import Left from './Left.js'; 6 | import Right from './Right.js'; 7 | 8 | /** 9 | * Receives a default value and returns a function to create `Either` instances 10 | * from values that can be nullish (`void`, `null` or `undefined`). If so, it 11 | * returns a `Left` with the received default value, otherwise a `Right` with 12 | * non-nullish value. 13 | * @param {L} defaultValue - The value used as `Left` if value is nullish. 14 | * @returns {function(R | Nullish): Either.} 15 | * @template L, R 16 | */ 17 | export default function fromNullish(defaultValue: L) { 18 | return (value?: Nullish | R): Either> => 19 | isNullish(value) ? Left(defaultValue) : Right(value as NonNullish); 20 | } 21 | -------------------------------------------------------------------------------- /packages/either/src/fromPredicate.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | import fromPredicate from './fromPredicate.js'; 4 | 5 | test("fromPredicate returns `Left` if value doesn't match predicate", (context) => { 6 | const validateEven = fromPredicate( 7 | (value: number) => value % 2 === 0, 8 | (value) => value, 9 | ); 10 | 11 | context.true(validateEven(1).isLeft()); 12 | }); 13 | 14 | test('fromPredicate returns `Right` if value matches predicate', (context) => { 15 | const validateEven = fromPredicate( 16 | (value: number) => value % 2 === 0, 17 | (value) => value, 18 | ); 19 | 20 | context.true(validateEven(2).isRight()); 21 | }); 22 | 23 | test('fromPredicate create value returned as `Left` with `onLeft` callback', (context) => { 24 | const VALUE = Math.random(); 25 | 26 | const getString = fromPredicate( 27 | (value: unknown) => typeof value === 'string', 28 | (value: unknown) => String(value), 29 | ); 30 | 31 | context.is(getString(VALUE).unwrap(), String(VALUE)); 32 | }); 33 | 34 | test('fromPredicate uses value as returned `Right` if value matches predicate', (context) => { 35 | const VALUE = Math.random(); 36 | const validateEven = fromPredicate( 37 | (value: number) => typeof value === 'number', 38 | (value) => value, 39 | ); 40 | 41 | context.is(validateEven(VALUE).unwrap(), VALUE); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/either/src/fromPredicate.ts: -------------------------------------------------------------------------------- 1 | import type { Predicate, Refinement } from '@bitty/predicate'; 2 | 3 | import type Either from './Either.js'; 4 | 5 | import Left from './Left.js'; 6 | import Right from './Right.js'; 7 | 8 | /** 9 | * Receives two arguments, a predicate, and the `onLeft` function, and returns a 10 | * function to create `Either` instances by checking predicate on values. If the 11 | * predicate returns true it uses the value as `Right`, otherwise it calls 12 | * `onLeft` with value and uses its result as `Left`. 13 | * @param {function(R): boolean} predicate - A predicate function. 14 | * @param {function(R): L} onLeft - A function to create value used as `Left`. 15 | * @returns {function(R): Either.} 16 | * @template L, R 17 | */ 18 | export default function fromPredicate( 19 | predicate: Refinement, 20 | onLeft: (value: R) => L, 21 | ): (value: R) => Either; 22 | export default function fromPredicate( 23 | predicate: Predicate, 24 | onLeft: (value: R) => L, 25 | ): (value: R) => Either; 26 | export default function fromPredicate(predicate: Predicate, onLeft: Function) { 27 | return (value: unknown) => 28 | predicate(value) ? Right(value) : Left(onLeft(value)); 29 | } 30 | -------------------------------------------------------------------------------- /packages/either/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { default as Either } from './Either.js'; 2 | 3 | export { default as fromFalsy } from './fromFalsy.js'; 4 | export { default as fromNullish } from './fromNullish.js'; 5 | export { default as fromPredicate } from './fromPredicate.js'; 6 | export { default as tryCatch } from './tryCatch.js'; 7 | export { default as Left } from './Left.js'; 8 | export { default as Right } from './Right.js'; 9 | -------------------------------------------------------------------------------- /packages/either/src/isEither.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | import isEither from './isEither.js'; 4 | import Left from './Left.js'; 5 | import Right from './Right.js'; 6 | 7 | test('isEither returns `true` for `Left` values', (context) => { 8 | context.true(isEither(Left(new Error('Invalid argument.')))); 9 | context.true(isEither(Left('Unknown'))); 10 | context.true(isEither(Left([]))); 11 | }); 12 | 13 | test('isEither returns `true` for `Right` values', (context) => { 14 | context.true(isEither(Right(null))); 15 | context.true(isEither(Right('Okay'))); 16 | context.true(isEither(Right([1, 2, 3]))); 17 | }); 18 | 19 | test('isEither returns `false` for any other value', (context) => { 20 | context.false(isEither(null)); 21 | context.false(isEither('Okay')); 22 | context.false(isEither({})); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/either/src/isEither.ts: -------------------------------------------------------------------------------- 1 | import type Either from './Either.js'; 2 | 3 | /** 4 | * Check if the value is an `Either`. 5 | * @param {*} value - Value that will be checked. 6 | * @returns {Boolean} 7 | */ 8 | export default function isEither( 9 | value: unknown, 10 | ): value is Either { 11 | return (value as any)?._kind === 'Left' || (value as any)?._kind === 'Right'; 12 | } 13 | -------------------------------------------------------------------------------- /packages/either/src/tryCatch.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import tryCatch from './tryCatch.js'; 3 | 4 | test('tryCatch execute function and use its return as `Right`', (context) => { 5 | const value = tryCatch( 6 | () => JSON.parse('{"name":"Karl"}'), 7 | (error) => error, 8 | ); 9 | 10 | context.deepEqual(value.unwrap(), { name: 'Karl' }); 11 | context.true(value.isRight()); 12 | }); 13 | 14 | test('tryCatch when error is thrown calls onLeft with error and returns its result as `Left`', (context) => { 15 | const value = tryCatch( 16 | () => JSON.parse('{"name":Karl}'), 17 | (error) => 18 | new Error( 19 | error instanceof Error 20 | ? error.message 21 | : typeof error === 'string' 22 | ? error 23 | : 'Unknown error message.', 24 | ), 25 | ); 26 | 27 | context.true(value.unwrap() instanceof Error); 28 | context.true(value.isLeft()); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/either/src/tryCatch.ts: -------------------------------------------------------------------------------- 1 | import type Either from './Either.js'; 2 | 3 | import Left from './Left.js'; 4 | import Right from './Right.js'; 5 | 6 | /** 7 | * Receives a function that returns a value used as `Right`, if an error is 8 | * thrown it calls `onLeft` with error and returns its result as `Left`. 9 | * @param {function(): R} fn - A function that returns the value used as `Right`. 10 | * @param {function(*): L} onLeft - A function used to transform error into the value used as `Left`. 11 | * @returns {Either.} 12 | * @template L, R 13 | */ 14 | export default function tryCatch( 15 | fn: () => R, 16 | onLeft: (error: unknown) => L, 17 | ): Either { 18 | try { 19 | return Right(fn()); 20 | } catch (error) { 21 | return Left(onLeft(error)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/either/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/either/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext" 5 | }, 6 | "include": ["./src/**/*.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/either/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "exclude": [] 7 | } 8 | -------------------------------------------------------------------------------- /packages/falsy/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/falsy/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/falsy/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/falsy/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/falsy` 2 | 3 | [![Bundle minified size](https://badgen.net/bundlephobia/min/@bitty/falsy)](https://bundlephobia.com/result?p=@bitty/falsy) 4 | [![Bundle minified and gzipped size](https://badgen.net/bundlephobia/minzip/@bitty/falsy)](https://bundlephobia.com/result?p=@bitty/falsy) 5 | 6 | Falsy helper functions and types for TypeScript. 7 | 8 | - 📦 Distributions in ESM, CommonJS, UMD and UMD _minified_ formats. 9 | 10 | - ⚡ Lightweight: 11 | - Weighs less than 0.2KB (min + gzip). 12 | - Tree-shakeable. 13 | - Side-effects free. 14 | 15 | - 🔋 Bateries included: 16 | - No dependencies. 17 | - Its not based on newer browser's APIs or es2015+ features. 18 | 19 | - 🏷 Safe: 20 | - JSDocs and type declarations for IDEs and editor's autocomplete/intellisense. 21 | - Made with TypeScript as strict as possible. 22 | - Unit tests with AVA. 23 | 24 | ## Installation 25 | 26 | This library is published in the NPM registry and can be installed using any compatible package manager. 27 | 28 | ```sh 29 | npm install @bitty/falsy --save 30 | 31 | # For Yarn, use the command below. 32 | yarn add @bitty/falsy 33 | ``` 34 | 35 | ### Installation from CDN 36 | 37 | This module has a UMD bundle available through JSDelivr and Unpkg CDNs. 38 | 39 | ```html 40 | 41 | 42 | 43 | 44 | 45 | 46 | 54 | ``` 55 | 56 | ## Getting Stated 57 | 58 | This module default exports `isFalsy`, which is a predicate function that checks if value is _falsy_. 59 | 60 | ```ts 61 | import isFalsy from '@bitty/pipe'; 62 | 63 | isFalsy(); 64 | isFalsy(null); 65 | isFalsy(undefined); 66 | isFalsy(0); 67 | isFalsy(-0); 68 | isFalsy(0n); 69 | isFalsy(NaN); 70 | isFalsy(''); 71 | isFalsy(false); 72 | //=> true 73 | 74 | isFalsy('Not empty.'); 75 | //=> false 76 | ``` 77 | 78 | We also exports `NonFalsy` and `Falsy` types. 79 | 80 | - `Falsy` is simply an union of `false`, `void`, `''`, `0`, `0n`, `null` and `undefined`, types. 81 | 82 | ```ts 83 | import { Falsy } from '@bitty/falsy'; 84 | 85 | let falsy: Falsy; 86 | falsy = false; 87 | falsy = undefined as void; 88 | falsy = ''; 89 | falsy = 0; 90 | falsy = 0n; 91 | falsy = null; 92 | falsy = undefined; 93 | 94 | falsy = 1; 95 | //=> throws "Type '1' is not assignable to type 'Falsy'.". 96 | ``` 97 | 98 | - `NonFalsy` is a type helper that removes _falsy_ types. 99 | 100 | ```ts 101 | import { NonFalsy } from '@bitty/falsy'; 102 | 103 | type Value = 0 | 1 | 2; 104 | 105 | const value: NonFalsy = 0; 106 | //=> throws "Type '0' is not assignable to type '1 | 2'.". 107 | ``` 108 | 109 | ## License 110 | 111 | Released under [MIT License](./LICENSE). 112 | -------------------------------------------------------------------------------- /packages/falsy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/falsy", 3 | "version": "0.2.0", 4 | "description": "Falsy helper functions and types for TypeScript.", 5 | "sideEffects": false, 6 | "cdn": "./dist/main.umd.js", 7 | "main": "./dist/main.js", 8 | "types": "./types/main.d.ts", 9 | "unpkg": "./dist/main.umd.js", 10 | "module": "./dist/main.esm.js", 11 | "jsdelivr": "./dist/main.umd.js", 12 | "umd:main": "./dist/main.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/main.mjs", 17 | "require": "./dist/main.js", 18 | "default": "./dist/main.js" 19 | }, 20 | "./dist/main.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "falsy", 29 | "falsey", 30 | "false", 31 | "non-falsy", 32 | "non-falsey", 33 | "predicate", 34 | "type", 35 | "types", 36 | "type-guard", 37 | "type-predicate", 38 | "type-helper", 39 | "typescript", 40 | "typescript-types", 41 | "fp", 42 | "functional programming", 43 | "function", 44 | "functional" 45 | ], 46 | "scripts": { 47 | "test": "pnpm run test:code-style && pnpm run test:unit", 48 | "test:transpile": "tsc --project ./tsconfig.test.json", 49 | "test:unit": "pnpm run test:transpile && ava", 50 | "test:code-style": "prettier --check \"./src/**/*.ts\"", 51 | "build": "pnpm run build:transpile && pnpm run build:bundle", 52 | "build:transpile": "tsc --project ./tsconfig.build.json", 53 | "build:bundle": "rollup --config rollup.config.js", 54 | "prepublishOnly": "pnpm run test && pnpm run build" 55 | }, 56 | "repository": { 57 | "type": "git", 58 | "url": "git+https://github.com/VitorLuizC/bitty.git", 59 | "directory": "packages/falsy" 60 | }, 61 | "author": { 62 | "url": "https://vitorluizc.github.io/", 63 | "name": "Vitor Luiz Cavalcanti", 64 | "email": "vitorluizc@outlook.com" 65 | }, 66 | "bugs": { 67 | "url": "https://github.com/VitorLuizC/bitty/issues" 68 | }, 69 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/falsy", 70 | "license": "MIT", 71 | "devDependencies": { 72 | "ava": "^4.0.1", 73 | "prettier": "^2.5.1", 74 | "rollup": "^2.63.0", 75 | "rollup-plugin-terser": "^7.0.2", 76 | "typescript": "^4.5.4" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/falsy/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | 3 | /** 4 | * Creates an output options object. 5 | * @param {import('rollup').OutputOptions} options 6 | * @returns {import('rollup').OutputOptions} 7 | */ 8 | const Option = (options) => ({ 9 | exports: 'named', 10 | sourcemap: true, 11 | ...options, 12 | }); 13 | 14 | /** 15 | * An object with all configuration for `Rollup.js`. 16 | * @type {import('rollup').RollupOptions} 17 | */ 18 | const options = { 19 | input: './src/main.js', 20 | output: [ 21 | Option({ 22 | file: './dist/main.js', 23 | format: 'commonjs', 24 | }), 25 | Option({ 26 | file: './dist/main.esm.js', 27 | format: 'esm', 28 | }), 29 | Option({ 30 | file: './dist/main.mjs', 31 | format: 'esm', 32 | }), 33 | Option({ 34 | file: './dist/main.umd.js', 35 | name: 'isNullish', 36 | format: 'umd', 37 | }), 38 | Option({ 39 | file: './dist/main.umd.min.js', 40 | name: 'isNullish', 41 | format: 'umd', 42 | plugins: [terser()], 43 | }), 44 | ], 45 | }; 46 | 47 | export default options; 48 | -------------------------------------------------------------------------------- /packages/falsy/src/main.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import isFalsy, { Falsy, NonFalsy } from './main.js'; 3 | 4 | test('isFalsy returns `true` for falsy values', (context) => { 5 | context.true(isFalsy()); 6 | context.true(isFalsy(null)); 7 | context.true(isFalsy(undefined)); 8 | context.true(isFalsy(0)); 9 | context.true(isFalsy(-0)); 10 | context.true(isFalsy(0n)); 11 | context.true(isFalsy(NaN)); 12 | context.true(isFalsy('')); 13 | context.true(isFalsy(false)); 14 | }); 15 | 16 | test('isFalsy returns `false` for non-falsy values', (context) => { 17 | context.false(isFalsy([])); 18 | context.false(isFalsy({})); 19 | context.false(isFalsy('Oi')); 20 | context.false(isFalsy(10)); 21 | context.false(isFalsy(true)); 22 | context.false(isFalsy(Infinity)); 23 | context.false(isFalsy(0.1)); 24 | context.false(isFalsy(-1n)); 25 | }); 26 | 27 | test('Falsy type is an union of falsy types', (context) => { 28 | type Assert = A extends B ? true : false; 29 | 30 | const value01: Assert<0, Falsy> = true; 31 | const value02: Assert<0n, Falsy> = true; 32 | const value03: Assert<-0, Falsy> = true; 33 | const value04: Assert<'', Falsy> = true; 34 | const value05: Assert = true; 35 | const value06: Assert = true; 36 | const value07: Assert = true; 37 | const value08: Assert = true; 38 | 39 | context.true(value01); 40 | context.true(value02); 41 | context.true(value03); 42 | context.true(value04); 43 | context.true(value05); 44 | context.true(value06); 45 | context.true(value07); 46 | context.true(value08); 47 | }); 48 | 49 | test('NonFalsy type excludes falsy types', (context) => { 50 | type Assert = A extends B ? true : false; 51 | 52 | const value01: Assert<1 | 2 | 3, NonFalsy<0 | 1 | 2 | 3>> = true; 53 | const value02: Assert> = true; 54 | 55 | context.true(value01); 56 | context.true(value02); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/falsy/src/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Union of values that is considered false when converted to `Boolean`. 3 | * @see {@link https://developer.mozilla.org/en-US/docs/Glossary/Falsy}. 4 | * @typedef {false | void | '' | 0 | 0n | null | undefined} Falsy 5 | */ 6 | 7 | /** 8 | * Union of values that is considered false when converted to `Boolean`. 9 | * @see {@link https://developer.mozilla.org/en-US/docs/Glossary/Falsy}. 10 | */ 11 | export type Falsy = false | void | '' | 0 | 0n | null | undefined; 12 | 13 | /** 14 | * Exclude falsy types (`false`, `void`, `''`, `0`, `0n`, `null` & `undefined`). 15 | */ 16 | export type NonFalsy = T extends Falsy ? never : T; 17 | 18 | /** 19 | * Check if value is falsy (`""`, `null`, `false`, `0`, `NaN` or `undefined`). 20 | * @param {*} value - The value that will be checked. 21 | * @returns {Boolean} 22 | */ 23 | export default function isFalsy(value?: unknown): value is Falsy { 24 | return !value; 25 | } 26 | -------------------------------------------------------------------------------- /packages/falsy/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/falsy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/falsy/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "exclude": [] 7 | } 8 | -------------------------------------------------------------------------------- /packages/json/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/json/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/json/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/json/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/json` 2 | 3 | [![Bundle minified size](https://badgen.net/bundlephobia/min/@bitty/json)](https://bundlephobia.com/result?p=@bitty/json) 4 | [![Bundle minified and gzipped size](https://badgen.net/bundlephobia/minzip/@bitty/json)](https://bundlephobia.com/result?p=@bitty/json) 5 | 6 | Types and type-safe functions for JSON. 7 | 8 | - 📦 Distributions in ESM, CommonJS, UMD and UMD _minified_ formats. 9 | 10 | - ⚡ Lightweight: 11 | - Weighs less than 0.2KB (min + gzip). 12 | - Tree-shakeable. 13 | - Side-effects free. 14 | 15 | - 🔋 Batteries included: 16 | - No dependencies. 17 | - Its not based on newer browser's APIs or es2015+ features. 18 | 19 | - 🏷 Safe: 20 | - JSDocs and type declarations for IDEs and editor's autocomplete/intellisense. 21 | - Made with TypeScript as strict as possible. 22 | - Unit tests with AVA (types was also tested). 23 | 24 | ## Installation 25 | 26 | This library is published in the NPM registry and can be installed using any compatible package manager. 27 | 28 | ```sh 29 | npm install @bitty/json --save 30 | 31 | # For Yarn, use the command below. 32 | yarn add @bitty/json 33 | ``` 34 | 35 | ### Installation from CDN 36 | 37 | This module has a UMD bundle available through JSDelivr and Unpkg CDNs. 38 | 39 | ```html 40 | 41 | 42 | 43 | 44 | 45 | 46 | 54 | ``` 55 | 56 | ## Getting Stated 57 | 58 | This module named exports functions and types to type-safely handle JSON. 59 | 60 | ```ts 61 | import { JsonObject, toJson } from '@bitty/json'; 62 | 63 | const sendJson = (obj: T) => { 64 | const json = toJson(obj); 65 | // ... 66 | }; 67 | 68 | sendJson<{ names: Set }>({ ... }); 69 | //=> ❌ Type 'Set' is not assignable to type 'Json'. 70 | 71 | sendJson<{ names: string[] }>({ ... }); 72 | //=> ✅ 73 | ``` 74 | 75 | ## API 76 | 77 | #### `JsonArray` 78 | 79 | An array of `Json` values. 80 | 81 | ```ts 82 | import { JsonArray } from '@bitty/json'; 83 | 84 | const answers: JsonArray = [false, 'Okay', null, { color: '#fff' }, [0,3]]; 85 | ``` 86 | 87 | #### `JsonObject` 88 | 89 | An object whose property keys are strings and values are `Json` values. 90 | 91 | ```ts 92 | import { JsonObject } from '@bitty/json'; 93 | 94 | const response: JsonObject = { 95 | id: 36, 96 | association: null, 97 | colors: [{color: '#00f'}, {color: '#d7a'}], 98 | isDisabled: true 99 | }; 100 | ``` 101 | 102 | #### `Json` 103 | 104 | A union of `null`, `boolean`, `number`, `string`, `JsonArray` and `JsonObject` types. 105 | 106 | ```ts 107 | import { Json } from '@bitty/json'; 108 | 109 | const response: Json = { 110 | latest: undefined, // ❌ Type 'undefined' is not assignable to type 'Json'. 111 | current: [ 112 | { 113 | name: 'Orange', 114 | color: '#ff8721', 115 | score: 2871, 116 | disabled: true, 117 | } 118 | ] 119 | }; 120 | ``` 121 | 122 | #### `parseJson` 123 | 124 | Converts a valid JSON string into a value, whose type that extends `Json`. 125 | 126 | ```ts 127 | import { parseJson } from '@bitty/json'; 128 | 129 | type User = { 130 | name: string; 131 | }; 132 | 133 | const user = parseJson('{"name":"Carlos Marcos"}'); 134 | ``` 135 | 136 | #### `toJson` 137 | 138 | Converts a value, whose type extends `Json`, to value to JSON string. 139 | 140 | ```ts 141 | import { toJson } from '@bitty/json'; 142 | 143 | type User = { 144 | name: string; 145 | }; 146 | 147 | const user = toJson({ 148 | name: 'Carlos Marcos' 149 | }, 0); 150 | //=> "{\"name\":\"Carlos Marcos\"}" 151 | ``` 152 | 153 | ## License 154 | 155 | Released under [MIT License](./LICENSE). 156 | -------------------------------------------------------------------------------- /packages/json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/json", 3 | "version": "0.2.0", 4 | "description": "Types and type-safe functions for JSON.", 5 | "sideEffects": false, 6 | "cdn": "./dist/json.umd.js", 7 | "main": "./dist/json.js", 8 | "types": "./types/main.d.ts", 9 | "unpkg": "./dist/json.umd.js", 10 | "module": "./dist/json.esm.js", 11 | "jsdelivr": "./dist/json.umd.js", 12 | "umd:main": "./dist/json.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/json.mjs", 17 | "require": "./dist/json.js", 18 | "default": "./dist/json.js" 19 | }, 20 | "./dist/json.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "json", 29 | "json-types", 30 | "types", 31 | "json-typescript", 32 | "typescript-json", 33 | "typescript", 34 | "type-safe", 35 | "type-safe-json", 36 | "json-parse", 37 | "fp", 38 | "functional programming", 39 | "function", 40 | "functional" 41 | ], 42 | "scripts": { 43 | "test": "pnpm run lint && pnpm run test:unit", 44 | "lint": "prettier --check \"./src/**/*.ts\"", 45 | "lint:fix": "prettier --write \"./src/**/*.ts\"", 46 | "test:transpile": "tsc --project ./tsconfig.test.json", 47 | "test:unit": "pnpm run test:transpile && ava", 48 | "build": "pnpm run build:transpile && pnpm run build:bundle", 49 | "build:transpile": "tsc --project ./tsconfig.build.json", 50 | "build:bundle": "rollup --config rollup.config.js", 51 | "prepublishOnly": "pnpm run test && pnpm run build" 52 | }, 53 | "repository": { 54 | "type": "git", 55 | "url": "git+https://github.com/VitorLuizC/bitty.git", 56 | "directory": "packages/json" 57 | }, 58 | "author": { 59 | "url": "https://vitorluizc.github.io/", 60 | "name": "Vitor Luiz Cavalcanti", 61 | "email": "vitorluizc@outlook.com" 62 | }, 63 | "bugs": { 64 | "url": "https://github.com/VitorLuizC/bitty/issues" 65 | }, 66 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/pipe", 67 | "license": "MIT", 68 | "devDependencies": { 69 | "ava": "^4.0.1", 70 | "prettier": "^2.5.1", 71 | "rollup": "^2.63.0", 72 | "rollup-plugin-terser": "^7.0.2", 73 | "typescript": "^4.5.4" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/json/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | 3 | /** 4 | * Creates an output options object. 5 | * @param {import('rollup').OutputOptions} options 6 | * @returns {import('rollup').OutputOptions} 7 | */ 8 | const Option = (options) => ({ 9 | exports: 'named', 10 | sourcemap: true, 11 | ...options, 12 | }); 13 | 14 | /** 15 | * An object with all configuration for `Rollup.js`. 16 | * @type {import('rollup').RollupOptions} 17 | */ 18 | const options = { 19 | input: './src/main.js', 20 | output: [ 21 | Option({ 22 | file: './dist/json.js', 23 | format: 'commonjs', 24 | }), 25 | Option({ 26 | file: './dist/json.esm.js', 27 | format: 'esm', 28 | }), 29 | Option({ 30 | file: './dist/json.mjs', 31 | format: 'esm', 32 | }), 33 | Option({ 34 | file: './dist/json.umd.js', 35 | name: 'Json', 36 | format: 'umd', 37 | }), 38 | Option({ 39 | file: './dist/json.umd.min.js', 40 | name: 'Json', 41 | format: 'umd', 42 | plugins: [terser()], 43 | }), 44 | ], 45 | }; 46 | 47 | export default options; 48 | -------------------------------------------------------------------------------- /packages/json/src/Json.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import type { Json, JsonArray, JsonObject, JsonPrimitive } from './Json.js'; 3 | 4 | type Assert = T extends Expected ? true : false; 5 | 6 | test("Json matches 'JsonPrimitive', 'JsonArray' and 'JsonObject'", (context) => { 7 | const valid_00: Assert = true; 8 | const valid_01: Assert = true; 9 | const valid_02: Assert = true; 10 | const valid_03: Assert = true; 11 | const valid_04: Assert = true; 12 | const valid_05: Assert<1917, Json> = true; 13 | const valid_06: Assert = true; 14 | const valid_07: Assert<'JSON is better than XML', Json> = true; 15 | const valid_08: Assert = true; 16 | const valid_09: Assert<['JSON', 1999, boolean[]], Json> = true; 17 | const valid_10: Assert = true; 18 | const valid_11: Assert< 19 | { 20 | name: string; 21 | stats: { 22 | A: number; 23 | }; 24 | records: null | string[]; 25 | }, 26 | Json 27 | > = true; 28 | 29 | context.true(valid_00); 30 | context.true(valid_01); 31 | context.true(valid_02); 32 | context.true(valid_03); 33 | context.true(valid_04); 34 | context.true(valid_05); 35 | context.true(valid_06); 36 | context.true(valid_07); 37 | context.true(valid_08); 38 | context.true(valid_09); 39 | context.true(valid_10); 40 | context.true(valid_11); 41 | }); 42 | 43 | test("Json doesn't match invalid JSON types", (context) => { 44 | const valid_1: Assert = false; 45 | const valid_2: Assert = false; 46 | const valid_3: Assert = false; 47 | const valid_4: Assert, Json> = false; 48 | const valid_5: Assert = false; 49 | const valid_6: Assert<() => void, Json> = false; 50 | 51 | context.false(valid_1); 52 | context.false(valid_2); 53 | context.false(valid_3); 54 | context.false(valid_4); 55 | context.false(valid_5); 56 | context.false(valid_6); 57 | }); 58 | 59 | test('JsonArray matches an array of primitive JSON types', (context) => { 60 | const valid: Assert<(null | number | string | boolean)[], JsonArray> = true; 61 | 62 | context.true(valid); 63 | }); 64 | 65 | test("JsonArray doesn't match arrays of non-JSON types", (context) => { 66 | const valid_0: Assert = false; 67 | const valid_1: Assert = false; 68 | const valid_2: Assert<(number | undefined)[], JsonArray> = false; 69 | 70 | context.false(valid_0); 71 | context.false(valid_1); 72 | context.false(valid_2); 73 | }); 74 | 75 | test("JsonArray doesn't match non array", (context) => { 76 | const valid: Assert = false; 77 | 78 | context.false(valid); 79 | }); 80 | 81 | test('JsonObject matches an object with primitive JSON types', (context) => { 82 | const valid: Assert< 83 | { 84 | name: null | string; 85 | email: string; 86 | createdAt: number; 87 | isDisabled: boolean; 88 | }, 89 | JsonObject 90 | > = true; 91 | 92 | context.true(valid); 93 | }); 94 | 95 | test("JsonObject doesn't match objects of non-JSON types", (context) => { 96 | const valid_0: Assert<{ value: bigint }, JsonObject> = false; 97 | const valid_1: Assert<{ id: symbol }, JsonObject> = false; 98 | const valid_2: Assert<{ name?: string }[], JsonObject> = false; 99 | 100 | context.false(valid_0); 101 | context.false(valid_1); 102 | context.false(valid_2); 103 | }); 104 | 105 | test("JsonObject doesn't match non object", (context) => { 106 | const valid: Assert = false; 107 | 108 | context.false(valid); 109 | }); 110 | 111 | test("JsonPrimitive matches 'null'", (context) => { 112 | const valid: Assert = true; 113 | 114 | context.true(valid); 115 | }); 116 | 117 | test("JsonPrimitive matches 'boolean' and its sub-types", (context) => { 118 | const valid_0: Assert = true; 119 | const valid_1: Assert = true; 120 | const valid_2: Assert = true; 121 | 122 | context.true(valid_0); 123 | context.true(valid_1); 124 | context.true(valid_2); 125 | }); 126 | 127 | test("JsonPrimitive matches 'number' and its sub-types", (context) => { 128 | const valid_0: Assert = true; 129 | const valid_1: Assert<1917, JsonPrimitive> = true; 130 | 131 | context.true(valid_0); 132 | context.true(valid_1); 133 | }); 134 | 135 | test("JsonPrimitive matches 'string' and its sub-types", (context) => { 136 | const valid_0: Assert = true; 137 | const valid_1: Assert<'JSON is better than XML', JsonPrimitive> = true; 138 | 139 | context.true(valid_0); 140 | context.true(valid_1); 141 | }); 142 | 143 | test("JsonPrimitive doesn't match 'undefined' and its sub-type 'void'", (context) => { 144 | const valid_0: Assert = false; 145 | const valid_1: Assert = false; 146 | 147 | context.false(valid_0); 148 | context.false(valid_1); 149 | }); 150 | 151 | test("JsonPrimitive doesn't match 'bigint' and its sub-types", (context) => { 152 | const valid_0: Assert = false; 153 | const valid_1: Assert<9999999999999999999999n, JsonPrimitive> = false; 154 | 155 | context.false(valid_0); 156 | context.false(valid_1); 157 | }); 158 | 159 | test("JsonPrimitive doesn't match 'symbol'", (context) => { 160 | const valid: Assert = false; 161 | 162 | context.false(valid); 163 | }); 164 | -------------------------------------------------------------------------------- /packages/json/src/Json.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An union between primitive types (`null`, `boolean`, `number` and `string`) supported by JSON. 3 | */ 4 | type JsonPrimitive = null | boolean | number | string; 5 | 6 | /** 7 | * An union between {@link JsonPrimitive}, {@link JsonArray} and {@link JsonObject}. 8 | */ 9 | type Json = JsonPrimitive | JsonArray | JsonObject; 10 | 11 | /** 12 | * An array of {@link Json} elements. 13 | */ 14 | type JsonArray = Json[]; 15 | 16 | /** 17 | * An object whose property keys are strings and values are {@link Json}. 18 | */ 19 | type JsonObject = { 20 | [key: string]: Json; 21 | }; 22 | 23 | export type { Json, JsonArray, JsonObject, JsonPrimitive }; 24 | -------------------------------------------------------------------------------- /packages/json/src/ReadonlyJson.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import type { Json, JsonArray, JsonObject, JsonPrimitive } from './Json.js'; 3 | import type { 4 | ReadonlyJson, 5 | ReadonlyJsonArray, 6 | ReadonlyJsonObject, 7 | } from './ReadonlyJson.js'; 8 | 9 | type Assert = T extends Expected ? true : false; 10 | 11 | test("ReadonlyJson matches 'Json'", (context) => { 12 | const valid: Assert = true; 13 | 14 | context.true(valid); 15 | }); 16 | 17 | test('ReadonlyJson defines a read-only JSON type', (context) => { 18 | const user: ReadonlyJson = { 19 | name: 'Vitor', 20 | items: [ 21 | { 22 | name: 'Magic Long Sword', 23 | }, 24 | ], 25 | }; 26 | 27 | // @ts-expect-error 28 | user.name = 'William'; 29 | 30 | // @ts-expect-error 31 | delete user.items[0]; 32 | 33 | // @ts-expect-error 34 | user.items.push({ 35 | name: 'Magic Hat', 36 | }); 37 | 38 | context.pass(); 39 | }); 40 | 41 | test("ReadonlyJson matches 'PrimitiveJson', 'ReadonlyJsonArray' and 'ReadonlyJsonObject'", (context) => { 42 | const valid_0: Assert = true; 43 | const valid_1: Assert = true; 44 | const valid_2: Assert = true; 45 | 46 | context.true(valid_0); 47 | context.true(valid_1); 48 | context.true(valid_2); 49 | }); 50 | 51 | test("ReadonlyJsonArray matches 'JsonArray'", (context) => { 52 | const valid: Assert = true; 53 | 54 | context.true(valid); 55 | }); 56 | 57 | test('ReadonlyJsonArray defines a read-only JSON array', (context) => { 58 | const items: ReadonlyJsonArray = [ 59 | { 60 | name: 'Magic Long Sword', 61 | }, 62 | ]; 63 | 64 | // @ts-expect-error 65 | items.splice(0); 66 | 67 | // @ts-expect-error 68 | items.push({ 69 | name: 'Axe', 70 | }); 71 | 72 | context.pass(); 73 | }); 74 | 75 | test("ReadonlyJsonObject matches 'JsonObject'", (context) => { 76 | const valid: Assert = true; 77 | 78 | context.true(valid); 79 | }); 80 | 81 | test('ReadonlyJsonObject defines a read-only JSON object', (context) => { 82 | const user: ReadonlyJsonObject = { 83 | name: 'Lord Haxz', 84 | level: 9, 85 | }; 86 | 87 | // @ts-expect-error 88 | user.level = 99; 89 | 90 | // @ts-expect-error 91 | delete user.name; 92 | 93 | context.pass(); 94 | }); 95 | -------------------------------------------------------------------------------- /packages/json/src/ReadonlyJson.ts: -------------------------------------------------------------------------------- 1 | import type { JsonPrimitive } from './Json'; 2 | 3 | /** 4 | * An union between {@link JsonPrimitive}, {@link ReadonlyJsonArray} and {@link ReadonlyJsonObject}. 5 | */ 6 | type ReadonlyJson = JsonPrimitive | ReadonlyJsonArray | ReadonlyJsonObject; 7 | 8 | /** 9 | * A read-only array with {@link ReadonlyJson} elements. 10 | */ 11 | type ReadonlyJsonArray = readonly ReadonlyJson[]; 12 | 13 | /** 14 | * An object with read-only properties whose keys are strings and values are {@link ReadonlyJson}. 15 | */ 16 | type ReadonlyJsonObject = { 17 | readonly [key: string]: ReadonlyJson; 18 | }; 19 | 20 | export type { ReadonlyJson, ReadonlyJsonArray, ReadonlyJsonObject }; 21 | -------------------------------------------------------------------------------- /packages/json/src/fromJSON.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import fromJSON from './fromJSON.js'; 3 | 4 | test("fromJSON parses JSON string to 'Json'", (context) => { 5 | const expected = { 6 | name: 'Santos Dumont', 7 | }; 8 | 9 | context.deepEqual( 10 | fromJSON<{ name: string }>('{ "name": "Santos Dumont" }'), 11 | expected, 12 | ); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/json/src/fromJSON.ts: -------------------------------------------------------------------------------- 1 | import type { Json } from './Json.js'; 2 | 3 | /** 4 | * Transforms (parses) a JSON string to {@link Json} value. 5 | * @example 6 | * ```ts 7 | * type User = { 8 | * name: string; 9 | * }; 10 | * 11 | * const user = fromJSON('{"name":"Carlos Marcos"}'); 12 | * //=> { name: 'Carlos Marcos' } 13 | * ``` 14 | * @param json - The JSON string. 15 | */ 16 | function fromJSON(json: string): T { 17 | return JSON.parse(json); 18 | } 19 | 20 | export default fromJSON; 21 | -------------------------------------------------------------------------------- /packages/json/src/main.ts: -------------------------------------------------------------------------------- 1 | export * from './Json.js'; 2 | export * from './ReadonlyJson.js'; 3 | export { default as fromJSON } from './fromJSON.js'; 4 | export { default as toJSON } from './toJSON.js'; 5 | -------------------------------------------------------------------------------- /packages/json/src/toJSON.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import toJSON from './toJSON.js'; 3 | 4 | test('toJSON transforms Json value to JSON string', (context) => { 5 | type User = { 6 | name: string; 7 | }; 8 | 9 | const user: User = { 10 | name: 'Santos Dumont', 11 | }; 12 | 13 | context.is(toJSON(user, 0), `{"name":"Santos Dumont"}`); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/json/src/toJSON.ts: -------------------------------------------------------------------------------- 1 | import type { ReadonlyJson } from './ReadonlyJson.js'; 2 | 3 | /** 4 | * Transforms a {@link Json} value to JSON string. 5 | * @example 6 | * ```ts 7 | * type User = { 8 | * name: string; 9 | * }; 10 | * 11 | * const user: User = { 12 | * name: 'Karl Marx', 13 | * }; 14 | * 15 | * toJson(user, 0); 16 | * //=> '{"name":"Karl Marx"}' 17 | * ``` 18 | * @param value - A {@link ReadonlyJson} value, usually an object or array. 19 | * @param space - A character or the number of spaces used for indentation. 20 | */ 21 | function toJSON(value: ReadonlyJson, space: string | number = 2): string { 22 | return JSON.stringify(value, null, space); 23 | } 24 | 25 | export default toJSON; 26 | -------------------------------------------------------------------------------- /packages/json/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/json/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": ["ESNext"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/json/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | // Transpile output settings 5 | "module": "CommonJS", 6 | "target": "ESNext", 7 | 8 | // Type declaration settings 9 | "declaration": false 10 | }, 11 | "include": ["./test/**/*.spec.ts", "./src"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/nullish/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/nullish/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/nullish/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/nullish/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/nullish` 2 | 3 | [![Bundle minified size](https://badgen.net/bundlephobia/min/@bitty/nullish)](https://bundlephobia.com/result?p=@bitty/nullish) 4 | [![Bundle minified and gzipped size](https://badgen.net/bundlephobia/minzip/@bitty/nullish)](https://bundlephobia.com/result?p=@bitty/nullish) 5 | 6 | Nullish helper functions and types for TypeScript. 7 | 8 | - 📦 Distributions in ESM, CommonJS, UMD and UMD _minified_ formats. 9 | 10 | - ⚡ Lightweight: 11 | - Weighs less than 0.2KB (min + gzip). 12 | - Tree-shakeable. 13 | - Side-effects free. 14 | 15 | - 🔋 Bateries included: 16 | - No dependencies. 17 | - Its not based on newer browser's APIs or es2015+ features. 18 | 19 | - 🏷 Safe: 20 | - JSDocs and type declarations for IDEs and editor's autocomplete/intellisense. 21 | - Made with TypeScript as strict as possible. 22 | - Unit tests with AVA. 23 | 24 | ## Installation 25 | 26 | This library is published in the NPM registry and can be installed using any compatible package manager. 27 | 28 | ```sh 29 | npm install @bitty/nullish --save 30 | 31 | # For Yarn, use the command below. 32 | yarn add @bitty/nullish 33 | ``` 34 | 35 | ### Installation from CDN 36 | 37 | This module has a UMD bundle available through JSDelivr and Unpkg CDNs. 38 | 39 | ```html 40 | 41 | 42 | 43 | 44 | 45 | 46 | 54 | ``` 55 | 56 | ## Getting Stated 57 | 58 | This module default exports `isNullish`, which is a predicate function that checks if value is _nullish_. 59 | 60 | ```ts 61 | import isNullish from '@bitty/pipe'; 62 | 63 | isNullish(null); 64 | //=> true 65 | 66 | isNullish(undefined); 67 | //=> true 68 | 69 | isNullish(undefined as void); 70 | //=> true 71 | 72 | isNullish(NaN); 73 | //=> false 74 | ``` 75 | 76 | We also exports `NonNullish` and `Nullish` types. 77 | 78 | - `Nullish` is simply an union of `null`, `void` and `undefined` types. 79 | 80 | ```ts 81 | import { Nullish } from '@bitty/nullish'; 82 | 83 | let nullish: Nullish; 84 | nullish = null; 85 | nullish = undefined; 86 | nullish = undefined as void; 87 | 88 | nullish = false; 89 | //=> throws "Type 'false' is not assignable to type 'Nullish'.". 90 | ``` 91 | 92 | - `NonNullish` is a type helper that removes _nullish_ types. 93 | 94 | ```ts 95 | import { NonNullish } from '@bitty/nullish'; 96 | 97 | type Value = string | null | undefined; 98 | 99 | const value: NonNullish = null; 100 | //=> throws "Type 'null' is not assignable to type 'string'.". 101 | ``` 102 | 103 | ## License 104 | 105 | Released under [MIT License](./LICENSE). 106 | -------------------------------------------------------------------------------- /packages/nullish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/nullish", 3 | "version": "0.2.0", 4 | "description": "Nullish helper functions and types for TypeScript.", 5 | "sideEffects": false, 6 | "cdn": "./dist/main.umd.min.js", 7 | "main": "./dist/main.js", 8 | "types": "./types/main.d.ts", 9 | "unpkg": "./dist/main.umd.min.js", 10 | "module": "./dist/main.esm.js", 11 | "jsdelivr": "./dist/main.umd.min.js", 12 | "umd:main": "./dist/main.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/main.mjs", 17 | "require": "./dist/main.js", 18 | "default": "./dist/main.js" 19 | }, 20 | "./dist/main.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "null", 29 | "undefined", 30 | "nully", 31 | "nullable", 32 | "non-nullable", 33 | "predicate", 34 | "type", 35 | "types", 36 | "type-guard", 37 | "type-predicate", 38 | "type-helper", 39 | "typescript", 40 | "typescript-types", 41 | "fp", 42 | "functional programming", 43 | "function", 44 | "functional" 45 | ], 46 | "scripts": { 47 | "test": "pnpm run test:code-style && pnpm run test:unit", 48 | "test:transpile": "tsc --project ./tsconfig.test.json", 49 | "test:unit": "pnpm run test:transpile && ava", 50 | "test:code-style": "prettier --check \"./src/**/*.ts\"", 51 | "build": "pnpm run build:transpile && pnpm run build:bundle", 52 | "build:transpile": "tsc --project ./tsconfig.build.json", 53 | "build:bundle": "rollup --config rollup.config.js", 54 | "prepublishOnly": "pnpm run test && pnpm run build" 55 | }, 56 | "repository": { 57 | "type": "git", 58 | "url": "git+https://github.com/VitorLuizC/bitty.git", 59 | "directory": "packages/nullish" 60 | }, 61 | "author": { 62 | "url": "https://vitorluizc.github.io/", 63 | "name": "Vitor Luiz Cavalcanti", 64 | "email": "vitorluizc@outlook.com" 65 | }, 66 | "bugs": { 67 | "url": "https://github.com/VitorLuizC/bitty/issues" 68 | }, 69 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/pipe", 70 | "license": "MIT", 71 | "devDependencies": { 72 | "ava": "^4.0.1", 73 | "prettier": "^2.5.1", 74 | "rollup": "^2.63.0", 75 | "rollup-plugin-terser": "^7.0.2", 76 | "typescript": "^4.5.4" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/nullish/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | 3 | /** 4 | * Creates an output options object. 5 | * @param {import('rollup').OutputOptions} options 6 | * @returns {import('rollup').OutputOptions} 7 | */ 8 | const Option = (options) => ({ 9 | exports: 'named', 10 | sourcemap: true, 11 | ...options, 12 | }); 13 | 14 | /** 15 | * An object with all configuration for `Rollup.js`. 16 | * @type {import('rollup').RollupOptions} 17 | */ 18 | const options = { 19 | input: './src/main.js', 20 | output: [ 21 | Option({ 22 | file: './dist/main.js', 23 | format: 'commonjs', 24 | }), 25 | Option({ 26 | file: './dist/main.esm.js', 27 | format: 'esm', 28 | }), 29 | Option({ 30 | file: './dist/main.mjs', 31 | format: 'esm', 32 | }), 33 | Option({ 34 | file: './dist/main.umd.js', 35 | name: 'isNullish', 36 | format: 'umd', 37 | }), 38 | Option({ 39 | file: './dist/main.umd.min.js', 40 | name: 'isNullish', 41 | format: 'umd', 42 | plugins: [terser()], 43 | }), 44 | ], 45 | }; 46 | 47 | export default options; 48 | -------------------------------------------------------------------------------- /packages/nullish/src/main.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import isNullish from './main.js'; 3 | 4 | test('isNullish returns `true` for nullish values', (context) => { 5 | context.true(isNullish()); 6 | context.true(isNullish(null)); 7 | context.true(isNullish(undefined)); 8 | }); 9 | 10 | test('isNullish returns `false` for non-nullish value', (context) => { 11 | context.false(isNullish('Okay')); 12 | context.false(isNullish({ name: 'Karl Marx' })); 13 | context.false(isNullish(true)); 14 | context.false(isNullish(1917)); 15 | }); 16 | 17 | test('isNullish returns `false` even for falsy non-nullish values', (context) => { 18 | context.false(isNullish('')); 19 | context.false(isNullish(NaN)); 20 | context.false(isNullish(false)); 21 | context.false(isNullish(0)); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/nullish/src/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Nullish is an union of `void`, `null` and `undefined` types. 3 | */ 4 | export type Nullish = void | null | undefined; 5 | 6 | /** 7 | * Exclude nullish types (`void`, `null` and `undefined`) from T. 8 | */ 9 | export type NonNullish = T extends Nullish ? never : T; 10 | 11 | /** 12 | * Check if value is nullish (`void`, `null` or `undefined`). 13 | * @param {*} value - Value that will be checked. 14 | * @returns {Boolean} 15 | */ 16 | export default function isNullish(value?: unknown): value is Nullish { 17 | return value == null; 18 | } 19 | -------------------------------------------------------------------------------- /packages/nullish/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/nullish/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/nullish/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "exclude": [] 7 | } 8 | -------------------------------------------------------------------------------- /packages/pipe/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/pipe/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/pipe/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/pipe/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/pipe` 2 | 3 | [![Bundle minified size](https://badgen.net/bundlephobia/min/@bitty/pipe)](https://bundlephobia.com/result?p=@bitty/pipe) 4 | [![Bundle minified and gzipped size](https://badgen.net/bundlephobia/minzip/@bitty/pipe)](https://bundlephobia.com/result?p=@bitty/pipe) 5 | 6 | A pipe function to perform function composition in LTR (Left-To-Right) direction. 7 | 8 | - 📦 Distributions in ESM, CommonJS, UMD and UMD _minified_ formats. 9 | 10 | - ⚡ Lightweight: 11 | - Weighs less than 0.3KB (min + gzip). 12 | - 3x smaller than `ramda.pipe`. 13 | - Tree-shakeable. 14 | - Side-effects free. 15 | 16 | - 🔋 Bateries included: 17 | - No dependencies. 18 | - Its not based on newer browser's APIs or es2015+ features. 19 | 20 | - 🏷 Safe: 21 | - JSDocs and type declarations for IDEs and editor's autocomplete/intellisense. 22 | - Made with TypeScript as strict as possible. 23 | - Unit tests with AVA. 24 | 25 | ## Installation 26 | 27 | This library is published in the NPM registry and can be installed using any compatible package manager. 28 | 29 | ```sh 30 | npm install @bitty/pipe --save 31 | 32 | # For Yarn, use the command below. 33 | yarn add @bitty/pipe 34 | ``` 35 | 36 | ### Installation from CDN 37 | 38 | This module has a UMD bundle available through JSDelivr and Unpkg CDNs. 39 | 40 | ```html 41 | 42 | 43 | 44 | 45 | 46 | 47 | 52 | ``` 53 | 54 | ## Getting Started 55 | 56 | Import `pipe` from package and just compose your functions with it. 57 | 58 | ```ts 59 | import pipe from '@bitty/pipe'; 60 | 61 | const resolveToNumber = pipe( 62 | (value: unknown) => typeof value === 'number' ? value : parseFloat(value), 63 | (value: number) => Number.isNaN(value) ? 0 : value, 64 | ); 65 | 66 | resolveToNumber('12389'); 67 | //=> 12389 68 | ``` 69 | 70 | The first pipe argument is an arity N function, so you can receive more than one argument in the composition. 71 | 72 | ```ts 73 | import pipe from '@bitty/pipe'; 74 | 75 | const fromTextToWords = (text: string, wordsToIgnore: string[] = []) => 76 | text 77 | .trim() 78 | .split(/\s+/) 79 | .filter((word) => !wordsToIgnore.includes(word)); 80 | 81 | const formatToInitials = pipe( 82 | fromTextToWords, 83 | (words) => words.map((word) => word.charAt(0)), 84 | (initials) => initials.join('').toUpperCase(), 85 | ); 86 | 87 | formatToInitials('abraão william de santana ', ['de']); 88 | //=> "AWS" 89 | ``` 90 | 91 | ## License 92 | 93 | Released under [MIT License](./LICENSE). 94 | -------------------------------------------------------------------------------- /packages/pipe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/pipe", 3 | "version": "0.3.0", 4 | "description": "A pipe function to perform function composition in LTR (Left To Right) direction.", 5 | "sideEffects": false, 6 | "cdn": "./dist/pipe.umd.js", 7 | "main": "./dist/pipe.js", 8 | "types": "./types/pipe.d.ts", 9 | "unpkg": "./dist/pipe.umd.js", 10 | "module": "./dist/pipe.esm.js", 11 | "jsdelivr": "./dist/pipe.umd.js", 12 | "umd:main": "./dist/pipe.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/pipe.mjs", 17 | "require": "./dist/pipe.js", 18 | "default": "./dist/pipe.js" 19 | }, 20 | "./dist/pipe.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "pipe", 29 | "compose", 30 | "composition", 31 | "flow", 32 | "pipeline", 33 | "fp", 34 | "functional programming", 35 | "chain", 36 | "function", 37 | "functional", 38 | "serial" 39 | ], 40 | "scripts": { 41 | "test": "pnpm run test:code-style && pnpm run test:unit", 42 | "test:transpile": "tsc --project ./tsconfig.test.json", 43 | "test:unit": "pnpm run test:transpile && ava", 44 | "test:code-style": "prettier --check \"./{src,test}/**/*.ts\"", 45 | "build": "pnpm run build:transpile && pnpm run build:bundle", 46 | "build:transpile": "tsc --project ./tsconfig.build.json", 47 | "build:bundle": "rollup --config rollup.config.js", 48 | "prepublishOnly": "pnpm run test && pnpm run build" 49 | }, 50 | "repository": { 51 | "type": "git", 52 | "url": "git+https://github.com/VitorLuizC/bitty.git", 53 | "directory": "packages/pipe" 54 | }, 55 | "author": { 56 | "url": "https://vitorluizc.github.io/", 57 | "name": "Vitor Luiz Cavalcanti", 58 | "email": "vitorluizc@outlook.com" 59 | }, 60 | "bugs": { 61 | "url": "https://github.com/VitorLuizC/bitty/issues" 62 | }, 63 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/pipe", 64 | "license": "MIT", 65 | "devDependencies": { 66 | "ava": "^4.0.1", 67 | "prettier": "^2.5.1", 68 | "rollup": "^2.63.0", 69 | "rollup-plugin-terser": "^7.0.2", 70 | "typescript": "^4.5.4" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/pipe/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | 3 | /** 4 | * Creates an output options object. 5 | * @param {import('rollup').OutputOptions} options 6 | * @returns {import('rollup').OutputOptions} 7 | */ 8 | const Option = (options) => ({ 9 | exports: 'default', 10 | sourcemap: true, 11 | ...options, 12 | }); 13 | 14 | /** 15 | * An object with all configuration for `Rollup.js`. 16 | * @type {import('rollup').RollupOptions} 17 | */ 18 | const options = { 19 | input: './src/pipe.js', 20 | output: [ 21 | Option({ 22 | file: './dist/pipe.js', 23 | format: 'commonjs', 24 | }), 25 | Option({ 26 | file: './dist/pipe.esm.js', 27 | format: 'esm', 28 | }), 29 | Option({ 30 | file: './dist/pipe.mjs', 31 | format: 'esm', 32 | }), 33 | Option({ 34 | file: './dist/pipe.umd.js', 35 | name: 'pipe', 36 | format: 'umd', 37 | }), 38 | Option({ 39 | file: './dist/pipe.umd.min.js', 40 | name: 'pipe', 41 | format: 'umd', 42 | plugins: [terser()], 43 | }), 44 | ], 45 | }; 46 | 47 | export default options; 48 | -------------------------------------------------------------------------------- /packages/pipe/src/pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import pipe from './pipe.js'; 3 | 4 | test('pipe is a function', (context) => { 5 | context.is(typeof pipe, 'function'); 6 | }); 7 | 8 | test('pipe compose functions in LTR direction', (context) => { 9 | const add = (x: number) => (y: number) => y + x; 10 | const subtract = (x: number) => (y: number) => y - x; 11 | const multiply = (x: number) => (y: number) => y * x; 12 | const divide = (x: number) => (y: number) => y / x; 13 | 14 | const calc = pipe(add(5), subtract(2), multiply(3), divide(2)); 15 | 16 | context.is(calc(2), 7.5); 17 | context.not(calc(2), 6); 18 | }); 19 | 20 | test("pipe's first function can handle more than one argument", (context) => { 21 | const getNames = (name: string, wordsToBeIgnored: string[] = []) => 22 | name.split(' ').filter((word) => wordsToBeIgnored.indexOf(word) === -1); 23 | 24 | const formatToInitials = pipe( 25 | getNames, 26 | (names) => names.map((name) => name.charAt(0)), 27 | (initials) => initials.join('').toUpperCase(), 28 | ); 29 | 30 | context.is(formatToInitials('Jairo de Almeida Machado', ['de']), 'JAM'); 31 | }); 32 | -------------------------------------------------------------------------------- /packages/pipe/src/pipe.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Performs function composition in LTR (Left To Right) direction. 3 | * 4 | * Our `pipe` implementation supports N arguments. But you can use only 10 in 5 | * TypeScript, because it doesn't support **Variadic Kinds** and we explicitly 6 | * have to define the type of all the possible usages as method overloads. 7 | * 8 | * @example 9 | * const normalizeWhiteSpaces = text => name.replace(/\s+/g, ' ').trim(); 10 | * 11 | * const getInitials = pipe( 12 | * normalizeWhiteSpaces, 13 | * name => name.split(' ').map(name => name.charAt(0)), 14 | * initials => initials.join('').toLocaleUpperCase() 15 | * ); 16 | * 17 | * getInitials('Vitor Luiz Cavalcanti'); 18 | * //=> "VLC" 19 | * 20 | * @param fn - An arity N function. Its result is the argument of next one. 21 | * @param fns - Functions of arity 1. Each one's result is next's argument. 22 | */ 23 | // prettier-ignore 24 | export default function pipe(...fns: [(...xs: Args) => T0]): (...xs: Args) => T0; 25 | // prettier-ignore 26 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1]): (...xs: Args) => T1; 27 | // prettier-ignore 28 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2]): (...xs: Args) => T2; 29 | // prettier-ignore 30 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3]): (...xs: Args) => T3; 31 | // prettier-ignore 32 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3, (x: T3) => T4]): (...xs: Args) => T4; 33 | // prettier-ignore 34 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3, (x: T3) => T4, (x: T4) => T5]): (...xs: Args) => T5; 35 | // prettier-ignore 36 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3, (x: T3) => T4, (x: T4) => T5, (x: T5) => T6]): (...xs: Args) => T6; 37 | // prettier-ignore 38 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3, (x: T3) => T4, (x: T4) => T5, (x: T5) => T6, (x: T6) => T7]): (...xs: Args) => T7; 39 | // prettier-ignore 40 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3, (x: T3) => T4, (x: T4) => T5, (x: T5) => T6, (x: T6) => T7, (x: T7) => T8]): (...xs: Args) => T8; 41 | // prettier-ignore 42 | export default function pipe(...fns: [(...xs: Args) => T0, (x: T0) => T1, (x: T1) => T2, (x: T2) => T3, (x: T3) => T4, (x: T4) => T5, (x: T5) => T6, (x: T6) => T7, (x: T7) => T8, (x: T8) => T9]): (...xs: Args) => T9; 43 | 44 | /** 45 | * Performs function composition in LTR (Left To Right) direction. 46 | * 47 | * @example 48 | * const normalizeWhiteSpaces = text => name.replace(/\s+/g, ' ').trim(); 49 | * 50 | * const getInitials = pipe( 51 | * normalizeWhiteSpaces, 52 | * name => name.split(' ').map(name => name.charAt(0)), 53 | * initials => initials.join('').toLocaleUpperCase() 54 | * ); 55 | * 56 | * getInitials('Vitor Luiz Cavalcanti'); 57 | * //=> "VLC" 58 | * 59 | * @param {Function} fn - An arity N function. Its result is the argument of next one. 60 | * @param {...Function[]} fns - Functions of arity 1. Each one's result is next's argument. 61 | * @returns {Function} 62 | */ 63 | export default function pipe(fn: Function) { 64 | const fns = [].slice.call(arguments, 1) as Function[]; 65 | return function () { 66 | return fns.reduce((x, fn) => fn(x), fn.apply(null, arguments)); 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /packages/pipe/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/pipe/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/pipe/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "exclude": [] 7 | } 8 | -------------------------------------------------------------------------------- /packages/predicate/.gitignore: -------------------------------------------------------------------------------- 1 | # Bundled modules and their source-maps. 2 | dist/ 3 | 4 | # Generated type declarations. 5 | types/ 6 | 7 | # Transpiled modules and their source-maps. 8 | src/**/*.js 9 | src/**/*.js.map 10 | -------------------------------------------------------------------------------- /packages/predicate/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../.prettierrc.js'); 2 | -------------------------------------------------------------------------------- /packages/predicate/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vitor Luiz Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/predicate/README.md: -------------------------------------------------------------------------------- 1 | # `@bitty/predicate` 2 | 3 | [![Bundle minified size](https://badgen.net/bundlephobia/min/@bitty/predicate)](https://bundlephobia.com/result?p=@bitty/predicate) 4 | [![Bundle minified and gzipped size](https://badgen.net/bundlephobia/minzip/@bitty/predicate)](https://bundlephobia.com/result?p=@bitty/predicate) 5 | 6 | `Predicate` and `Refinement` types for TypeScript. 7 | 8 | - 🏷 Safe: 9 | - JSDocs and type declarations for IDEs and editor's autocomplete/intellisense. 10 | - Made with TypeScript as strict as possible. 11 | - Unit tests with AVA. 12 | 13 | ## Installation 14 | 15 | This library is published in the NPM registry and can be installed using any compatible package manager. 16 | 17 | ```sh 18 | npm install @bitty/predicate --save 19 | 20 | # For Yarn, use the command below. 21 | yarn add @bitty/predicate 22 | ``` 23 | 24 | ## Getting Stated 25 | 26 | It exports `Predicate` and `Refinement` types. 27 | 28 | - `Predicate` is a function that receives a value and returns a boolean. 29 | 30 | ```ts 31 | import type { Predicate } from '@bitty/predicate'; 32 | 33 | function checkAll(predicates: Predicate[]): Predicate { 34 | return (value) => predicates.every((predicate) => predicate(value)); 35 | } 36 | ``` 37 | 38 | - `Refinement` is similar to `Predicate`, but uses [TypeScript `is` type guard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards). 39 | 40 | ```ts 41 | import { Refinement } from '@bitty/predicate'; 42 | 43 | const isNumber: Refinement = (value) => 44 | Number.isFinite(value); 45 | //=> Was typed as `(value: unknown) => value is number`. 46 | 47 | const value: number | string = Math.random() > 0.5 ? 100 : 'A text.'; 48 | 49 | if (isNumber(value)) { 50 | console.log(value.toFixed(2)); 51 | //=> Okay, because type of `value` was refined to `number`. 52 | } 53 | console.log(value.toFixed(2)); 54 | //=> Property 'toFixed' does not exist on type 'string | number'. 55 | // Property 'toFixed' does not exist on type 'string'. 56 | ``` 57 | 58 | ## License 59 | 60 | Released under [MIT License](./LICENSE). 61 | -------------------------------------------------------------------------------- /packages/predicate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitty/predicate", 3 | "version": "0.2.0", 4 | "description": "Predicate helper functions and types for TypeScript.", 5 | "sideEffects": false, 6 | "cdn": "./dist/main.umd.min.js", 7 | "main": "./dist/main.js", 8 | "types": "./types/main.d.ts", 9 | "unpkg": "./dist/main.umd.min.js", 10 | "module": "./dist/main.esm.js", 11 | "jsdelivr": "./dist/main.umd.min.js", 12 | "umd:main": "./dist/main.umd.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./dist/main.mjs", 17 | "require": "./dist/main.js", 18 | "default": "./dist/main.js" 19 | }, 20 | "./dist/main.js" 21 | ] 22 | }, 23 | "files": [ 24 | "dist/", 25 | "types/" 26 | ], 27 | "keywords": [ 28 | "predicate", 29 | "type", 30 | "types", 31 | "type-guard", 32 | "type-predicate", 33 | "type-helper", 34 | "typescript", 35 | "typescript-types", 36 | "fp", 37 | "functional programming", 38 | "function", 39 | "functional" 40 | ], 41 | "scripts": { 42 | "test": "pnpm run test:code-style && pnpm run test:unit", 43 | "test:transpile": "tsc --project ./tsconfig.test.json", 44 | "test:unit": "pnpm run test:transpile && ava", 45 | "test:code-style": "prettier --check \"./src/**/*.ts\"", 46 | "build": "pnpm run build:transpile && pnpm run build:bundle", 47 | "build:transpile": "tsc --project ./tsconfig.build.json", 48 | "build:bundle": "rollup --config rollup.config.js", 49 | "prepublishOnly": "pnpm run test && pnpm run build" 50 | }, 51 | "repository": { 52 | "type": "git", 53 | "url": "git+https://github.com/VitorLuizC/bitty.git", 54 | "directory": "packages/predicate" 55 | }, 56 | "author": { 57 | "url": "https://vitorluizc.github.io/", 58 | "name": "Vitor Luiz Cavalcanti", 59 | "email": "vitorluizc@outlook.com" 60 | }, 61 | "bugs": { 62 | "url": "https://github.com/VitorLuizC/bitty/issues" 63 | }, 64 | "homepage": "https://github.com/VitorLuizC/bitty/tree/master/packages/predicate", 65 | "license": "MIT", 66 | "devDependencies": { 67 | "ava": "^4.0.1", 68 | "prettier": "^2.5.1", 69 | "rollup": "^2.63.0", 70 | "rollup-plugin-terser": "^7.0.2", 71 | "typescript": "^4.5.4" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /packages/predicate/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | 3 | /** 4 | * Creates an output options object. 5 | * @param {import('rollup').OutputOptions} options 6 | * @returns {import('rollup').OutputOptions} 7 | */ 8 | const Option = (options) => ({ 9 | exports: 'named', 10 | sourcemap: true, 11 | ...options, 12 | }); 13 | 14 | /** 15 | * An object with all configuration for `Rollup.js`. 16 | * @type {import('rollup').RollupOptions} 17 | */ 18 | const options = { 19 | input: './src/main.js', 20 | output: [ 21 | Option({ 22 | file: './dist/main.js', 23 | format: 'commonjs', 24 | }), 25 | Option({ 26 | file: './dist/main.esm.js', 27 | format: 'esm', 28 | }), 29 | Option({ 30 | file: './dist/main.mjs', 31 | format: 'esm', 32 | }), 33 | Option({ 34 | file: './dist/main.umd.js', 35 | name: 'Predicate', 36 | format: 'umd', 37 | }), 38 | Option({ 39 | file: './dist/main.umd.min.js', 40 | name: 'Predicate', 41 | format: 'umd', 42 | plugins: [terser()], 43 | }), 44 | ], 45 | }; 46 | 47 | export default options; 48 | -------------------------------------------------------------------------------- /packages/predicate/src/main.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import type { Predicate, Refinement } from './main'; 3 | 4 | test('Predicate is a function that receives a value and returns boolean', (context) => { 5 | type Assert = T2 extends T ? true : false; 6 | 7 | const V1: Assert boolean> = true; 8 | const V2: Assert, (value: string) => boolean> = true; 9 | 10 | context.true(V1); 11 | context.true(V2); 12 | }); 13 | 14 | test('Refinement is a Predicate that uses `is` type guard', (context) => { 15 | type Assert = T2 extends T ? true : false; 16 | 17 | const V1: Assert, Refinement> = true; 18 | const V2: Assert< 19 | Refinement, 20 | (value: string) => value is 'Okay' 21 | > = true; 22 | const V3: Assert< 23 | Refinement, 24 | (value: 0 | 1 | 2) => value is 0 25 | > = false; 26 | 27 | context.true(V1); 28 | context.true(V2); 29 | context.false(V3); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/predicate/src/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A function that check if value (`T`) matches some predicate. 3 | */ 4 | export type Predicate = (value: T) => boolean; 5 | 6 | /** 7 | * A function that check if value (`T`) is of type `T2`. 8 | */ 9 | export type Refinement = (value: T) => value is T2; 10 | -------------------------------------------------------------------------------- /packages/predicate/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "compilerOptions": { 4 | // Type declaration settings 5 | "declarationDir": "./types", 6 | 7 | // ECMAScript version settings 8 | "lib": ["ES5"] 9 | }, 10 | "include": ["./src/**/*.ts"], 11 | "exclude": ["./src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/predicate/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/predicate/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS" 5 | }, 6 | "exclude": [] 7 | } 8 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.3 2 | 3 | importers: 4 | 5 | .: 6 | specifiers: 7 | pnpm: ^6.25.1 8 | devDependencies: 9 | pnpm: 6.25.1 10 | 11 | packages/animate: 12 | specifiers: 13 | ava: ^4.0.1 14 | prettier: ^2.5.1 15 | rollup: ^2.63.0 16 | rollup-plugin-terser: ^7.0.2 17 | typescript: ^4.5.4 18 | devDependencies: 19 | ava: 4.0.1 20 | prettier: 2.5.1 21 | rollup: 2.63.0 22 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 23 | typescript: 4.5.4 24 | 25 | packages/create-request: 26 | specifiers: 27 | prettier: ^2.5.1 28 | rollup: ^2.63.0 29 | rollup-plugin-terser: ^7.0.2 30 | typescript: ^4.5.4 31 | devDependencies: 32 | prettier: 2.5.1 33 | rollup: 2.63.0 34 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 35 | typescript: 4.5.4 36 | 37 | packages/deferred: 38 | specifiers: 39 | ava: ^4.0.1 40 | prettier: ^2.5.1 41 | rollup: ^2.63.0 42 | rollup-plugin-terser: ^7.0.2 43 | typescript: ^4.5.4 44 | devDependencies: 45 | ava: 4.0.1 46 | prettier: 2.5.1 47 | rollup: 2.63.0 48 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 49 | typescript: 4.5.4 50 | 51 | packages/either: 52 | specifiers: 53 | '@bitty/falsy': workspace:* 54 | '@bitty/nullish': workspace:* 55 | '@bitty/predicate': workspace:* 56 | '@rollup/plugin-node-resolve': ^13.1.3 57 | ava: ^4.0.1 58 | jwt-decode: ^3.1.2 59 | prettier: ^2.5.1 60 | rollup: ^2.63.0 61 | rollup-plugin-terser: ^7.0.2 62 | typescript: ^4.5.4 63 | dependencies: 64 | '@bitty/falsy': link:../falsy 65 | '@bitty/nullish': link:../nullish 66 | '@bitty/predicate': link:../predicate 67 | devDependencies: 68 | '@rollup/plugin-node-resolve': 13.1.3_rollup@2.63.0 69 | ava: 4.0.1 70 | jwt-decode: 3.1.2 71 | prettier: 2.5.1 72 | rollup: 2.63.0 73 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 74 | typescript: 4.5.4 75 | 76 | packages/event-emitter: 77 | specifiers: 78 | ava: ^4.0.1 79 | prettier: ^2.5.1 80 | rollup: ^2.63.0 81 | rollup-plugin-terser: ^7.0.2 82 | typescript: ^4.5.4 83 | devDependencies: 84 | ava: 4.0.1 85 | prettier: 2.5.1 86 | rollup: 2.63.0 87 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 88 | typescript: 4.5.4 89 | 90 | packages/falsy: 91 | specifiers: 92 | ava: ^4.0.1 93 | prettier: ^2.5.1 94 | rollup: ^2.63.0 95 | rollup-plugin-terser: ^7.0.2 96 | typescript: ^4.5.4 97 | devDependencies: 98 | ava: 4.0.1 99 | prettier: 2.5.1 100 | rollup: 2.63.0 101 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 102 | typescript: 4.5.4 103 | 104 | packages/format-date: 105 | specifiers: 106 | ava: ^4.0.1 107 | prettier: ^2.5.1 108 | rollup: ^2.63.0 109 | rollup-plugin-terser: ^7.0.2 110 | typescript: ^4.5.4 111 | devDependencies: 112 | ava: 4.0.1 113 | prettier: 2.5.1 114 | rollup: 2.63.0 115 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 116 | typescript: 4.5.4 117 | 118 | packages/get: 119 | specifiers: 120 | ava: ^4.0.1 121 | prettier: ^2.5.1 122 | rollup: ^2.63.0 123 | rollup-plugin-terser: ^7.0.2 124 | typescript: ^4.5.4 125 | devDependencies: 126 | ava: 4.0.1 127 | prettier: 2.5.1 128 | rollup: 2.63.0 129 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 130 | typescript: 4.5.4 131 | 132 | packages/insist: 133 | specifiers: 134 | ava: ^4.0.1 135 | prettier: ^2.5.1 136 | rollup: ^2.63.0 137 | rollup-plugin-terser: ^7.0.2 138 | typescript: ^4.5.4 139 | devDependencies: 140 | ava: 4.0.1 141 | prettier: 2.5.1 142 | rollup: 2.63.0 143 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 144 | typescript: 4.5.4 145 | 146 | packages/json: 147 | specifiers: 148 | ava: ^4.0.1 149 | prettier: ^2.5.1 150 | rollup: ^2.63.0 151 | rollup-plugin-terser: ^7.0.2 152 | typescript: ^4.5.4 153 | devDependencies: 154 | ava: 4.0.1 155 | prettier: 2.5.1 156 | rollup: 2.63.0 157 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 158 | typescript: 4.5.4 159 | 160 | packages/maybe: 161 | specifiers: 162 | '@bitty/falsy': workspace:* 163 | '@bitty/nullish': workspace:* 164 | '@bitty/predicate': workspace:* 165 | '@rollup/plugin-node-resolve': ^13.1.3 166 | rollup: ^2.63.0 167 | rollup-plugin-terser: ^7.0.2 168 | typescript: ^4.5.4 169 | dependencies: 170 | '@bitty/falsy': link:../falsy 171 | '@bitty/nullish': link:../nullish 172 | '@bitty/predicate': link:../predicate 173 | devDependencies: 174 | '@rollup/plugin-node-resolve': 13.1.3_rollup@2.63.0 175 | rollup: 2.63.0 176 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 177 | typescript: 4.5.4 178 | 179 | packages/nullish: 180 | specifiers: 181 | ava: ^4.0.1 182 | prettier: ^2.5.1 183 | rollup: ^2.63.0 184 | rollup-plugin-terser: ^7.0.2 185 | typescript: ^4.5.4 186 | devDependencies: 187 | ava: 4.0.1 188 | prettier: 2.5.1 189 | rollup: 2.63.0 190 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 191 | typescript: 4.5.4 192 | 193 | packages/pipe: 194 | specifiers: 195 | ava: ^4.0.1 196 | prettier: ^2.5.1 197 | rollup: ^2.63.0 198 | rollup-plugin-terser: ^7.0.2 199 | typescript: ^4.5.4 200 | devDependencies: 201 | ava: 4.0.1 202 | prettier: 2.5.1 203 | rollup: 2.63.0 204 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 205 | typescript: 4.5.4 206 | 207 | packages/predicate: 208 | specifiers: 209 | ava: ^4.0.1 210 | prettier: ^2.5.1 211 | rollup: ^2.63.0 212 | rollup-plugin-terser: ^7.0.2 213 | typescript: ^4.5.4 214 | devDependencies: 215 | ava: 4.0.1 216 | prettier: 2.5.1 217 | rollup: 2.63.0 218 | rollup-plugin-terser: 7.0.2_rollup@2.63.0 219 | typescript: 4.5.4 220 | 221 | packages: 222 | 223 | /@babel/code-frame/7.16.7: 224 | resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==} 225 | engines: {node: '>=6.9.0'} 226 | dependencies: 227 | '@babel/highlight': 7.16.7 228 | dev: true 229 | 230 | /@babel/helper-validator-identifier/7.16.7: 231 | resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==} 232 | engines: {node: '>=6.9.0'} 233 | dev: true 234 | 235 | /@babel/highlight/7.16.7: 236 | resolution: {integrity: sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==} 237 | engines: {node: '>=6.9.0'} 238 | dependencies: 239 | '@babel/helper-validator-identifier': 7.16.7 240 | chalk: 2.4.2 241 | js-tokens: 4.0.0 242 | dev: true 243 | 244 | /@nodelib/fs.scandir/2.1.5: 245 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 246 | engines: {node: '>= 8'} 247 | dependencies: 248 | '@nodelib/fs.stat': 2.0.5 249 | run-parallel: 1.2.0 250 | dev: true 251 | 252 | /@nodelib/fs.stat/2.0.5: 253 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 254 | engines: {node: '>= 8'} 255 | dev: true 256 | 257 | /@nodelib/fs.walk/1.2.8: 258 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 259 | engines: {node: '>= 8'} 260 | dependencies: 261 | '@nodelib/fs.scandir': 2.1.5 262 | fastq: 1.13.0 263 | dev: true 264 | 265 | /@rollup/plugin-node-resolve/13.1.3_rollup@2.63.0: 266 | resolution: {integrity: sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==} 267 | engines: {node: '>= 10.0.0'} 268 | peerDependencies: 269 | rollup: ^2.42.0 270 | dependencies: 271 | '@rollup/pluginutils': 3.1.0_rollup@2.63.0 272 | '@types/resolve': 1.17.1 273 | builtin-modules: 3.2.0 274 | deepmerge: 4.2.2 275 | is-module: 1.0.0 276 | resolve: 1.21.0 277 | rollup: 2.63.0 278 | dev: true 279 | 280 | /@rollup/pluginutils/3.1.0_rollup@2.63.0: 281 | resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} 282 | engines: {node: '>= 8.0.0'} 283 | peerDependencies: 284 | rollup: ^1.20.0||^2.0.0 285 | dependencies: 286 | '@types/estree': 0.0.39 287 | estree-walker: 1.0.1 288 | picomatch: 2.3.1 289 | rollup: 2.63.0 290 | dev: true 291 | 292 | /@types/estree/0.0.39: 293 | resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} 294 | dev: true 295 | 296 | /@types/node/17.0.8: 297 | resolution: {integrity: sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==} 298 | dev: true 299 | 300 | /@types/resolve/1.17.1: 301 | resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} 302 | dependencies: 303 | '@types/node': 17.0.8 304 | dev: true 305 | 306 | /acorn-walk/8.2.0: 307 | resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} 308 | engines: {node: '>=0.4.0'} 309 | dev: true 310 | 311 | /acorn/8.7.0: 312 | resolution: {integrity: sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==} 313 | engines: {node: '>=0.4.0'} 314 | hasBin: true 315 | dev: true 316 | 317 | /aggregate-error/3.1.0: 318 | resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} 319 | engines: {node: '>=8'} 320 | dependencies: 321 | clean-stack: 2.2.0 322 | indent-string: 4.0.0 323 | dev: true 324 | 325 | /aggregate-error/4.0.0: 326 | resolution: {integrity: sha512-8DGp7zUt1E9k0NE2q4jlXHk+V3ORErmwolEdRz9iV+LKJ40WhMHh92cxAvhqV2I+zEn/gotIoqoMs0NjF3xofg==} 327 | engines: {node: '>=12'} 328 | dependencies: 329 | clean-stack: 4.1.0 330 | indent-string: 5.0.0 331 | dev: true 332 | 333 | /ansi-regex/5.0.1: 334 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 335 | engines: {node: '>=8'} 336 | dev: true 337 | 338 | /ansi-regex/6.0.1: 339 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 340 | engines: {node: '>=12'} 341 | dev: true 342 | 343 | /ansi-styles/3.2.1: 344 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 345 | engines: {node: '>=4'} 346 | dependencies: 347 | color-convert: 1.9.3 348 | dev: true 349 | 350 | /ansi-styles/4.3.0: 351 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 352 | engines: {node: '>=8'} 353 | dependencies: 354 | color-convert: 2.0.1 355 | dev: true 356 | 357 | /ansi-styles/6.1.0: 358 | resolution: {integrity: sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==} 359 | engines: {node: '>=12'} 360 | dev: true 361 | 362 | /anymatch/3.1.2: 363 | resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} 364 | engines: {node: '>= 8'} 365 | dependencies: 366 | normalize-path: 3.0.0 367 | picomatch: 2.3.1 368 | dev: true 369 | 370 | /argparse/1.0.10: 371 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 372 | dependencies: 373 | sprintf-js: 1.0.3 374 | dev: true 375 | 376 | /array-find-index/1.0.2: 377 | resolution: {integrity: sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=} 378 | engines: {node: '>=0.10.0'} 379 | dev: true 380 | 381 | /array-union/2.1.0: 382 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 383 | engines: {node: '>=8'} 384 | dev: true 385 | 386 | /array-union/3.0.1: 387 | resolution: {integrity: sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==} 388 | engines: {node: '>=12'} 389 | dev: true 390 | 391 | /arrgv/1.0.2: 392 | resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} 393 | engines: {node: '>=8.0.0'} 394 | dev: true 395 | 396 | /arrify/2.0.1: 397 | resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} 398 | engines: {node: '>=8'} 399 | dev: true 400 | 401 | /arrify/3.0.0: 402 | resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} 403 | engines: {node: '>=12'} 404 | dev: true 405 | 406 | /ava/4.0.1: 407 | resolution: {integrity: sha512-+12A/JDWyShBCZAKISEEPyM2dwkUrrAfPILqXi4LI4Aa58d92PzjY829hmuoSeACPNqrn2Wlbnja8c/n7bKV6Q==} 408 | engines: {node: '>=12.22 <13 || >=14.17 <15 || >=16.4 <17 || >=17'} 409 | hasBin: true 410 | peerDependencies: 411 | '@ava/typescript': '*' 412 | peerDependenciesMeta: 413 | '@ava/typescript': 414 | optional: true 415 | dependencies: 416 | acorn: 8.7.0 417 | acorn-walk: 8.2.0 418 | ansi-styles: 6.1.0 419 | arrgv: 1.0.2 420 | arrify: 3.0.0 421 | callsites: 4.0.0 422 | cbor: 8.1.0 423 | chalk: 5.0.0 424 | chokidar: 3.5.2 425 | chunkd: 2.0.1 426 | ci-info: 3.3.0 427 | ci-parallel-vars: 1.0.1 428 | clean-yaml-object: 0.1.0 429 | cli-truncate: 3.1.0 430 | code-excerpt: 3.0.0 431 | common-path-prefix: 3.0.0 432 | concordance: 5.0.4 433 | currently-unhandled: 0.4.1 434 | debug: 4.3.3 435 | del: 6.0.0 436 | emittery: 0.10.0 437 | figures: 4.0.0 438 | globby: 12.0.2 439 | ignore-by-default: 2.0.0 440 | indent-string: 5.0.0 441 | is-error: 2.2.2 442 | is-plain-object: 5.0.0 443 | is-promise: 4.0.0 444 | matcher: 5.0.0 445 | mem: 9.0.1 446 | ms: 2.1.3 447 | p-event: 5.0.1 448 | p-map: 5.3.0 449 | picomatch: 2.3.1 450 | pkg-conf: 4.0.0 451 | plur: 5.1.0 452 | pretty-ms: 7.0.1 453 | resolve-cwd: 3.0.0 454 | slash: 3.0.0 455 | stack-utils: 2.0.5 456 | strip-ansi: 7.0.1 457 | supertap: 2.0.0 458 | temp-dir: 2.0.0 459 | write-file-atomic: 3.0.3 460 | yargs: 17.3.1 461 | transitivePeerDependencies: 462 | - supports-color 463 | dev: true 464 | 465 | /balanced-match/1.0.2: 466 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 467 | dev: true 468 | 469 | /binary-extensions/2.2.0: 470 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 471 | engines: {node: '>=8'} 472 | dev: true 473 | 474 | /blueimp-md5/2.19.0: 475 | resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} 476 | dev: true 477 | 478 | /brace-expansion/1.1.11: 479 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 480 | dependencies: 481 | balanced-match: 1.0.2 482 | concat-map: 0.0.1 483 | dev: true 484 | 485 | /braces/3.0.2: 486 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 487 | engines: {node: '>=8'} 488 | dependencies: 489 | fill-range: 7.0.1 490 | dev: true 491 | 492 | /buffer-from/1.1.2: 493 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 494 | dev: true 495 | 496 | /builtin-modules/3.2.0: 497 | resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==} 498 | engines: {node: '>=6'} 499 | dev: true 500 | 501 | /callsites/4.0.0: 502 | resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==} 503 | engines: {node: '>=12.20'} 504 | dev: true 505 | 506 | /cbor/8.1.0: 507 | resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} 508 | engines: {node: '>=12.19'} 509 | dependencies: 510 | nofilter: 3.1.0 511 | dev: true 512 | 513 | /chalk/2.4.2: 514 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 515 | engines: {node: '>=4'} 516 | dependencies: 517 | ansi-styles: 3.2.1 518 | escape-string-regexp: 1.0.5 519 | supports-color: 5.5.0 520 | dev: true 521 | 522 | /chalk/5.0.0: 523 | resolution: {integrity: sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==} 524 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 525 | dev: true 526 | 527 | /chokidar/3.5.2: 528 | resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==} 529 | engines: {node: '>= 8.10.0'} 530 | dependencies: 531 | anymatch: 3.1.2 532 | braces: 3.0.2 533 | glob-parent: 5.1.2 534 | is-binary-path: 2.1.0 535 | is-glob: 4.0.3 536 | normalize-path: 3.0.0 537 | readdirp: 3.6.0 538 | optionalDependencies: 539 | fsevents: 2.3.2 540 | dev: true 541 | 542 | /chunkd/2.0.1: 543 | resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} 544 | dev: true 545 | 546 | /ci-info/3.3.0: 547 | resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} 548 | dev: true 549 | 550 | /ci-parallel-vars/1.0.1: 551 | resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} 552 | dev: true 553 | 554 | /clean-stack/2.2.0: 555 | resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} 556 | engines: {node: '>=6'} 557 | dev: true 558 | 559 | /clean-stack/4.1.0: 560 | resolution: {integrity: sha512-dxXQYI7mfQVcaF12s6sjNFoZ6ZPDQuBBLp3QJ5156k9EvUFClUoZ11fo8HnLQO241DDVntHEug8MOuFO5PSfRg==} 561 | engines: {node: '>=12'} 562 | dependencies: 563 | escape-string-regexp: 5.0.0 564 | dev: true 565 | 566 | /clean-yaml-object/0.1.0: 567 | resolution: {integrity: sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=} 568 | engines: {node: '>=0.10.0'} 569 | dev: true 570 | 571 | /cli-truncate/3.1.0: 572 | resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} 573 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 574 | dependencies: 575 | slice-ansi: 5.0.0 576 | string-width: 5.1.0 577 | dev: true 578 | 579 | /cliui/7.0.4: 580 | resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} 581 | dependencies: 582 | string-width: 4.2.3 583 | strip-ansi: 6.0.1 584 | wrap-ansi: 7.0.0 585 | dev: true 586 | 587 | /code-excerpt/3.0.0: 588 | resolution: {integrity: sha512-VHNTVhd7KsLGOqfX3SyeO8RyYPMp1GJOg194VITk04WMYCv4plV68YWe6TJZxd9MhobjtpMRnVky01gqZsalaw==} 589 | engines: {node: '>=10'} 590 | dependencies: 591 | convert-to-spaces: 1.0.2 592 | dev: true 593 | 594 | /color-convert/1.9.3: 595 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 596 | dependencies: 597 | color-name: 1.1.3 598 | dev: true 599 | 600 | /color-convert/2.0.1: 601 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 602 | engines: {node: '>=7.0.0'} 603 | dependencies: 604 | color-name: 1.1.4 605 | dev: true 606 | 607 | /color-name/1.1.3: 608 | resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} 609 | dev: true 610 | 611 | /color-name/1.1.4: 612 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 613 | dev: true 614 | 615 | /commander/2.20.3: 616 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 617 | dev: true 618 | 619 | /common-path-prefix/3.0.0: 620 | resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} 621 | dev: true 622 | 623 | /concat-map/0.0.1: 624 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 625 | dev: true 626 | 627 | /concordance/5.0.4: 628 | resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} 629 | engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} 630 | dependencies: 631 | date-time: 3.1.0 632 | esutils: 2.0.3 633 | fast-diff: 1.2.0 634 | js-string-escape: 1.0.1 635 | lodash: 4.17.21 636 | md5-hex: 3.0.1 637 | semver: 7.3.5 638 | well-known-symbols: 2.0.0 639 | dev: true 640 | 641 | /convert-to-spaces/1.0.2: 642 | resolution: {integrity: sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=} 643 | engines: {node: '>= 4'} 644 | dev: true 645 | 646 | /currently-unhandled/0.4.1: 647 | resolution: {integrity: sha1-mI3zP+qxke95mmE2nddsF635V+o=} 648 | engines: {node: '>=0.10.0'} 649 | dependencies: 650 | array-find-index: 1.0.2 651 | dev: true 652 | 653 | /date-time/3.1.0: 654 | resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} 655 | engines: {node: '>=6'} 656 | dependencies: 657 | time-zone: 1.0.0 658 | dev: true 659 | 660 | /debug/4.3.3: 661 | resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} 662 | engines: {node: '>=6.0'} 663 | peerDependencies: 664 | supports-color: '*' 665 | peerDependenciesMeta: 666 | supports-color: 667 | optional: true 668 | dependencies: 669 | ms: 2.1.2 670 | dev: true 671 | 672 | /deepmerge/4.2.2: 673 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} 674 | engines: {node: '>=0.10.0'} 675 | dev: true 676 | 677 | /del/6.0.0: 678 | resolution: {integrity: sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==} 679 | engines: {node: '>=10'} 680 | dependencies: 681 | globby: 11.1.0 682 | graceful-fs: 4.2.9 683 | is-glob: 4.0.3 684 | is-path-cwd: 2.2.0 685 | is-path-inside: 3.0.3 686 | p-map: 4.0.0 687 | rimraf: 3.0.2 688 | slash: 3.0.0 689 | dev: true 690 | 691 | /dir-glob/3.0.1: 692 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 693 | engines: {node: '>=8'} 694 | dependencies: 695 | path-type: 4.0.0 696 | dev: true 697 | 698 | /eastasianwidth/0.2.0: 699 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 700 | dev: true 701 | 702 | /emittery/0.10.0: 703 | resolution: {integrity: sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==} 704 | engines: {node: '>=12'} 705 | dev: true 706 | 707 | /emoji-regex/8.0.0: 708 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 709 | dev: true 710 | 711 | /emoji-regex/9.2.2: 712 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 713 | dev: true 714 | 715 | /escalade/3.1.1: 716 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 717 | engines: {node: '>=6'} 718 | dev: true 719 | 720 | /escape-string-regexp/1.0.5: 721 | resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} 722 | engines: {node: '>=0.8.0'} 723 | dev: true 724 | 725 | /escape-string-regexp/2.0.0: 726 | resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} 727 | engines: {node: '>=8'} 728 | dev: true 729 | 730 | /escape-string-regexp/5.0.0: 731 | resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} 732 | engines: {node: '>=12'} 733 | dev: true 734 | 735 | /esprima/4.0.1: 736 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 737 | engines: {node: '>=4'} 738 | hasBin: true 739 | dev: true 740 | 741 | /estree-walker/1.0.1: 742 | resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} 743 | dev: true 744 | 745 | /esutils/2.0.3: 746 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 747 | engines: {node: '>=0.10.0'} 748 | dev: true 749 | 750 | /fast-diff/1.2.0: 751 | resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} 752 | dev: true 753 | 754 | /fast-glob/3.2.10: 755 | resolution: {integrity: sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==} 756 | engines: {node: '>=8.6.0'} 757 | dependencies: 758 | '@nodelib/fs.stat': 2.0.5 759 | '@nodelib/fs.walk': 1.2.8 760 | glob-parent: 5.1.2 761 | merge2: 1.4.1 762 | micromatch: 4.0.4 763 | dev: true 764 | 765 | /fastq/1.13.0: 766 | resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} 767 | dependencies: 768 | reusify: 1.0.4 769 | dev: true 770 | 771 | /figures/4.0.0: 772 | resolution: {integrity: sha512-VnYcWq6H6F0qDN0QnorznBr0abEovifzUokmnezpKZBUbDmbLAt7LMryOp1TKFVxLxyNYkxEkCEADZR58U9oSw==} 773 | engines: {node: '>=12'} 774 | dependencies: 775 | escape-string-regexp: 5.0.0 776 | is-unicode-supported: 1.1.0 777 | dev: true 778 | 779 | /fill-range/7.0.1: 780 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 781 | engines: {node: '>=8'} 782 | dependencies: 783 | to-regex-range: 5.0.1 784 | dev: true 785 | 786 | /find-up/6.2.0: 787 | resolution: {integrity: sha512-yWHzMzXCaFoABSnFTCPKNFlYoq4mSga9QLRRKOCLSJ33hSkzROB14ITbAWW0QDQDyuzsPQ33S1DsOWQb/oW1yA==} 788 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 789 | dependencies: 790 | locate-path: 7.0.0 791 | path-exists: 5.0.0 792 | dev: true 793 | 794 | /fs.realpath/1.0.0: 795 | resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} 796 | dev: true 797 | 798 | /fsevents/2.3.2: 799 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 800 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 801 | os: [darwin] 802 | requiresBuild: true 803 | dev: true 804 | optional: true 805 | 806 | /function-bind/1.1.1: 807 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 808 | dev: true 809 | 810 | /get-caller-file/2.0.5: 811 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 812 | engines: {node: 6.* || 8.* || >= 10.*} 813 | dev: true 814 | 815 | /glob-parent/5.1.2: 816 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 817 | engines: {node: '>= 6'} 818 | dependencies: 819 | is-glob: 4.0.3 820 | dev: true 821 | 822 | /glob/7.2.0: 823 | resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} 824 | dependencies: 825 | fs.realpath: 1.0.0 826 | inflight: 1.0.6 827 | inherits: 2.0.4 828 | minimatch: 3.0.4 829 | once: 1.4.0 830 | path-is-absolute: 1.0.1 831 | dev: true 832 | 833 | /globby/11.1.0: 834 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 835 | engines: {node: '>=10'} 836 | dependencies: 837 | array-union: 2.1.0 838 | dir-glob: 3.0.1 839 | fast-glob: 3.2.10 840 | ignore: 5.2.0 841 | merge2: 1.4.1 842 | slash: 3.0.0 843 | dev: true 844 | 845 | /globby/12.0.2: 846 | resolution: {integrity: sha512-lAsmb/5Lww4r7MM9nCCliDZVIKbZTavrsunAsHLr9oHthrZP1qi7/gAnHOsUs9bLvEt2vKVJhHmxuL7QbDuPdQ==} 847 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 848 | dependencies: 849 | array-union: 3.0.1 850 | dir-glob: 3.0.1 851 | fast-glob: 3.2.10 852 | ignore: 5.2.0 853 | merge2: 1.4.1 854 | slash: 4.0.0 855 | dev: true 856 | 857 | /graceful-fs/4.2.9: 858 | resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} 859 | dev: true 860 | 861 | /has-flag/3.0.0: 862 | resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} 863 | engines: {node: '>=4'} 864 | dev: true 865 | 866 | /has-flag/4.0.0: 867 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 868 | engines: {node: '>=8'} 869 | dev: true 870 | 871 | /has/1.0.3: 872 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 873 | engines: {node: '>= 0.4.0'} 874 | dependencies: 875 | function-bind: 1.1.1 876 | dev: true 877 | 878 | /ignore-by-default/2.0.0: 879 | resolution: {integrity: sha512-+mQSgMRiFD3L3AOxLYOCxjIq4OnAmo5CIuC+lj5ehCJcPtV++QacEV7FdpzvYxH6DaOySWzQU6RR0lPLy37ckA==} 880 | engines: {node: '>=10 <11 || >=12 <13 || >=14'} 881 | dev: true 882 | 883 | /ignore/5.2.0: 884 | resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} 885 | engines: {node: '>= 4'} 886 | dev: true 887 | 888 | /imurmurhash/0.1.4: 889 | resolution: {integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o=} 890 | engines: {node: '>=0.8.19'} 891 | dev: true 892 | 893 | /indent-string/4.0.0: 894 | resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} 895 | engines: {node: '>=8'} 896 | dev: true 897 | 898 | /indent-string/5.0.0: 899 | resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} 900 | engines: {node: '>=12'} 901 | dev: true 902 | 903 | /inflight/1.0.6: 904 | resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} 905 | dependencies: 906 | once: 1.4.0 907 | wrappy: 1.0.2 908 | dev: true 909 | 910 | /inherits/2.0.4: 911 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 912 | dev: true 913 | 914 | /irregular-plurals/3.3.0: 915 | resolution: {integrity: sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==} 916 | engines: {node: '>=8'} 917 | dev: true 918 | 919 | /is-binary-path/2.1.0: 920 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 921 | engines: {node: '>=8'} 922 | dependencies: 923 | binary-extensions: 2.2.0 924 | dev: true 925 | 926 | /is-core-module/2.8.1: 927 | resolution: {integrity: sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==} 928 | dependencies: 929 | has: 1.0.3 930 | dev: true 931 | 932 | /is-error/2.2.2: 933 | resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} 934 | dev: true 935 | 936 | /is-extglob/2.1.1: 937 | resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} 938 | engines: {node: '>=0.10.0'} 939 | dev: true 940 | 941 | /is-fullwidth-code-point/3.0.0: 942 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 943 | engines: {node: '>=8'} 944 | dev: true 945 | 946 | /is-fullwidth-code-point/4.0.0: 947 | resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} 948 | engines: {node: '>=12'} 949 | dev: true 950 | 951 | /is-glob/4.0.3: 952 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 953 | engines: {node: '>=0.10.0'} 954 | dependencies: 955 | is-extglob: 2.1.1 956 | dev: true 957 | 958 | /is-module/1.0.0: 959 | resolution: {integrity: sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=} 960 | dev: true 961 | 962 | /is-number/7.0.0: 963 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 964 | engines: {node: '>=0.12.0'} 965 | dev: true 966 | 967 | /is-path-cwd/2.2.0: 968 | resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} 969 | engines: {node: '>=6'} 970 | dev: true 971 | 972 | /is-path-inside/3.0.3: 973 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 974 | engines: {node: '>=8'} 975 | dev: true 976 | 977 | /is-plain-object/5.0.0: 978 | resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} 979 | engines: {node: '>=0.10.0'} 980 | dev: true 981 | 982 | /is-promise/4.0.0: 983 | resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} 984 | dev: true 985 | 986 | /is-typedarray/1.0.0: 987 | resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=} 988 | dev: true 989 | 990 | /is-unicode-supported/1.1.0: 991 | resolution: {integrity: sha512-lDcxivp8TJpLG75/DpatAqNzOpDPSpED8XNtrpBHTdQ2InQ1PbW78jhwSxyxhhu+xbVSast2X38bwj8atwoUQA==} 992 | engines: {node: '>=12'} 993 | dev: true 994 | 995 | /jest-worker/26.6.2: 996 | resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} 997 | engines: {node: '>= 10.13.0'} 998 | dependencies: 999 | '@types/node': 17.0.8 1000 | merge-stream: 2.0.0 1001 | supports-color: 7.2.0 1002 | dev: true 1003 | 1004 | /js-string-escape/1.0.1: 1005 | resolution: {integrity: sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=} 1006 | engines: {node: '>= 0.8'} 1007 | dev: true 1008 | 1009 | /js-tokens/4.0.0: 1010 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1011 | dev: true 1012 | 1013 | /js-yaml/3.14.1: 1014 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 1015 | hasBin: true 1016 | dependencies: 1017 | argparse: 1.0.10 1018 | esprima: 4.0.1 1019 | dev: true 1020 | 1021 | /jwt-decode/3.1.2: 1022 | resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} 1023 | dev: true 1024 | 1025 | /load-json-file/7.0.1: 1026 | resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} 1027 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1028 | dev: true 1029 | 1030 | /locate-path/7.0.0: 1031 | resolution: {integrity: sha512-+cg2yXqDUKfo4hsFxwa3G1cBJeA+gs1vD8FyV9/odWoUlQe/4syxHQ5DPtKjtfm6gnKbZzjCqzX03kXosvZB1w==} 1032 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1033 | dependencies: 1034 | p-locate: 6.0.0 1035 | dev: true 1036 | 1037 | /lodash/4.17.21: 1038 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 1039 | dev: true 1040 | 1041 | /lru-cache/6.0.0: 1042 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1043 | engines: {node: '>=10'} 1044 | dependencies: 1045 | yallist: 4.0.0 1046 | dev: true 1047 | 1048 | /map-age-cleaner/0.1.3: 1049 | resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} 1050 | engines: {node: '>=6'} 1051 | dependencies: 1052 | p-defer: 1.0.0 1053 | dev: true 1054 | 1055 | /matcher/5.0.0: 1056 | resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} 1057 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1058 | dependencies: 1059 | escape-string-regexp: 5.0.0 1060 | dev: true 1061 | 1062 | /md5-hex/3.0.1: 1063 | resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} 1064 | engines: {node: '>=8'} 1065 | dependencies: 1066 | blueimp-md5: 2.19.0 1067 | dev: true 1068 | 1069 | /mem/9.0.1: 1070 | resolution: {integrity: sha512-f4uEX3Ley9FZqcFIRSBr2q43x1bJQeDvsxgkSN/BPnA7jY9Aue4sBU2dsjmpDwiaY/QY1maNCeosbUHQWzzdQw==} 1071 | engines: {node: '>=12.20'} 1072 | dependencies: 1073 | map-age-cleaner: 0.1.3 1074 | mimic-fn: 4.0.0 1075 | dev: true 1076 | 1077 | /merge-stream/2.0.0: 1078 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 1079 | dev: true 1080 | 1081 | /merge2/1.4.1: 1082 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1083 | engines: {node: '>= 8'} 1084 | dev: true 1085 | 1086 | /micromatch/4.0.4: 1087 | resolution: {integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==} 1088 | engines: {node: '>=8.6'} 1089 | dependencies: 1090 | braces: 3.0.2 1091 | picomatch: 2.3.1 1092 | dev: true 1093 | 1094 | /mimic-fn/4.0.0: 1095 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} 1096 | engines: {node: '>=12'} 1097 | dev: true 1098 | 1099 | /minimatch/3.0.4: 1100 | resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} 1101 | dependencies: 1102 | brace-expansion: 1.1.11 1103 | dev: true 1104 | 1105 | /ms/2.1.2: 1106 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1107 | dev: true 1108 | 1109 | /ms/2.1.3: 1110 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1111 | dev: true 1112 | 1113 | /nofilter/3.1.0: 1114 | resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} 1115 | engines: {node: '>=12.19'} 1116 | dev: true 1117 | 1118 | /normalize-path/3.0.0: 1119 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1120 | engines: {node: '>=0.10.0'} 1121 | dev: true 1122 | 1123 | /once/1.4.0: 1124 | resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} 1125 | dependencies: 1126 | wrappy: 1.0.2 1127 | dev: true 1128 | 1129 | /p-defer/1.0.0: 1130 | resolution: {integrity: sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=} 1131 | engines: {node: '>=4'} 1132 | dev: true 1133 | 1134 | /p-event/5.0.1: 1135 | resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} 1136 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1137 | dependencies: 1138 | p-timeout: 5.0.2 1139 | dev: true 1140 | 1141 | /p-limit/4.0.0: 1142 | resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} 1143 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1144 | dependencies: 1145 | yocto-queue: 1.0.0 1146 | dev: true 1147 | 1148 | /p-locate/6.0.0: 1149 | resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} 1150 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1151 | dependencies: 1152 | p-limit: 4.0.0 1153 | dev: true 1154 | 1155 | /p-map/4.0.0: 1156 | resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} 1157 | engines: {node: '>=10'} 1158 | dependencies: 1159 | aggregate-error: 3.1.0 1160 | dev: true 1161 | 1162 | /p-map/5.3.0: 1163 | resolution: {integrity: sha512-SRbIQFoLYNezHkqZslqeg963HYUtqOrfMCxjNrFOpJ19WTYuq26rQoOXeX8QQiMLUlLqdYV/7PuDsdYJ7hLE1w==} 1164 | engines: {node: '>=12'} 1165 | dependencies: 1166 | aggregate-error: 4.0.0 1167 | dev: true 1168 | 1169 | /p-timeout/5.0.2: 1170 | resolution: {integrity: sha512-sEmji9Yaq+Tw+STwsGAE56hf7gMy9p0tQfJojIAamB7WHJYJKf1qlsg9jqBWG8q9VCxKPhZaP/AcXwEoBcYQhQ==} 1171 | engines: {node: '>=12'} 1172 | dev: true 1173 | 1174 | /parse-ms/2.1.0: 1175 | resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} 1176 | engines: {node: '>=6'} 1177 | dev: true 1178 | 1179 | /path-exists/5.0.0: 1180 | resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} 1181 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1182 | dev: true 1183 | 1184 | /path-is-absolute/1.0.1: 1185 | resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} 1186 | engines: {node: '>=0.10.0'} 1187 | dev: true 1188 | 1189 | /path-parse/1.0.7: 1190 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1191 | dev: true 1192 | 1193 | /path-type/4.0.0: 1194 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1195 | engines: {node: '>=8'} 1196 | dev: true 1197 | 1198 | /picomatch/2.3.1: 1199 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1200 | engines: {node: '>=8.6'} 1201 | dev: true 1202 | 1203 | /pkg-conf/4.0.0: 1204 | resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} 1205 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1206 | dependencies: 1207 | find-up: 6.2.0 1208 | load-json-file: 7.0.1 1209 | dev: true 1210 | 1211 | /plur/5.1.0: 1212 | resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} 1213 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1214 | dependencies: 1215 | irregular-plurals: 3.3.0 1216 | dev: true 1217 | 1218 | /pnpm/6.25.1: 1219 | resolution: {integrity: sha512-/jvwDU8XJ3ntw1fJ5pYGN+nMqxHuXoarajc/95CrAB9+lVfjTJooiOc5BmxT7GrZzcEwdpJKMCdN3yR1ItGFMw==} 1220 | engines: {node: '>=12.17'} 1221 | hasBin: true 1222 | dev: true 1223 | 1224 | /prettier/2.5.1: 1225 | resolution: {integrity: sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==} 1226 | engines: {node: '>=10.13.0'} 1227 | hasBin: true 1228 | dev: true 1229 | 1230 | /pretty-ms/7.0.1: 1231 | resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} 1232 | engines: {node: '>=10'} 1233 | dependencies: 1234 | parse-ms: 2.1.0 1235 | dev: true 1236 | 1237 | /queue-microtask/1.2.3: 1238 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1239 | dev: true 1240 | 1241 | /randombytes/2.1.0: 1242 | resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} 1243 | dependencies: 1244 | safe-buffer: 5.2.1 1245 | dev: true 1246 | 1247 | /readdirp/3.6.0: 1248 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1249 | engines: {node: '>=8.10.0'} 1250 | dependencies: 1251 | picomatch: 2.3.1 1252 | dev: true 1253 | 1254 | /require-directory/2.1.1: 1255 | resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} 1256 | engines: {node: '>=0.10.0'} 1257 | dev: true 1258 | 1259 | /resolve-cwd/3.0.0: 1260 | resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} 1261 | engines: {node: '>=8'} 1262 | dependencies: 1263 | resolve-from: 5.0.0 1264 | dev: true 1265 | 1266 | /resolve-from/5.0.0: 1267 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1268 | engines: {node: '>=8'} 1269 | dev: true 1270 | 1271 | /resolve/1.21.0: 1272 | resolution: {integrity: sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==} 1273 | hasBin: true 1274 | dependencies: 1275 | is-core-module: 2.8.1 1276 | path-parse: 1.0.7 1277 | supports-preserve-symlinks-flag: 1.0.0 1278 | dev: true 1279 | 1280 | /reusify/1.0.4: 1281 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1282 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1283 | dev: true 1284 | 1285 | /rimraf/3.0.2: 1286 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1287 | hasBin: true 1288 | dependencies: 1289 | glob: 7.2.0 1290 | dev: true 1291 | 1292 | /rollup-plugin-terser/7.0.2_rollup@2.63.0: 1293 | resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} 1294 | peerDependencies: 1295 | rollup: ^2.0.0 1296 | dependencies: 1297 | '@babel/code-frame': 7.16.7 1298 | jest-worker: 26.6.2 1299 | rollup: 2.63.0 1300 | serialize-javascript: 4.0.0 1301 | terser: 5.10.0 1302 | transitivePeerDependencies: 1303 | - acorn 1304 | dev: true 1305 | 1306 | /rollup/2.63.0: 1307 | resolution: {integrity: sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==} 1308 | engines: {node: '>=10.0.0'} 1309 | hasBin: true 1310 | optionalDependencies: 1311 | fsevents: 2.3.2 1312 | dev: true 1313 | 1314 | /run-parallel/1.2.0: 1315 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1316 | dependencies: 1317 | queue-microtask: 1.2.3 1318 | dev: true 1319 | 1320 | /safe-buffer/5.2.1: 1321 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1322 | dev: true 1323 | 1324 | /semver/7.3.5: 1325 | resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==} 1326 | engines: {node: '>=10'} 1327 | hasBin: true 1328 | dependencies: 1329 | lru-cache: 6.0.0 1330 | dev: true 1331 | 1332 | /serialize-error/7.0.1: 1333 | resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} 1334 | engines: {node: '>=10'} 1335 | dependencies: 1336 | type-fest: 0.13.1 1337 | dev: true 1338 | 1339 | /serialize-javascript/4.0.0: 1340 | resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} 1341 | dependencies: 1342 | randombytes: 2.1.0 1343 | dev: true 1344 | 1345 | /signal-exit/3.0.6: 1346 | resolution: {integrity: sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==} 1347 | dev: true 1348 | 1349 | /slash/3.0.0: 1350 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1351 | engines: {node: '>=8'} 1352 | dev: true 1353 | 1354 | /slash/4.0.0: 1355 | resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} 1356 | engines: {node: '>=12'} 1357 | dev: true 1358 | 1359 | /slice-ansi/5.0.0: 1360 | resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} 1361 | engines: {node: '>=12'} 1362 | dependencies: 1363 | ansi-styles: 6.1.0 1364 | is-fullwidth-code-point: 4.0.0 1365 | dev: true 1366 | 1367 | /source-map-support/0.5.21: 1368 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 1369 | dependencies: 1370 | buffer-from: 1.1.2 1371 | source-map: 0.6.1 1372 | dev: true 1373 | 1374 | /source-map/0.6.1: 1375 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1376 | engines: {node: '>=0.10.0'} 1377 | dev: true 1378 | 1379 | /source-map/0.7.3: 1380 | resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} 1381 | engines: {node: '>= 8'} 1382 | dev: true 1383 | 1384 | /sprintf-js/1.0.3: 1385 | resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} 1386 | dev: true 1387 | 1388 | /stack-utils/2.0.5: 1389 | resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} 1390 | engines: {node: '>=10'} 1391 | dependencies: 1392 | escape-string-regexp: 2.0.0 1393 | dev: true 1394 | 1395 | /string-width/4.2.3: 1396 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1397 | engines: {node: '>=8'} 1398 | dependencies: 1399 | emoji-regex: 8.0.0 1400 | is-fullwidth-code-point: 3.0.0 1401 | strip-ansi: 6.0.1 1402 | dev: true 1403 | 1404 | /string-width/5.1.0: 1405 | resolution: {integrity: sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==} 1406 | engines: {node: '>=12'} 1407 | dependencies: 1408 | eastasianwidth: 0.2.0 1409 | emoji-regex: 9.2.2 1410 | strip-ansi: 7.0.1 1411 | dev: true 1412 | 1413 | /strip-ansi/6.0.1: 1414 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1415 | engines: {node: '>=8'} 1416 | dependencies: 1417 | ansi-regex: 5.0.1 1418 | dev: true 1419 | 1420 | /strip-ansi/7.0.1: 1421 | resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} 1422 | engines: {node: '>=12'} 1423 | dependencies: 1424 | ansi-regex: 6.0.1 1425 | dev: true 1426 | 1427 | /supertap/2.0.0: 1428 | resolution: {integrity: sha512-jRzcXlCeDYvKoZGA5oRhYyR3jUIYu0enkSxtmAgHRlD7HwrovTpH4bDSi0py9FtuA8si9cW/fKommJHuaoDHJA==} 1429 | engines: {node: '>=10'} 1430 | dependencies: 1431 | arrify: 2.0.1 1432 | indent-string: 4.0.0 1433 | js-yaml: 3.14.1 1434 | serialize-error: 7.0.1 1435 | strip-ansi: 6.0.1 1436 | dev: true 1437 | 1438 | /supports-color/5.5.0: 1439 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 1440 | engines: {node: '>=4'} 1441 | dependencies: 1442 | has-flag: 3.0.0 1443 | dev: true 1444 | 1445 | /supports-color/7.2.0: 1446 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1447 | engines: {node: '>=8'} 1448 | dependencies: 1449 | has-flag: 4.0.0 1450 | dev: true 1451 | 1452 | /supports-preserve-symlinks-flag/1.0.0: 1453 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1454 | engines: {node: '>= 0.4'} 1455 | dev: true 1456 | 1457 | /temp-dir/2.0.0: 1458 | resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} 1459 | engines: {node: '>=8'} 1460 | dev: true 1461 | 1462 | /terser/5.10.0: 1463 | resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==} 1464 | engines: {node: '>=10'} 1465 | hasBin: true 1466 | peerDependencies: 1467 | acorn: ^8.5.0 1468 | peerDependenciesMeta: 1469 | acorn: 1470 | optional: true 1471 | dependencies: 1472 | commander: 2.20.3 1473 | source-map: 0.7.3 1474 | source-map-support: 0.5.21 1475 | dev: true 1476 | 1477 | /time-zone/1.0.0: 1478 | resolution: {integrity: sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=} 1479 | engines: {node: '>=4'} 1480 | dev: true 1481 | 1482 | /to-regex-range/5.0.1: 1483 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1484 | engines: {node: '>=8.0'} 1485 | dependencies: 1486 | is-number: 7.0.0 1487 | dev: true 1488 | 1489 | /type-fest/0.13.1: 1490 | resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} 1491 | engines: {node: '>=10'} 1492 | dev: true 1493 | 1494 | /typedarray-to-buffer/3.1.5: 1495 | resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} 1496 | dependencies: 1497 | is-typedarray: 1.0.0 1498 | dev: true 1499 | 1500 | /typescript/4.5.4: 1501 | resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==} 1502 | engines: {node: '>=4.2.0'} 1503 | hasBin: true 1504 | dev: true 1505 | 1506 | /well-known-symbols/2.0.0: 1507 | resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} 1508 | engines: {node: '>=6'} 1509 | dev: true 1510 | 1511 | /wrap-ansi/7.0.0: 1512 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1513 | engines: {node: '>=10'} 1514 | dependencies: 1515 | ansi-styles: 4.3.0 1516 | string-width: 4.2.3 1517 | strip-ansi: 6.0.1 1518 | dev: true 1519 | 1520 | /wrappy/1.0.2: 1521 | resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} 1522 | dev: true 1523 | 1524 | /write-file-atomic/3.0.3: 1525 | resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} 1526 | dependencies: 1527 | imurmurhash: 0.1.4 1528 | is-typedarray: 1.0.0 1529 | signal-exit: 3.0.6 1530 | typedarray-to-buffer: 3.1.5 1531 | dev: true 1532 | 1533 | /y18n/5.0.8: 1534 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 1535 | engines: {node: '>=10'} 1536 | dev: true 1537 | 1538 | /yallist/4.0.0: 1539 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1540 | dev: true 1541 | 1542 | /yargs-parser/21.0.0: 1543 | resolution: {integrity: sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==} 1544 | engines: {node: '>=12'} 1545 | dev: true 1546 | 1547 | /yargs/17.3.1: 1548 | resolution: {integrity: sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==} 1549 | engines: {node: '>=12'} 1550 | dependencies: 1551 | cliui: 7.0.4 1552 | escalade: 3.1.1 1553 | get-caller-file: 2.0.5 1554 | require-directory: 2.1.1 1555 | string-width: 4.2.3 1556 | y18n: 5.0.8 1557 | yargs-parser: 21.0.0 1558 | dev: true 1559 | 1560 | /yocto-queue/1.0.0: 1561 | resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} 1562 | engines: {node: '>=12.20'} 1563 | dev: true 1564 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/**' 3 | -------------------------------------------------------------------------------- /scripts/bump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | ROOT_DIR="$(dirname $(dirname $0))" 6 | 7 | PACKAGE_NAME="$PNPM_PACKAGE_NAME" 8 | 9 | # It's the package name without "@bitty/" 10 | PACKAGE_DIR_NAME="${PACKAGE_NAME:7}" 11 | 12 | PACKAGE_DIR="$ROOT_DIR/packages/$PACKAGE_DIR_NAME" 13 | 14 | cd $PACKAGE_DIR 15 | 16 | PACKAGE_VERSION="$(node -p 'require("./package.json").version')" 17 | 18 | npm version $1 \ 19 | --commit-hooks false \ 20 | --git-tag-version false 21 | 22 | sleep 2 23 | 24 | git add package.json 25 | 26 | sleep 2 27 | 28 | GIT_DIR="$(git rev-parse --show-toplevel)" 29 | 30 | sleep 2 31 | 32 | if [[ $GIT_DIR == $PACKAGE_DIR ]]; then 33 | git commit -m "🔖 bump to version $PACKAGE_VERSION" 34 | else 35 | git commit -m "🔖 ($PACKAGE_DIR_NAME): bump to version $PACKAGE_VERSION" 36 | fi 37 | 38 | sleep 2 39 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | // Transpile output settings 5 | "target": "ES5", 6 | "module": "ES2015", 7 | "charset": "utf-8", 8 | "newLine": "lf", 9 | "sourceMap": true, 10 | 11 | // Type declaration settings 12 | "declaration": true, 13 | "declarationMap": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Module settings 4 | "allowSyntheticDefaultImports": true, 5 | "esModuleInterop": true, 6 | "moduleResolution": "node", 7 | 8 | // Type-check settings 9 | "alwaysStrict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "importsNotUsedAsValues": "error", 12 | "noFallthroughCasesInSwitch": true, 13 | "noImplicitReturns": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "strict": true, 17 | 18 | // Type declaration settings 19 | "types": [] 20 | } 21 | } 22 | --------------------------------------------------------------------------------