├── .gitattributes ├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── RELEASE.md ├── example-esm ├── .gitignore ├── lib │ ├── animals │ │ ├── bear.mjs │ │ └── lion.mjs │ └── zoo.mjs ├── package-lock.json ├── package.json └── test │ ├── helper.js │ └── lib │ └── zoo-spec.mjs ├── example ├── .gitignore ├── lib │ ├── animals │ │ ├── bear.js │ │ └── lion.js │ └── zoo.js ├── package-lock.json ├── package.json └── test │ ├── helper.js │ └── lib │ └── zoo-spec.js ├── index.d.ts ├── index.js ├── lib ├── canRegisterLoader.js ├── esm-import-functions.js ├── quibble-registered.mjs ├── quibble.js ├── quibble.mjs └── thisWillRunInUserThread.js ├── package-lock.json ├── package.json └── test ├── esm-fixtures ├── a-module-ignored.js ├── a-module-ignored.mjs ├── a-module-with-function.mjs ├── a-module.js ├── a-module.mjs └── b-module.mjs ├── esm-lib ├── quibble-cjs-esmImportWithPath.test.js ├── quibble-cjs.test.js ├── quibble-esm.test.mjs ├── quibble.no-loader-test.js ├── quibble.no-loader-test.mjs ├── supports-auto-load.js └── teenytest-proxy.js ├── fixtures ├── a-function.js ├── a-function.json ├── a-quibble-wrapper.js ├── a-symlinked-function.js ├── b-function.js ├── bomb.js ├── expects-a-quibbling.js ├── node_modules │ └── is-number │ │ ├── index.js │ │ └── package.json ├── quibbles-requires-a-function.js ├── requires-a-function.js └── requires-a-node-module.js ├── helper.js ├── lib ├── a-module-spec.js ├── a-quibble-wrapper-spec.js └── quibble.test.js └── require-smell-test.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | strategy: 16 | matrix: 17 | node-version: [16.x, 18.x, 20.x] 18 | os: [ubuntu-latest, windows-latest] 19 | 20 | runs-on: ${{ matrix.os }} 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: 'npm' 29 | - run: npm ci 30 | - run: npm run test:ci 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | 3 | #ignore node_modules, as the node project is not "deployed" per se: http://www.mikealrogers.com/posts/nodemodules-in-git.html 4 | /node_modules 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | - 10 5 | - 12 6 | - 13 7 | - 14 8 | before_install: npm i -g npm@6 9 | script: npm run test:ci 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.9.2 2 | 3 | * Fix loader stomping on other loaders [#108](https://github.com/testdouble/quibble/pull/108) 4 | 5 | # … 6 | 7 | We failed to update the CHANGELOG much 8 | 9 | # 0.7.0 10 | 11 | Add support for Node 20. [#96](https://github.com/testdouble/quibble/pull/96) 12 | 13 | # 0.6.17 14 | 15 | * Allow proxy as a default export 16 | [#93](https://github.com/testdouble/quibble/pull/93) 17 | 18 | # 0.6.16 19 | 20 | * Improve Windows support 21 | * Update dependencies 22 | 23 | # 0.6.15 24 | 25 | * Make sure the isLoaded state is explicitly set through the NodeJS loader 26 | life-cycle [#80](https://github.com/testdouble/quibble/pull/80) 27 | 28 | # 0.0.1 … 0.6.14 29 | 30 | * Everything 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quibble 2 | 3 | [![Build Status](https://travis-ci.org/testdouble/quibble.svg?branch=main)](https://travis-ci.org/testdouble/quibble) 4 | 5 | Quibble is a terser (and more magical) alternative to packages like 6 | [proxyquire](https://github.com/thlorenz/proxyquire), 7 | [sandboxed-module](https://github.com/felixge/node-sandboxed-module) and 8 | [mockery](https://github.com/mfncooper/mockery) for mocking out dependencies 9 | in tests of Node.js modules. Using `quibble` you can replace 10 | how `require()` will behave for a given path. Its intended use is squarely 11 | focused on unit testing. It is almost-but-not-quite a private dependency of 12 | [testdouble.js](https://github.com/testdouble/testdouble.js), as it 13 | implements the `td.replace()` function's module-replacement behavior. 14 | 15 | ## Usage 16 | 17 | Say we're testing pants: 18 | 19 | ```js 20 | quibble = require('quibble') 21 | 22 | describe('pants', function(){ 23 | var subject, legs; 24 | beforeEach(function(){ 25 | legs = quibble('./../lib/legs', function(){ return 'a leg';}); 26 | 27 | subject = require('./../lib/pants'); 28 | }); 29 | it('contains legs', function() { 30 | expect(subject().left).toContain('a leg') 31 | expect(subject().right).toContain('a leg') 32 | }) 33 | }); 34 | ``` 35 | 36 | That way, when the `subject` loaded from `lib/pants` runs `require('./legs')`, 37 | it will get back the function that returns `'a leg'`. The fake value is also 38 | returned by `quibble`, which makes it easy to set and assign a test double in a 39 | one-liner. 40 | 41 | For more info on how this module is _really_ intended to be used, check out its 42 | inclusion in [testdouble.js](https://github.com/testdouble/testdouble.js/blob/main/docs/7-replacing-dependencies.md#nodejs) 43 | 44 | ## Configuration 45 | 46 | There's only one option: what you want to do with quibbled modules by default. 47 | 48 | Say you're pulling in [testdouble.js](https://github.com/testdouble/testdouble.js) 49 | and you want every quibbled module to default to a single test double function with 50 | a name that matches its absolute path. You could do this: 51 | 52 | ```js 53 | quibble = require('quibble') 54 | beforeEach(function(){ 55 | quibble.config({ 56 | defaultFakeCreator: function(path) { 57 | return require('testdouble').create(path); 58 | } 59 | }); 60 | }); 61 | ``` 62 | 63 | With this set up, running `quibble('./some/path')` will default to replacing all 64 | `require('../anything/that/matches/some/path')` invocations with a test double named 65 | after the absolute path resolved to by `'./some/path'`. 66 | 67 | Spiffy! 68 | 69 | > Note: `defaultFakeCreator` is not supported for ES Module stubbing 70 | 71 | ## ES Modules support 72 | 73 | Quibble supports ES Modules. Quibble implements ES module support using [ES Module 74 | Loaders](https://nodejs.org/api/esm.html#esm_experimental_loaders) which are the official way to 75 | "patch" Node.js' module loading mechanism for ESM. 76 | 77 | > Note that Loader support is currently experimental and unstable. We are doing our best 78 | to track the changes in the specification for the upcoming Node.js versions. 79 | 80 | If you're running a Node.js version smaller than v20.6.0, you must run Node with the `quibble` package as a loader: 81 | 82 | ```sh 83 | node --loader=quibble ... 84 | ``` 85 | 86 | Most test runners allow you to specify this in their command line, e.g. for Mocha: 87 | 88 | ```sh 89 | mocha --loader=quibble ... 90 | ``` 91 | 92 | The `quibble` loader will enable the replacement of the ES modules with the stubs you specify, and 93 | without it, the stubbing will be ignored. 94 | 95 | For versions larger or equal to v20.6.0, there is no need to specify a `--loader`, as registering the loader 96 | happens automatically once you use the API. 97 | 98 | ### Restrictions on ESM 99 | 100 | * `defaultFakeCreator` is not yet supported. 101 | 102 | ### `quibble` ESM API 103 | 104 | The API is similar to the CommonJS API, but uses `quibble.esm` function, and is async: 105 | 106 | ```js 107 | // a-module.mjs (ESM) 108 | export const life = 42; 109 | export default 'universe'; 110 | 111 | // uses-a-module.mjs 112 | import universe, {life} from './a-module.mjs'; 113 | 114 | console.log(life, universe); 115 | 116 | (async function () { 117 | await quibble.esm('./a-module.mjs', {life: 41}, 'replacement universe'); 118 | 119 | await import('./uses-some-module.mjs'); 120 | // ==> logs: 41, replacement universe 121 | })(); 122 | ``` 123 | 124 | The parameters to be given to `quibble.esm` for ESM modules are: 125 | 126 | 1. the module path: similar to CommonJS, the path is relative to the directory you are in. It is 127 | resolved the ESM way, so if you're using a relative path, you must specify the filename, 128 | including the extension. 129 | 2. the named export stubs: either null/undefied or an object with each property 130 | having key corresponding to export names and value being the implementation 131 | to use. To define the `default` export you can either define a `default` 132 | property here or use the third argument, but not both at same time. 133 | 3. the default export stub: if named export stubs does not contain a `default` 134 | key, you can define the default stub with this argument. 135 | 136 | Note that `quibble.reset` works the same as for CommonJS modules 137 | 138 | ESM support also exposes the function `quibble.esmImportWithPath` which both imports a module and 139 | resolves the path to the module that is the package's entry point: 140 | 141 | * `async quibble.esmImportWithPath(importPath)`: imports a module, just like `import(importPath)`, 142 | but returns an object with two properties: 143 | * `module`: the module returned by `await import(importPath)`. 144 | * `modulePath`: the full path to the module (file) that is the entry point to the package/module. 145 | 146 | > Note that when mocking internal Node.js modules (e.g. "[fs](https://nodejs.org/api/fs.html)")), you need to mock the named exports both as named exports and as properties in the default export, because Node.js exports internal modules both as named exports and as a default object. Example: 147 | 148 | ```js 149 | const fsExports = { 150 | readFileSync: function (path) { 151 | console.log("using quibbled readFileSyns... yay!"); 152 | return "Looks like 'fs' was replaced correctly."; 153 | }, 154 | } 155 | await quibble.esm("fs", fsExports, fsExports); 156 | ``` 157 | 158 | ## How's it different? 159 | 160 | A few things that stand out about quibble: 161 | 162 | 1. No partial mocking, as proxyquire does. [Partial Mocks](https://github.com/testdouble/contributing-tests/wiki/Partial-Mock) 163 | are often seen problematic and not helpful for unit testing designed to create clear boundaries 164 | between the SUT and its dependencies 165 | 2. Global replacements, so it's easy to set up a few arrange steps in advance of 166 | instantiating your subject (using `require` just as you normally would). The instantiation 167 | style of other libs is a little different (e.g. `require('./my/subject', {'/this/thing': stub})` 168 | 3. Require strings are resolved to absolute paths. It can be a bit confusing using other tools because from the perspective of the test particular paths are knocked out _from the perspective of the subject_ and not from the test listing, which runs counter to how every other Node.js API works. Instead, here, the path of the file being knocked out is relative to whoever is knocking it out. 169 | 4. A configurable default faker function. This lib was written to support the [testdouble.js](https://github.com/testdouble/testdouble.js) feature [td.replace()](https://github.com/testdouble/testdouble.js/blob/main/docs/7-replacing-dependencies.md#nodejs), in an effort to reduce the amount of per-test friction to repetitively create & pass in test doubles 170 | 5. A `reset()` method that undoes everything, intended to be run `afterEach` test runs 171 | 172 | 173 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Cutting Releases 2 | 3 | To cut a new release, first make sure the git working directory is clear and 4 | then ensure the full suite of tests are passing: 5 | 6 | ``` 7 | $ npm run test:ci 8 | ``` 9 | 10 | We use some `preversion` and `postversion` script hooks to automate git & npm 11 | pushing (and another round of testing), so to bump version and publish in one 12 | go: 13 | 14 | ``` 15 | $ npm version patch 16 | ``` 17 | 18 | Same goes for `npm version minor` and `major`, naturally. 19 | -------------------------------------------------------------------------------- /example-esm/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /example-esm/lib/animals/bear.mjs: -------------------------------------------------------------------------------- 1 | export default function () { return 'a real bear' } 2 | -------------------------------------------------------------------------------- /example-esm/lib/animals/lion.mjs: -------------------------------------------------------------------------------- 1 | export default function () { return 'a real lion' } 2 | -------------------------------------------------------------------------------- /example-esm/lib/zoo.mjs: -------------------------------------------------------------------------------- 1 | import lion from './animals/lion.mjs' 2 | import bear from './animals/bear.mjs' 3 | 4 | export default function () { 5 | return { 6 | animals: [ 7 | lion(), 8 | bear() 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example-esm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quibble-example", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "quibble-example", 8 | "devDependencies": { 9 | "chai": "^4.3.7", 10 | "mocha": "^10.2.0", 11 | "quibble": "file:.." 12 | } 13 | }, 14 | "..": { 15 | "version": "0.9.0", 16 | "dev": true, 17 | "license": "MIT", 18 | "dependencies": { 19 | "lodash": "^4.17.21", 20 | "resolve": "^1.22.8" 21 | }, 22 | "devDependencies": { 23 | "core-assert": "^1.0.0", 24 | "is-number": "^7.0.0", 25 | "is-promise": "^4.0.0", 26 | "standard": "^17.1.0", 27 | "teenytest": "^6.0.5", 28 | "teenytest-promise": "^1.0.0" 29 | }, 30 | "engines": { 31 | "node": ">= 0.14.0" 32 | } 33 | }, 34 | "node_modules/ansi-colors": { 35 | "version": "4.1.1", 36 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 37 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 38 | "dev": true, 39 | "engines": { 40 | "node": ">=6" 41 | } 42 | }, 43 | "node_modules/ansi-regex": { 44 | "version": "5.0.1", 45 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 46 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 47 | "dev": true, 48 | "engines": { 49 | "node": ">=8" 50 | } 51 | }, 52 | "node_modules/ansi-styles": { 53 | "version": "4.3.0", 54 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 55 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 56 | "dev": true, 57 | "dependencies": { 58 | "color-convert": "^2.0.1" 59 | }, 60 | "engines": { 61 | "node": ">=8" 62 | }, 63 | "funding": { 64 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 65 | } 66 | }, 67 | "node_modules/anymatch": { 68 | "version": "3.1.3", 69 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 70 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 71 | "dev": true, 72 | "dependencies": { 73 | "normalize-path": "^3.0.0", 74 | "picomatch": "^2.0.4" 75 | }, 76 | "engines": { 77 | "node": ">= 8" 78 | } 79 | }, 80 | "node_modules/argparse": { 81 | "version": "2.0.1", 82 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 83 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 84 | "dev": true 85 | }, 86 | "node_modules/assertion-error": { 87 | "version": "1.1.0", 88 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 89 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 90 | "dev": true, 91 | "engines": { 92 | "node": "*" 93 | } 94 | }, 95 | "node_modules/balanced-match": { 96 | "version": "1.0.2", 97 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 98 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 99 | "dev": true 100 | }, 101 | "node_modules/binary-extensions": { 102 | "version": "2.2.0", 103 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 104 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 105 | "dev": true, 106 | "engines": { 107 | "node": ">=8" 108 | } 109 | }, 110 | "node_modules/brace-expansion": { 111 | "version": "2.0.1", 112 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 113 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 114 | "dev": true, 115 | "dependencies": { 116 | "balanced-match": "^1.0.0" 117 | } 118 | }, 119 | "node_modules/braces": { 120 | "version": "3.0.2", 121 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 122 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 123 | "dev": true, 124 | "dependencies": { 125 | "fill-range": "^7.0.1" 126 | }, 127 | "engines": { 128 | "node": ">=8" 129 | } 130 | }, 131 | "node_modules/browser-stdout": { 132 | "version": "1.3.1", 133 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 134 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 135 | "dev": true 136 | }, 137 | "node_modules/camelcase": { 138 | "version": "6.3.0", 139 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 140 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 141 | "dev": true, 142 | "engines": { 143 | "node": ">=10" 144 | }, 145 | "funding": { 146 | "url": "https://github.com/sponsors/sindresorhus" 147 | } 148 | }, 149 | "node_modules/chai": { 150 | "version": "4.3.7", 151 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", 152 | "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", 153 | "dev": true, 154 | "dependencies": { 155 | "assertion-error": "^1.1.0", 156 | "check-error": "^1.0.2", 157 | "deep-eql": "^4.1.2", 158 | "get-func-name": "^2.0.0", 159 | "loupe": "^2.3.1", 160 | "pathval": "^1.1.1", 161 | "type-detect": "^4.0.5" 162 | }, 163 | "engines": { 164 | "node": ">=4" 165 | } 166 | }, 167 | "node_modules/chalk": { 168 | "version": "4.1.2", 169 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 170 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 171 | "dev": true, 172 | "dependencies": { 173 | "ansi-styles": "^4.1.0", 174 | "supports-color": "^7.1.0" 175 | }, 176 | "engines": { 177 | "node": ">=10" 178 | }, 179 | "funding": { 180 | "url": "https://github.com/chalk/chalk?sponsor=1" 181 | } 182 | }, 183 | "node_modules/chalk/node_modules/supports-color": { 184 | "version": "7.2.0", 185 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 186 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 187 | "dev": true, 188 | "dependencies": { 189 | "has-flag": "^4.0.0" 190 | }, 191 | "engines": { 192 | "node": ">=8" 193 | } 194 | }, 195 | "node_modules/check-error": { 196 | "version": "1.0.2", 197 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 198 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 199 | "dev": true, 200 | "engines": { 201 | "node": "*" 202 | } 203 | }, 204 | "node_modules/chokidar": { 205 | "version": "3.5.3", 206 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 207 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 208 | "dev": true, 209 | "funding": [ 210 | { 211 | "type": "individual", 212 | "url": "https://paulmillr.com/funding/" 213 | } 214 | ], 215 | "dependencies": { 216 | "anymatch": "~3.1.2", 217 | "braces": "~3.0.2", 218 | "glob-parent": "~5.1.2", 219 | "is-binary-path": "~2.1.0", 220 | "is-glob": "~4.0.1", 221 | "normalize-path": "~3.0.0", 222 | "readdirp": "~3.6.0" 223 | }, 224 | "engines": { 225 | "node": ">= 8.10.0" 226 | }, 227 | "optionalDependencies": { 228 | "fsevents": "~2.3.2" 229 | } 230 | }, 231 | "node_modules/cliui": { 232 | "version": "7.0.4", 233 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 234 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 235 | "dev": true, 236 | "dependencies": { 237 | "string-width": "^4.2.0", 238 | "strip-ansi": "^6.0.0", 239 | "wrap-ansi": "^7.0.0" 240 | } 241 | }, 242 | "node_modules/color-convert": { 243 | "version": "2.0.1", 244 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 245 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 246 | "dev": true, 247 | "dependencies": { 248 | "color-name": "~1.1.4" 249 | }, 250 | "engines": { 251 | "node": ">=7.0.0" 252 | } 253 | }, 254 | "node_modules/color-name": { 255 | "version": "1.1.4", 256 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 257 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 258 | "dev": true 259 | }, 260 | "node_modules/concat-map": { 261 | "version": "0.0.1", 262 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 263 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 264 | "dev": true 265 | }, 266 | "node_modules/debug": { 267 | "version": "4.3.4", 268 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 269 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 270 | "dev": true, 271 | "dependencies": { 272 | "ms": "2.1.2" 273 | }, 274 | "engines": { 275 | "node": ">=6.0" 276 | }, 277 | "peerDependenciesMeta": { 278 | "supports-color": { 279 | "optional": true 280 | } 281 | } 282 | }, 283 | "node_modules/debug/node_modules/ms": { 284 | "version": "2.1.2", 285 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 286 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 287 | "dev": true 288 | }, 289 | "node_modules/decamelize": { 290 | "version": "4.0.0", 291 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 292 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 293 | "dev": true, 294 | "engines": { 295 | "node": ">=10" 296 | }, 297 | "funding": { 298 | "url": "https://github.com/sponsors/sindresorhus" 299 | } 300 | }, 301 | "node_modules/deep-eql": { 302 | "version": "4.1.3", 303 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", 304 | "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", 305 | "dev": true, 306 | "dependencies": { 307 | "type-detect": "^4.0.0" 308 | }, 309 | "engines": { 310 | "node": ">=6" 311 | } 312 | }, 313 | "node_modules/diff": { 314 | "version": "5.0.0", 315 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 316 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 317 | "dev": true, 318 | "engines": { 319 | "node": ">=0.3.1" 320 | } 321 | }, 322 | "node_modules/emoji-regex": { 323 | "version": "8.0.0", 324 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 325 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 326 | "dev": true 327 | }, 328 | "node_modules/escalade": { 329 | "version": "3.1.1", 330 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 331 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 332 | "dev": true, 333 | "engines": { 334 | "node": ">=6" 335 | } 336 | }, 337 | "node_modules/escape-string-regexp": { 338 | "version": "4.0.0", 339 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 340 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 341 | "dev": true, 342 | "engines": { 343 | "node": ">=10" 344 | }, 345 | "funding": { 346 | "url": "https://github.com/sponsors/sindresorhus" 347 | } 348 | }, 349 | "node_modules/fill-range": { 350 | "version": "7.0.1", 351 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 352 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 353 | "dev": true, 354 | "dependencies": { 355 | "to-regex-range": "^5.0.1" 356 | }, 357 | "engines": { 358 | "node": ">=8" 359 | } 360 | }, 361 | "node_modules/find-up": { 362 | "version": "5.0.0", 363 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 364 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 365 | "dev": true, 366 | "dependencies": { 367 | "locate-path": "^6.0.0", 368 | "path-exists": "^4.0.0" 369 | }, 370 | "engines": { 371 | "node": ">=10" 372 | }, 373 | "funding": { 374 | "url": "https://github.com/sponsors/sindresorhus" 375 | } 376 | }, 377 | "node_modules/flat": { 378 | "version": "5.0.2", 379 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 380 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 381 | "dev": true, 382 | "bin": { 383 | "flat": "cli.js" 384 | } 385 | }, 386 | "node_modules/fs.realpath": { 387 | "version": "1.0.0", 388 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 389 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 390 | "dev": true 391 | }, 392 | "node_modules/fsevents": { 393 | "version": "2.3.2", 394 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 395 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 396 | "dev": true, 397 | "hasInstallScript": true, 398 | "optional": true, 399 | "os": [ 400 | "darwin" 401 | ], 402 | "engines": { 403 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 404 | } 405 | }, 406 | "node_modules/get-caller-file": { 407 | "version": "2.0.5", 408 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 409 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 410 | "dev": true, 411 | "engines": { 412 | "node": "6.* || 8.* || >= 10.*" 413 | } 414 | }, 415 | "node_modules/get-func-name": { 416 | "version": "2.0.0", 417 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 418 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 419 | "dev": true, 420 | "engines": { 421 | "node": "*" 422 | } 423 | }, 424 | "node_modules/glob": { 425 | "version": "7.2.0", 426 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 427 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 428 | "dev": true, 429 | "dependencies": { 430 | "fs.realpath": "^1.0.0", 431 | "inflight": "^1.0.4", 432 | "inherits": "2", 433 | "minimatch": "^3.0.4", 434 | "once": "^1.3.0", 435 | "path-is-absolute": "^1.0.0" 436 | }, 437 | "engines": { 438 | "node": "*" 439 | }, 440 | "funding": { 441 | "url": "https://github.com/sponsors/isaacs" 442 | } 443 | }, 444 | "node_modules/glob-parent": { 445 | "version": "5.1.2", 446 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 447 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 448 | "dev": true, 449 | "dependencies": { 450 | "is-glob": "^4.0.1" 451 | }, 452 | "engines": { 453 | "node": ">= 6" 454 | } 455 | }, 456 | "node_modules/glob/node_modules/brace-expansion": { 457 | "version": "1.1.11", 458 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 459 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 460 | "dev": true, 461 | "dependencies": { 462 | "balanced-match": "^1.0.0", 463 | "concat-map": "0.0.1" 464 | } 465 | }, 466 | "node_modules/glob/node_modules/minimatch": { 467 | "version": "3.1.2", 468 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 469 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 470 | "dev": true, 471 | "dependencies": { 472 | "brace-expansion": "^1.1.7" 473 | }, 474 | "engines": { 475 | "node": "*" 476 | } 477 | }, 478 | "node_modules/has-flag": { 479 | "version": "4.0.0", 480 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 481 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 482 | "dev": true, 483 | "engines": { 484 | "node": ">=8" 485 | } 486 | }, 487 | "node_modules/he": { 488 | "version": "1.2.0", 489 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 490 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 491 | "dev": true, 492 | "bin": { 493 | "he": "bin/he" 494 | } 495 | }, 496 | "node_modules/inflight": { 497 | "version": "1.0.6", 498 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 499 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 500 | "dev": true, 501 | "dependencies": { 502 | "once": "^1.3.0", 503 | "wrappy": "1" 504 | } 505 | }, 506 | "node_modules/inherits": { 507 | "version": "2.0.4", 508 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 509 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 510 | "dev": true 511 | }, 512 | "node_modules/is-binary-path": { 513 | "version": "2.1.0", 514 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 515 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 516 | "dev": true, 517 | "dependencies": { 518 | "binary-extensions": "^2.0.0" 519 | }, 520 | "engines": { 521 | "node": ">=8" 522 | } 523 | }, 524 | "node_modules/is-extglob": { 525 | "version": "2.1.1", 526 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 527 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 528 | "dev": true, 529 | "engines": { 530 | "node": ">=0.10.0" 531 | } 532 | }, 533 | "node_modules/is-fullwidth-code-point": { 534 | "version": "3.0.0", 535 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 536 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 537 | "dev": true, 538 | "engines": { 539 | "node": ">=8" 540 | } 541 | }, 542 | "node_modules/is-glob": { 543 | "version": "4.0.3", 544 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 545 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 546 | "dev": true, 547 | "dependencies": { 548 | "is-extglob": "^2.1.1" 549 | }, 550 | "engines": { 551 | "node": ">=0.10.0" 552 | } 553 | }, 554 | "node_modules/is-number": { 555 | "version": "7.0.0", 556 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 557 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 558 | "dev": true, 559 | "engines": { 560 | "node": ">=0.12.0" 561 | } 562 | }, 563 | "node_modules/is-plain-obj": { 564 | "version": "2.1.0", 565 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 566 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 567 | "dev": true, 568 | "engines": { 569 | "node": ">=8" 570 | } 571 | }, 572 | "node_modules/is-unicode-supported": { 573 | "version": "0.1.0", 574 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 575 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 576 | "dev": true, 577 | "engines": { 578 | "node": ">=10" 579 | }, 580 | "funding": { 581 | "url": "https://github.com/sponsors/sindresorhus" 582 | } 583 | }, 584 | "node_modules/js-yaml": { 585 | "version": "4.1.0", 586 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 587 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 588 | "dev": true, 589 | "dependencies": { 590 | "argparse": "^2.0.1" 591 | }, 592 | "bin": { 593 | "js-yaml": "bin/js-yaml.js" 594 | } 595 | }, 596 | "node_modules/locate-path": { 597 | "version": "6.0.0", 598 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 599 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 600 | "dev": true, 601 | "dependencies": { 602 | "p-locate": "^5.0.0" 603 | }, 604 | "engines": { 605 | "node": ">=10" 606 | }, 607 | "funding": { 608 | "url": "https://github.com/sponsors/sindresorhus" 609 | } 610 | }, 611 | "node_modules/log-symbols": { 612 | "version": "4.1.0", 613 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 614 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 615 | "dev": true, 616 | "dependencies": { 617 | "chalk": "^4.1.0", 618 | "is-unicode-supported": "^0.1.0" 619 | }, 620 | "engines": { 621 | "node": ">=10" 622 | }, 623 | "funding": { 624 | "url": "https://github.com/sponsors/sindresorhus" 625 | } 626 | }, 627 | "node_modules/loupe": { 628 | "version": "2.3.6", 629 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", 630 | "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", 631 | "dev": true, 632 | "dependencies": { 633 | "get-func-name": "^2.0.0" 634 | } 635 | }, 636 | "node_modules/minimatch": { 637 | "version": "5.0.1", 638 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 639 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 640 | "dev": true, 641 | "dependencies": { 642 | "brace-expansion": "^2.0.1" 643 | }, 644 | "engines": { 645 | "node": ">=10" 646 | } 647 | }, 648 | "node_modules/mocha": { 649 | "version": "10.2.0", 650 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", 651 | "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", 652 | "dev": true, 653 | "dependencies": { 654 | "ansi-colors": "4.1.1", 655 | "browser-stdout": "1.3.1", 656 | "chokidar": "3.5.3", 657 | "debug": "4.3.4", 658 | "diff": "5.0.0", 659 | "escape-string-regexp": "4.0.0", 660 | "find-up": "5.0.0", 661 | "glob": "7.2.0", 662 | "he": "1.2.0", 663 | "js-yaml": "4.1.0", 664 | "log-symbols": "4.1.0", 665 | "minimatch": "5.0.1", 666 | "ms": "2.1.3", 667 | "nanoid": "3.3.3", 668 | "serialize-javascript": "6.0.0", 669 | "strip-json-comments": "3.1.1", 670 | "supports-color": "8.1.1", 671 | "workerpool": "6.2.1", 672 | "yargs": "16.2.0", 673 | "yargs-parser": "20.2.4", 674 | "yargs-unparser": "2.0.0" 675 | }, 676 | "bin": { 677 | "_mocha": "bin/_mocha", 678 | "mocha": "bin/mocha.js" 679 | }, 680 | "engines": { 681 | "node": ">= 14.0.0" 682 | }, 683 | "funding": { 684 | "type": "opencollective", 685 | "url": "https://opencollective.com/mochajs" 686 | } 687 | }, 688 | "node_modules/ms": { 689 | "version": "2.1.3", 690 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 691 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 692 | "dev": true 693 | }, 694 | "node_modules/nanoid": { 695 | "version": "3.3.3", 696 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", 697 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", 698 | "dev": true, 699 | "bin": { 700 | "nanoid": "bin/nanoid.cjs" 701 | }, 702 | "engines": { 703 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 704 | } 705 | }, 706 | "node_modules/normalize-path": { 707 | "version": "3.0.0", 708 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 709 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 710 | "dev": true, 711 | "engines": { 712 | "node": ">=0.10.0" 713 | } 714 | }, 715 | "node_modules/once": { 716 | "version": "1.4.0", 717 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 718 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 719 | "dev": true, 720 | "dependencies": { 721 | "wrappy": "1" 722 | } 723 | }, 724 | "node_modules/p-limit": { 725 | "version": "3.1.0", 726 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 727 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 728 | "dev": true, 729 | "dependencies": { 730 | "yocto-queue": "^0.1.0" 731 | }, 732 | "engines": { 733 | "node": ">=10" 734 | }, 735 | "funding": { 736 | "url": "https://github.com/sponsors/sindresorhus" 737 | } 738 | }, 739 | "node_modules/p-locate": { 740 | "version": "5.0.0", 741 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 742 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 743 | "dev": true, 744 | "dependencies": { 745 | "p-limit": "^3.0.2" 746 | }, 747 | "engines": { 748 | "node": ">=10" 749 | }, 750 | "funding": { 751 | "url": "https://github.com/sponsors/sindresorhus" 752 | } 753 | }, 754 | "node_modules/path-exists": { 755 | "version": "4.0.0", 756 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 757 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 758 | "dev": true, 759 | "engines": { 760 | "node": ">=8" 761 | } 762 | }, 763 | "node_modules/path-is-absolute": { 764 | "version": "1.0.1", 765 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 766 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 767 | "dev": true, 768 | "engines": { 769 | "node": ">=0.10.0" 770 | } 771 | }, 772 | "node_modules/pathval": { 773 | "version": "1.1.1", 774 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 775 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 776 | "dev": true, 777 | "engines": { 778 | "node": "*" 779 | } 780 | }, 781 | "node_modules/picomatch": { 782 | "version": "2.3.1", 783 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 784 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 785 | "dev": true, 786 | "engines": { 787 | "node": ">=8.6" 788 | }, 789 | "funding": { 790 | "url": "https://github.com/sponsors/jonschlinkert" 791 | } 792 | }, 793 | "node_modules/quibble": { 794 | "resolved": "..", 795 | "link": true 796 | }, 797 | "node_modules/randombytes": { 798 | "version": "2.1.0", 799 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 800 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 801 | "dev": true, 802 | "dependencies": { 803 | "safe-buffer": "^5.1.0" 804 | } 805 | }, 806 | "node_modules/readdirp": { 807 | "version": "3.6.0", 808 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 809 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 810 | "dev": true, 811 | "dependencies": { 812 | "picomatch": "^2.2.1" 813 | }, 814 | "engines": { 815 | "node": ">=8.10.0" 816 | } 817 | }, 818 | "node_modules/require-directory": { 819 | "version": "2.1.1", 820 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 821 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 822 | "dev": true, 823 | "engines": { 824 | "node": ">=0.10.0" 825 | } 826 | }, 827 | "node_modules/safe-buffer": { 828 | "version": "5.2.1", 829 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 830 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 831 | "dev": true, 832 | "funding": [ 833 | { 834 | "type": "github", 835 | "url": "https://github.com/sponsors/feross" 836 | }, 837 | { 838 | "type": "patreon", 839 | "url": "https://www.patreon.com/feross" 840 | }, 841 | { 842 | "type": "consulting", 843 | "url": "https://feross.org/support" 844 | } 845 | ] 846 | }, 847 | "node_modules/serialize-javascript": { 848 | "version": "6.0.0", 849 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 850 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 851 | "dev": true, 852 | "dependencies": { 853 | "randombytes": "^2.1.0" 854 | } 855 | }, 856 | "node_modules/string-width": { 857 | "version": "4.2.3", 858 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 859 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 860 | "dev": true, 861 | "dependencies": { 862 | "emoji-regex": "^8.0.0", 863 | "is-fullwidth-code-point": "^3.0.0", 864 | "strip-ansi": "^6.0.1" 865 | }, 866 | "engines": { 867 | "node": ">=8" 868 | } 869 | }, 870 | "node_modules/strip-ansi": { 871 | "version": "6.0.1", 872 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 873 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 874 | "dev": true, 875 | "dependencies": { 876 | "ansi-regex": "^5.0.1" 877 | }, 878 | "engines": { 879 | "node": ">=8" 880 | } 881 | }, 882 | "node_modules/strip-json-comments": { 883 | "version": "3.1.1", 884 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 885 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 886 | "dev": true, 887 | "engines": { 888 | "node": ">=8" 889 | }, 890 | "funding": { 891 | "url": "https://github.com/sponsors/sindresorhus" 892 | } 893 | }, 894 | "node_modules/supports-color": { 895 | "version": "8.1.1", 896 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 897 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 898 | "dev": true, 899 | "dependencies": { 900 | "has-flag": "^4.0.0" 901 | }, 902 | "engines": { 903 | "node": ">=10" 904 | }, 905 | "funding": { 906 | "url": "https://github.com/chalk/supports-color?sponsor=1" 907 | } 908 | }, 909 | "node_modules/to-regex-range": { 910 | "version": "5.0.1", 911 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 912 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 913 | "dev": true, 914 | "dependencies": { 915 | "is-number": "^7.0.0" 916 | }, 917 | "engines": { 918 | "node": ">=8.0" 919 | } 920 | }, 921 | "node_modules/type-detect": { 922 | "version": "4.0.8", 923 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 924 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 925 | "dev": true, 926 | "engines": { 927 | "node": ">=4" 928 | } 929 | }, 930 | "node_modules/workerpool": { 931 | "version": "6.2.1", 932 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 933 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 934 | "dev": true 935 | }, 936 | "node_modules/wrap-ansi": { 937 | "version": "7.0.0", 938 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 939 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 940 | "dev": true, 941 | "dependencies": { 942 | "ansi-styles": "^4.0.0", 943 | "string-width": "^4.1.0", 944 | "strip-ansi": "^6.0.0" 945 | }, 946 | "engines": { 947 | "node": ">=10" 948 | }, 949 | "funding": { 950 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 951 | } 952 | }, 953 | "node_modules/wrappy": { 954 | "version": "1.0.2", 955 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 956 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 957 | "dev": true 958 | }, 959 | "node_modules/y18n": { 960 | "version": "5.0.8", 961 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 962 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 963 | "dev": true, 964 | "engines": { 965 | "node": ">=10" 966 | } 967 | }, 968 | "node_modules/yargs": { 969 | "version": "16.2.0", 970 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 971 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 972 | "dev": true, 973 | "dependencies": { 974 | "cliui": "^7.0.2", 975 | "escalade": "^3.1.1", 976 | "get-caller-file": "^2.0.5", 977 | "require-directory": "^2.1.1", 978 | "string-width": "^4.2.0", 979 | "y18n": "^5.0.5", 980 | "yargs-parser": "^20.2.2" 981 | }, 982 | "engines": { 983 | "node": ">=10" 984 | } 985 | }, 986 | "node_modules/yargs-parser": { 987 | "version": "20.2.4", 988 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 989 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 990 | "dev": true, 991 | "engines": { 992 | "node": ">=10" 993 | } 994 | }, 995 | "node_modules/yargs-unparser": { 996 | "version": "2.0.0", 997 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 998 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 999 | "dev": true, 1000 | "dependencies": { 1001 | "camelcase": "^6.0.0", 1002 | "decamelize": "^4.0.0", 1003 | "flat": "^5.0.2", 1004 | "is-plain-obj": "^2.1.0" 1005 | }, 1006 | "engines": { 1007 | "node": ">=10" 1008 | } 1009 | }, 1010 | "node_modules/yocto-queue": { 1011 | "version": "0.1.0", 1012 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1013 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1014 | "dev": true, 1015 | "engines": { 1016 | "node": ">=10" 1017 | }, 1018 | "funding": { 1019 | "url": "https://github.com/sponsors/sindresorhus" 1020 | } 1021 | } 1022 | } 1023 | } 1024 | -------------------------------------------------------------------------------- /example-esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quibble-example", 3 | "private": true, 4 | "scripts": { 5 | "test": "mocha --loader=quibble test/helper.js --recursive test/lib/", 6 | "test-auto-loader": "mocha test/helper.js --recursive test/lib/" 7 | }, 8 | "devDependencies": { 9 | "chai": "^4.3.7", 10 | "mocha": "^10.2.0", 11 | "quibble": "file:.." 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example-esm/test/helper.js: -------------------------------------------------------------------------------- 1 | const { beforeEach, afterEach } = require('mocha') 2 | const quibble = require('quibble') 3 | 4 | beforeEach(async function () { 5 | await quibble.esm('../lib/animals/bear.mjs', undefined, function () { return 'a fake bear' }) 6 | await quibble.esm('../lib/animals/lion.mjs', { default: function () { return 'a fake lion' }}) 7 | }) 8 | 9 | afterEach(function () { 10 | quibble.reset() 11 | }) 12 | -------------------------------------------------------------------------------- /example-esm/test/lib/zoo-spec.mjs: -------------------------------------------------------------------------------- 1 | import chai from 'chai' 2 | import '../../lib/zoo.mjs' // drop the zoo in the cache 3 | 4 | const { expect } = chai 5 | 6 | describe('zoo', function () { 7 | var subject 8 | 9 | beforeEach(async function () { 10 | subject = await import('../../lib/zoo.mjs') 11 | }) 12 | 13 | it('contains a fake bear', function () { 14 | expect(subject.default().animals).to.contain('a fake bear') 15 | }) 16 | 17 | it('contains a fake lion', function () { 18 | expect(subject.default().animals).to.contain('a fake lion') 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /example/lib/animals/bear.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { return 'a real bear' } 2 | -------------------------------------------------------------------------------- /example/lib/animals/lion.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { return 'a real lion' } 2 | -------------------------------------------------------------------------------- /example/lib/zoo.js: -------------------------------------------------------------------------------- 1 | var lion = require('./animals/lion'), 2 | bear = require('./animals/bear') 3 | 4 | module.exports = function () { 5 | return { 6 | animals: [ 7 | lion(), 8 | bear() 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quibble-example", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "quibble-example", 8 | "devDependencies": { 9 | "chai": "^4.3.7", 10 | "mocha": "^10.2.0", 11 | "quibble": "file:.." 12 | } 13 | }, 14 | "..": { 15 | "version": "0.9.0", 16 | "dev": true, 17 | "license": "MIT", 18 | "dependencies": { 19 | "lodash": "^4.17.21", 20 | "resolve": "^1.22.8" 21 | }, 22 | "devDependencies": { 23 | "core-assert": "^1.0.0", 24 | "is-number": "^7.0.0", 25 | "is-promise": "^4.0.0", 26 | "standard": "^17.1.0", 27 | "teenytest": "^6.0.5", 28 | "teenytest-promise": "^1.0.0" 29 | }, 30 | "engines": { 31 | "node": ">= 0.14.0" 32 | } 33 | }, 34 | "node_modules/ansi-colors": { 35 | "version": "4.1.1", 36 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 37 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 38 | "dev": true, 39 | "engines": { 40 | "node": ">=6" 41 | } 42 | }, 43 | "node_modules/ansi-regex": { 44 | "version": "5.0.1", 45 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 46 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 47 | "dev": true, 48 | "engines": { 49 | "node": ">=8" 50 | } 51 | }, 52 | "node_modules/ansi-styles": { 53 | "version": "4.3.0", 54 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 55 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 56 | "dev": true, 57 | "dependencies": { 58 | "color-convert": "^2.0.1" 59 | }, 60 | "engines": { 61 | "node": ">=8" 62 | }, 63 | "funding": { 64 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 65 | } 66 | }, 67 | "node_modules/anymatch": { 68 | "version": "3.1.3", 69 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 70 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 71 | "dev": true, 72 | "dependencies": { 73 | "normalize-path": "^3.0.0", 74 | "picomatch": "^2.0.4" 75 | }, 76 | "engines": { 77 | "node": ">= 8" 78 | } 79 | }, 80 | "node_modules/argparse": { 81 | "version": "2.0.1", 82 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 83 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 84 | "dev": true 85 | }, 86 | "node_modules/assertion-error": { 87 | "version": "1.1.0", 88 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 89 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 90 | "dev": true, 91 | "engines": { 92 | "node": "*" 93 | } 94 | }, 95 | "node_modules/balanced-match": { 96 | "version": "1.0.2", 97 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 98 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 99 | "dev": true 100 | }, 101 | "node_modules/binary-extensions": { 102 | "version": "2.2.0", 103 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 104 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 105 | "dev": true, 106 | "engines": { 107 | "node": ">=8" 108 | } 109 | }, 110 | "node_modules/brace-expansion": { 111 | "version": "2.0.1", 112 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 113 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 114 | "dev": true, 115 | "dependencies": { 116 | "balanced-match": "^1.0.0" 117 | } 118 | }, 119 | "node_modules/braces": { 120 | "version": "3.0.2", 121 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 122 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 123 | "dev": true, 124 | "dependencies": { 125 | "fill-range": "^7.0.1" 126 | }, 127 | "engines": { 128 | "node": ">=8" 129 | } 130 | }, 131 | "node_modules/browser-stdout": { 132 | "version": "1.3.1", 133 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 134 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 135 | "dev": true 136 | }, 137 | "node_modules/camelcase": { 138 | "version": "6.3.0", 139 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 140 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 141 | "dev": true, 142 | "engines": { 143 | "node": ">=10" 144 | }, 145 | "funding": { 146 | "url": "https://github.com/sponsors/sindresorhus" 147 | } 148 | }, 149 | "node_modules/chai": { 150 | "version": "4.3.7", 151 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", 152 | "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", 153 | "dev": true, 154 | "dependencies": { 155 | "assertion-error": "^1.1.0", 156 | "check-error": "^1.0.2", 157 | "deep-eql": "^4.1.2", 158 | "get-func-name": "^2.0.0", 159 | "loupe": "^2.3.1", 160 | "pathval": "^1.1.1", 161 | "type-detect": "^4.0.5" 162 | }, 163 | "engines": { 164 | "node": ">=4" 165 | } 166 | }, 167 | "node_modules/chalk": { 168 | "version": "4.1.2", 169 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 170 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 171 | "dev": true, 172 | "dependencies": { 173 | "ansi-styles": "^4.1.0", 174 | "supports-color": "^7.1.0" 175 | }, 176 | "engines": { 177 | "node": ">=10" 178 | }, 179 | "funding": { 180 | "url": "https://github.com/chalk/chalk?sponsor=1" 181 | } 182 | }, 183 | "node_modules/chalk/node_modules/supports-color": { 184 | "version": "7.2.0", 185 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 186 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 187 | "dev": true, 188 | "dependencies": { 189 | "has-flag": "^4.0.0" 190 | }, 191 | "engines": { 192 | "node": ">=8" 193 | } 194 | }, 195 | "node_modules/check-error": { 196 | "version": "1.0.2", 197 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 198 | "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", 199 | "dev": true, 200 | "engines": { 201 | "node": "*" 202 | } 203 | }, 204 | "node_modules/chokidar": { 205 | "version": "3.5.3", 206 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 207 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 208 | "dev": true, 209 | "funding": [ 210 | { 211 | "type": "individual", 212 | "url": "https://paulmillr.com/funding/" 213 | } 214 | ], 215 | "dependencies": { 216 | "anymatch": "~3.1.2", 217 | "braces": "~3.0.2", 218 | "glob-parent": "~5.1.2", 219 | "is-binary-path": "~2.1.0", 220 | "is-glob": "~4.0.1", 221 | "normalize-path": "~3.0.0", 222 | "readdirp": "~3.6.0" 223 | }, 224 | "engines": { 225 | "node": ">= 8.10.0" 226 | }, 227 | "optionalDependencies": { 228 | "fsevents": "~2.3.2" 229 | } 230 | }, 231 | "node_modules/cliui": { 232 | "version": "7.0.4", 233 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 234 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 235 | "dev": true, 236 | "dependencies": { 237 | "string-width": "^4.2.0", 238 | "strip-ansi": "^6.0.0", 239 | "wrap-ansi": "^7.0.0" 240 | } 241 | }, 242 | "node_modules/color-convert": { 243 | "version": "2.0.1", 244 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 245 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 246 | "dev": true, 247 | "dependencies": { 248 | "color-name": "~1.1.4" 249 | }, 250 | "engines": { 251 | "node": ">=7.0.0" 252 | } 253 | }, 254 | "node_modules/color-name": { 255 | "version": "1.1.4", 256 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 257 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 258 | "dev": true 259 | }, 260 | "node_modules/concat-map": { 261 | "version": "0.0.1", 262 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 263 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 264 | "dev": true 265 | }, 266 | "node_modules/debug": { 267 | "version": "4.3.4", 268 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 269 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 270 | "dev": true, 271 | "dependencies": { 272 | "ms": "2.1.2" 273 | }, 274 | "engines": { 275 | "node": ">=6.0" 276 | }, 277 | "peerDependenciesMeta": { 278 | "supports-color": { 279 | "optional": true 280 | } 281 | } 282 | }, 283 | "node_modules/debug/node_modules/ms": { 284 | "version": "2.1.2", 285 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 286 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 287 | "dev": true 288 | }, 289 | "node_modules/decamelize": { 290 | "version": "4.0.0", 291 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 292 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 293 | "dev": true, 294 | "engines": { 295 | "node": ">=10" 296 | }, 297 | "funding": { 298 | "url": "https://github.com/sponsors/sindresorhus" 299 | } 300 | }, 301 | "node_modules/deep-eql": { 302 | "version": "4.1.3", 303 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", 304 | "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", 305 | "dev": true, 306 | "dependencies": { 307 | "type-detect": "^4.0.0" 308 | }, 309 | "engines": { 310 | "node": ">=6" 311 | } 312 | }, 313 | "node_modules/diff": { 314 | "version": "5.0.0", 315 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 316 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 317 | "dev": true, 318 | "engines": { 319 | "node": ">=0.3.1" 320 | } 321 | }, 322 | "node_modules/emoji-regex": { 323 | "version": "8.0.0", 324 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 325 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 326 | "dev": true 327 | }, 328 | "node_modules/escalade": { 329 | "version": "3.1.1", 330 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 331 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 332 | "dev": true, 333 | "engines": { 334 | "node": ">=6" 335 | } 336 | }, 337 | "node_modules/escape-string-regexp": { 338 | "version": "4.0.0", 339 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 340 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 341 | "dev": true, 342 | "engines": { 343 | "node": ">=10" 344 | }, 345 | "funding": { 346 | "url": "https://github.com/sponsors/sindresorhus" 347 | } 348 | }, 349 | "node_modules/fill-range": { 350 | "version": "7.0.1", 351 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 352 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 353 | "dev": true, 354 | "dependencies": { 355 | "to-regex-range": "^5.0.1" 356 | }, 357 | "engines": { 358 | "node": ">=8" 359 | } 360 | }, 361 | "node_modules/find-up": { 362 | "version": "5.0.0", 363 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 364 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 365 | "dev": true, 366 | "dependencies": { 367 | "locate-path": "^6.0.0", 368 | "path-exists": "^4.0.0" 369 | }, 370 | "engines": { 371 | "node": ">=10" 372 | }, 373 | "funding": { 374 | "url": "https://github.com/sponsors/sindresorhus" 375 | } 376 | }, 377 | "node_modules/flat": { 378 | "version": "5.0.2", 379 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 380 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 381 | "dev": true, 382 | "bin": { 383 | "flat": "cli.js" 384 | } 385 | }, 386 | "node_modules/fs.realpath": { 387 | "version": "1.0.0", 388 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 389 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 390 | "dev": true 391 | }, 392 | "node_modules/fsevents": { 393 | "version": "2.3.2", 394 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 395 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 396 | "dev": true, 397 | "hasInstallScript": true, 398 | "optional": true, 399 | "os": [ 400 | "darwin" 401 | ], 402 | "engines": { 403 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 404 | } 405 | }, 406 | "node_modules/get-caller-file": { 407 | "version": "2.0.5", 408 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 409 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 410 | "dev": true, 411 | "engines": { 412 | "node": "6.* || 8.* || >= 10.*" 413 | } 414 | }, 415 | "node_modules/get-func-name": { 416 | "version": "2.0.0", 417 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 418 | "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", 419 | "dev": true, 420 | "engines": { 421 | "node": "*" 422 | } 423 | }, 424 | "node_modules/glob": { 425 | "version": "7.2.0", 426 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 427 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 428 | "dev": true, 429 | "dependencies": { 430 | "fs.realpath": "^1.0.0", 431 | "inflight": "^1.0.4", 432 | "inherits": "2", 433 | "minimatch": "^3.0.4", 434 | "once": "^1.3.0", 435 | "path-is-absolute": "^1.0.0" 436 | }, 437 | "engines": { 438 | "node": "*" 439 | }, 440 | "funding": { 441 | "url": "https://github.com/sponsors/isaacs" 442 | } 443 | }, 444 | "node_modules/glob-parent": { 445 | "version": "5.1.2", 446 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 447 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 448 | "dev": true, 449 | "dependencies": { 450 | "is-glob": "^4.0.1" 451 | }, 452 | "engines": { 453 | "node": ">= 6" 454 | } 455 | }, 456 | "node_modules/glob/node_modules/brace-expansion": { 457 | "version": "1.1.11", 458 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 459 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 460 | "dev": true, 461 | "dependencies": { 462 | "balanced-match": "^1.0.0", 463 | "concat-map": "0.0.1" 464 | } 465 | }, 466 | "node_modules/glob/node_modules/minimatch": { 467 | "version": "3.1.2", 468 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 469 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 470 | "dev": true, 471 | "dependencies": { 472 | "brace-expansion": "^1.1.7" 473 | }, 474 | "engines": { 475 | "node": "*" 476 | } 477 | }, 478 | "node_modules/has-flag": { 479 | "version": "4.0.0", 480 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 481 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 482 | "dev": true, 483 | "engines": { 484 | "node": ">=8" 485 | } 486 | }, 487 | "node_modules/he": { 488 | "version": "1.2.0", 489 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 490 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 491 | "dev": true, 492 | "bin": { 493 | "he": "bin/he" 494 | } 495 | }, 496 | "node_modules/inflight": { 497 | "version": "1.0.6", 498 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 499 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 500 | "dev": true, 501 | "dependencies": { 502 | "once": "^1.3.0", 503 | "wrappy": "1" 504 | } 505 | }, 506 | "node_modules/inherits": { 507 | "version": "2.0.4", 508 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 509 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 510 | "dev": true 511 | }, 512 | "node_modules/is-binary-path": { 513 | "version": "2.1.0", 514 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 515 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 516 | "dev": true, 517 | "dependencies": { 518 | "binary-extensions": "^2.0.0" 519 | }, 520 | "engines": { 521 | "node": ">=8" 522 | } 523 | }, 524 | "node_modules/is-extglob": { 525 | "version": "2.1.1", 526 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 527 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 528 | "dev": true, 529 | "engines": { 530 | "node": ">=0.10.0" 531 | } 532 | }, 533 | "node_modules/is-fullwidth-code-point": { 534 | "version": "3.0.0", 535 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 536 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 537 | "dev": true, 538 | "engines": { 539 | "node": ">=8" 540 | } 541 | }, 542 | "node_modules/is-glob": { 543 | "version": "4.0.3", 544 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 545 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 546 | "dev": true, 547 | "dependencies": { 548 | "is-extglob": "^2.1.1" 549 | }, 550 | "engines": { 551 | "node": ">=0.10.0" 552 | } 553 | }, 554 | "node_modules/is-number": { 555 | "version": "7.0.0", 556 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 557 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 558 | "dev": true, 559 | "engines": { 560 | "node": ">=0.12.0" 561 | } 562 | }, 563 | "node_modules/is-plain-obj": { 564 | "version": "2.1.0", 565 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 566 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 567 | "dev": true, 568 | "engines": { 569 | "node": ">=8" 570 | } 571 | }, 572 | "node_modules/is-unicode-supported": { 573 | "version": "0.1.0", 574 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 575 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 576 | "dev": true, 577 | "engines": { 578 | "node": ">=10" 579 | }, 580 | "funding": { 581 | "url": "https://github.com/sponsors/sindresorhus" 582 | } 583 | }, 584 | "node_modules/js-yaml": { 585 | "version": "4.1.0", 586 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 587 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 588 | "dev": true, 589 | "dependencies": { 590 | "argparse": "^2.0.1" 591 | }, 592 | "bin": { 593 | "js-yaml": "bin/js-yaml.js" 594 | } 595 | }, 596 | "node_modules/locate-path": { 597 | "version": "6.0.0", 598 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 599 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 600 | "dev": true, 601 | "dependencies": { 602 | "p-locate": "^5.0.0" 603 | }, 604 | "engines": { 605 | "node": ">=10" 606 | }, 607 | "funding": { 608 | "url": "https://github.com/sponsors/sindresorhus" 609 | } 610 | }, 611 | "node_modules/log-symbols": { 612 | "version": "4.1.0", 613 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 614 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 615 | "dev": true, 616 | "dependencies": { 617 | "chalk": "^4.1.0", 618 | "is-unicode-supported": "^0.1.0" 619 | }, 620 | "engines": { 621 | "node": ">=10" 622 | }, 623 | "funding": { 624 | "url": "https://github.com/sponsors/sindresorhus" 625 | } 626 | }, 627 | "node_modules/loupe": { 628 | "version": "2.3.6", 629 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", 630 | "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", 631 | "dev": true, 632 | "dependencies": { 633 | "get-func-name": "^2.0.0" 634 | } 635 | }, 636 | "node_modules/minimatch": { 637 | "version": "5.0.1", 638 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 639 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 640 | "dev": true, 641 | "dependencies": { 642 | "brace-expansion": "^2.0.1" 643 | }, 644 | "engines": { 645 | "node": ">=10" 646 | } 647 | }, 648 | "node_modules/mocha": { 649 | "version": "10.2.0", 650 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", 651 | "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", 652 | "dev": true, 653 | "dependencies": { 654 | "ansi-colors": "4.1.1", 655 | "browser-stdout": "1.3.1", 656 | "chokidar": "3.5.3", 657 | "debug": "4.3.4", 658 | "diff": "5.0.0", 659 | "escape-string-regexp": "4.0.0", 660 | "find-up": "5.0.0", 661 | "glob": "7.2.0", 662 | "he": "1.2.0", 663 | "js-yaml": "4.1.0", 664 | "log-symbols": "4.1.0", 665 | "minimatch": "5.0.1", 666 | "ms": "2.1.3", 667 | "nanoid": "3.3.3", 668 | "serialize-javascript": "6.0.0", 669 | "strip-json-comments": "3.1.1", 670 | "supports-color": "8.1.1", 671 | "workerpool": "6.2.1", 672 | "yargs": "16.2.0", 673 | "yargs-parser": "20.2.4", 674 | "yargs-unparser": "2.0.0" 675 | }, 676 | "bin": { 677 | "_mocha": "bin/_mocha", 678 | "mocha": "bin/mocha.js" 679 | }, 680 | "engines": { 681 | "node": ">= 14.0.0" 682 | }, 683 | "funding": { 684 | "type": "opencollective", 685 | "url": "https://opencollective.com/mochajs" 686 | } 687 | }, 688 | "node_modules/ms": { 689 | "version": "2.1.3", 690 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 691 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 692 | "dev": true 693 | }, 694 | "node_modules/nanoid": { 695 | "version": "3.3.3", 696 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", 697 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", 698 | "dev": true, 699 | "bin": { 700 | "nanoid": "bin/nanoid.cjs" 701 | }, 702 | "engines": { 703 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 704 | } 705 | }, 706 | "node_modules/normalize-path": { 707 | "version": "3.0.0", 708 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 709 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 710 | "dev": true, 711 | "engines": { 712 | "node": ">=0.10.0" 713 | } 714 | }, 715 | "node_modules/once": { 716 | "version": "1.4.0", 717 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 718 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 719 | "dev": true, 720 | "dependencies": { 721 | "wrappy": "1" 722 | } 723 | }, 724 | "node_modules/p-limit": { 725 | "version": "3.1.0", 726 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 727 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 728 | "dev": true, 729 | "dependencies": { 730 | "yocto-queue": "^0.1.0" 731 | }, 732 | "engines": { 733 | "node": ">=10" 734 | }, 735 | "funding": { 736 | "url": "https://github.com/sponsors/sindresorhus" 737 | } 738 | }, 739 | "node_modules/p-locate": { 740 | "version": "5.0.0", 741 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 742 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 743 | "dev": true, 744 | "dependencies": { 745 | "p-limit": "^3.0.2" 746 | }, 747 | "engines": { 748 | "node": ">=10" 749 | }, 750 | "funding": { 751 | "url": "https://github.com/sponsors/sindresorhus" 752 | } 753 | }, 754 | "node_modules/path-exists": { 755 | "version": "4.0.0", 756 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 757 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 758 | "dev": true, 759 | "engines": { 760 | "node": ">=8" 761 | } 762 | }, 763 | "node_modules/path-is-absolute": { 764 | "version": "1.0.1", 765 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 766 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 767 | "dev": true, 768 | "engines": { 769 | "node": ">=0.10.0" 770 | } 771 | }, 772 | "node_modules/pathval": { 773 | "version": "1.1.1", 774 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 775 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 776 | "dev": true, 777 | "engines": { 778 | "node": "*" 779 | } 780 | }, 781 | "node_modules/picomatch": { 782 | "version": "2.3.1", 783 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 784 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 785 | "dev": true, 786 | "engines": { 787 | "node": ">=8.6" 788 | }, 789 | "funding": { 790 | "url": "https://github.com/sponsors/jonschlinkert" 791 | } 792 | }, 793 | "node_modules/quibble": { 794 | "resolved": "..", 795 | "link": true 796 | }, 797 | "node_modules/randombytes": { 798 | "version": "2.1.0", 799 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 800 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 801 | "dev": true, 802 | "dependencies": { 803 | "safe-buffer": "^5.1.0" 804 | } 805 | }, 806 | "node_modules/readdirp": { 807 | "version": "3.6.0", 808 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 809 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 810 | "dev": true, 811 | "dependencies": { 812 | "picomatch": "^2.2.1" 813 | }, 814 | "engines": { 815 | "node": ">=8.10.0" 816 | } 817 | }, 818 | "node_modules/require-directory": { 819 | "version": "2.1.1", 820 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 821 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 822 | "dev": true, 823 | "engines": { 824 | "node": ">=0.10.0" 825 | } 826 | }, 827 | "node_modules/safe-buffer": { 828 | "version": "5.2.1", 829 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 830 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 831 | "dev": true, 832 | "funding": [ 833 | { 834 | "type": "github", 835 | "url": "https://github.com/sponsors/feross" 836 | }, 837 | { 838 | "type": "patreon", 839 | "url": "https://www.patreon.com/feross" 840 | }, 841 | { 842 | "type": "consulting", 843 | "url": "https://feross.org/support" 844 | } 845 | ] 846 | }, 847 | "node_modules/serialize-javascript": { 848 | "version": "6.0.0", 849 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 850 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 851 | "dev": true, 852 | "dependencies": { 853 | "randombytes": "^2.1.0" 854 | } 855 | }, 856 | "node_modules/string-width": { 857 | "version": "4.2.3", 858 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 859 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 860 | "dev": true, 861 | "dependencies": { 862 | "emoji-regex": "^8.0.0", 863 | "is-fullwidth-code-point": "^3.0.0", 864 | "strip-ansi": "^6.0.1" 865 | }, 866 | "engines": { 867 | "node": ">=8" 868 | } 869 | }, 870 | "node_modules/strip-ansi": { 871 | "version": "6.0.1", 872 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 873 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 874 | "dev": true, 875 | "dependencies": { 876 | "ansi-regex": "^5.0.1" 877 | }, 878 | "engines": { 879 | "node": ">=8" 880 | } 881 | }, 882 | "node_modules/strip-json-comments": { 883 | "version": "3.1.1", 884 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 885 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 886 | "dev": true, 887 | "engines": { 888 | "node": ">=8" 889 | }, 890 | "funding": { 891 | "url": "https://github.com/sponsors/sindresorhus" 892 | } 893 | }, 894 | "node_modules/supports-color": { 895 | "version": "8.1.1", 896 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 897 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 898 | "dev": true, 899 | "dependencies": { 900 | "has-flag": "^4.0.0" 901 | }, 902 | "engines": { 903 | "node": ">=10" 904 | }, 905 | "funding": { 906 | "url": "https://github.com/chalk/supports-color?sponsor=1" 907 | } 908 | }, 909 | "node_modules/to-regex-range": { 910 | "version": "5.0.1", 911 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 912 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 913 | "dev": true, 914 | "dependencies": { 915 | "is-number": "^7.0.0" 916 | }, 917 | "engines": { 918 | "node": ">=8.0" 919 | } 920 | }, 921 | "node_modules/type-detect": { 922 | "version": "4.0.8", 923 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 924 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 925 | "dev": true, 926 | "engines": { 927 | "node": ">=4" 928 | } 929 | }, 930 | "node_modules/workerpool": { 931 | "version": "6.2.1", 932 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 933 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 934 | "dev": true 935 | }, 936 | "node_modules/wrap-ansi": { 937 | "version": "7.0.0", 938 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 939 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 940 | "dev": true, 941 | "dependencies": { 942 | "ansi-styles": "^4.0.0", 943 | "string-width": "^4.1.0", 944 | "strip-ansi": "^6.0.0" 945 | }, 946 | "engines": { 947 | "node": ">=10" 948 | }, 949 | "funding": { 950 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 951 | } 952 | }, 953 | "node_modules/wrappy": { 954 | "version": "1.0.2", 955 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 956 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 957 | "dev": true 958 | }, 959 | "node_modules/y18n": { 960 | "version": "5.0.8", 961 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 962 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 963 | "dev": true, 964 | "engines": { 965 | "node": ">=10" 966 | } 967 | }, 968 | "node_modules/yargs": { 969 | "version": "16.2.0", 970 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 971 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 972 | "dev": true, 973 | "dependencies": { 974 | "cliui": "^7.0.2", 975 | "escalade": "^3.1.1", 976 | "get-caller-file": "^2.0.5", 977 | "require-directory": "^2.1.1", 978 | "string-width": "^4.2.0", 979 | "y18n": "^5.0.5", 980 | "yargs-parser": "^20.2.2" 981 | }, 982 | "engines": { 983 | "node": ">=10" 984 | } 985 | }, 986 | "node_modules/yargs-parser": { 987 | "version": "20.2.4", 988 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 989 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 990 | "dev": true, 991 | "engines": { 992 | "node": ">=10" 993 | } 994 | }, 995 | "node_modules/yargs-unparser": { 996 | "version": "2.0.0", 997 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 998 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 999 | "dev": true, 1000 | "dependencies": { 1001 | "camelcase": "^6.0.0", 1002 | "decamelize": "^4.0.0", 1003 | "flat": "^5.0.2", 1004 | "is-plain-obj": "^2.1.0" 1005 | }, 1006 | "engines": { 1007 | "node": ">=10" 1008 | } 1009 | }, 1010 | "node_modules/yocto-queue": { 1011 | "version": "0.1.0", 1012 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1013 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1014 | "dev": true, 1015 | "engines": { 1016 | "node": ">=10" 1017 | }, 1018 | "funding": { 1019 | "url": "https://github.com/sponsors/sindresorhus" 1020 | } 1021 | } 1022 | }, 1023 | "dependencies": { 1024 | "ansi-colors": { 1025 | "version": "4.1.1", 1026 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 1027 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 1028 | "dev": true 1029 | }, 1030 | "ansi-regex": { 1031 | "version": "5.0.1", 1032 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1033 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1034 | "dev": true 1035 | }, 1036 | "ansi-styles": { 1037 | "version": "4.3.0", 1038 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1039 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1040 | "dev": true, 1041 | "requires": { 1042 | "color-convert": "^2.0.1" 1043 | } 1044 | }, 1045 | "anymatch": { 1046 | "version": "3.1.3", 1047 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 1048 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 1049 | "dev": true, 1050 | "requires": { 1051 | "normalize-path": "^3.0.0", 1052 | "picomatch": "^2.0.4" 1053 | } 1054 | }, 1055 | "argparse": { 1056 | "version": "2.0.1", 1057 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1058 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1059 | "dev": true 1060 | }, 1061 | "assertion-error": { 1062 | "version": "1.1.0", 1063 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 1064 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 1065 | "dev": true 1066 | }, 1067 | "balanced-match": { 1068 | "version": "1.0.2", 1069 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1070 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1071 | "dev": true 1072 | }, 1073 | "binary-extensions": { 1074 | "version": "2.2.0", 1075 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 1076 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 1077 | "dev": true 1078 | }, 1079 | "brace-expansion": { 1080 | "version": "2.0.1", 1081 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1082 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1083 | "dev": true, 1084 | "requires": { 1085 | "balanced-match": "^1.0.0" 1086 | } 1087 | }, 1088 | "braces": { 1089 | "version": "3.0.2", 1090 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1091 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1092 | "dev": true, 1093 | "requires": { 1094 | "fill-range": "^7.0.1" 1095 | } 1096 | }, 1097 | "browser-stdout": { 1098 | "version": "1.3.1", 1099 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 1100 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 1101 | "dev": true 1102 | }, 1103 | "camelcase": { 1104 | "version": "6.3.0", 1105 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 1106 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 1107 | "dev": true 1108 | }, 1109 | "chai": { 1110 | "version": "4.3.7", 1111 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", 1112 | "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", 1113 | "dev": true, 1114 | "requires": { 1115 | "assertion-error": "^1.1.0", 1116 | "check-error": "^1.0.2", 1117 | "deep-eql": "^4.1.2", 1118 | "get-func-name": "^2.0.0", 1119 | "loupe": "^2.3.1", 1120 | "pathval": "^1.1.1", 1121 | "type-detect": "^4.0.5" 1122 | } 1123 | }, 1124 | "chalk": { 1125 | "version": "4.1.2", 1126 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1127 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1128 | "dev": true, 1129 | "requires": { 1130 | "ansi-styles": "^4.1.0", 1131 | "supports-color": "^7.1.0" 1132 | }, 1133 | "dependencies": { 1134 | "supports-color": { 1135 | "version": "7.2.0", 1136 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1137 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1138 | "dev": true, 1139 | "requires": { 1140 | "has-flag": "^4.0.0" 1141 | } 1142 | } 1143 | } 1144 | }, 1145 | "check-error": { 1146 | "version": "1.0.2", 1147 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 1148 | "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", 1149 | "dev": true 1150 | }, 1151 | "chokidar": { 1152 | "version": "3.5.3", 1153 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 1154 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 1155 | "dev": true, 1156 | "requires": { 1157 | "anymatch": "~3.1.2", 1158 | "braces": "~3.0.2", 1159 | "fsevents": "~2.3.2", 1160 | "glob-parent": "~5.1.2", 1161 | "is-binary-path": "~2.1.0", 1162 | "is-glob": "~4.0.1", 1163 | "normalize-path": "~3.0.0", 1164 | "readdirp": "~3.6.0" 1165 | } 1166 | }, 1167 | "cliui": { 1168 | "version": "7.0.4", 1169 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 1170 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 1171 | "dev": true, 1172 | "requires": { 1173 | "string-width": "^4.2.0", 1174 | "strip-ansi": "^6.0.0", 1175 | "wrap-ansi": "^7.0.0" 1176 | } 1177 | }, 1178 | "color-convert": { 1179 | "version": "2.0.1", 1180 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1181 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1182 | "dev": true, 1183 | "requires": { 1184 | "color-name": "~1.1.4" 1185 | } 1186 | }, 1187 | "color-name": { 1188 | "version": "1.1.4", 1189 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1190 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1191 | "dev": true 1192 | }, 1193 | "concat-map": { 1194 | "version": "0.0.1", 1195 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1196 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1197 | "dev": true 1198 | }, 1199 | "debug": { 1200 | "version": "4.3.4", 1201 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1202 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1203 | "dev": true, 1204 | "requires": { 1205 | "ms": "2.1.2" 1206 | }, 1207 | "dependencies": { 1208 | "ms": { 1209 | "version": "2.1.2", 1210 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1211 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1212 | "dev": true 1213 | } 1214 | } 1215 | }, 1216 | "decamelize": { 1217 | "version": "4.0.0", 1218 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 1219 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 1220 | "dev": true 1221 | }, 1222 | "deep-eql": { 1223 | "version": "4.1.3", 1224 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", 1225 | "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", 1226 | "dev": true, 1227 | "requires": { 1228 | "type-detect": "^4.0.0" 1229 | } 1230 | }, 1231 | "diff": { 1232 | "version": "5.0.0", 1233 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 1234 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 1235 | "dev": true 1236 | }, 1237 | "emoji-regex": { 1238 | "version": "8.0.0", 1239 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1240 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1241 | "dev": true 1242 | }, 1243 | "escalade": { 1244 | "version": "3.1.1", 1245 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1246 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1247 | "dev": true 1248 | }, 1249 | "escape-string-regexp": { 1250 | "version": "4.0.0", 1251 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1252 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1253 | "dev": true 1254 | }, 1255 | "fill-range": { 1256 | "version": "7.0.1", 1257 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1258 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1259 | "dev": true, 1260 | "requires": { 1261 | "to-regex-range": "^5.0.1" 1262 | } 1263 | }, 1264 | "find-up": { 1265 | "version": "5.0.0", 1266 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1267 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1268 | "dev": true, 1269 | "requires": { 1270 | "locate-path": "^6.0.0", 1271 | "path-exists": "^4.0.0" 1272 | } 1273 | }, 1274 | "flat": { 1275 | "version": "5.0.2", 1276 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 1277 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 1278 | "dev": true 1279 | }, 1280 | "fs.realpath": { 1281 | "version": "1.0.0", 1282 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1283 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1284 | "dev": true 1285 | }, 1286 | "fsevents": { 1287 | "version": "2.3.2", 1288 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1289 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1290 | "dev": true, 1291 | "optional": true 1292 | }, 1293 | "get-caller-file": { 1294 | "version": "2.0.5", 1295 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1296 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1297 | "dev": true 1298 | }, 1299 | "get-func-name": { 1300 | "version": "2.0.0", 1301 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 1302 | "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", 1303 | "dev": true 1304 | }, 1305 | "glob": { 1306 | "version": "7.2.0", 1307 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 1308 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 1309 | "dev": true, 1310 | "requires": { 1311 | "fs.realpath": "^1.0.0", 1312 | "inflight": "^1.0.4", 1313 | "inherits": "2", 1314 | "minimatch": "^3.0.4", 1315 | "once": "^1.3.0", 1316 | "path-is-absolute": "^1.0.0" 1317 | }, 1318 | "dependencies": { 1319 | "brace-expansion": { 1320 | "version": "1.1.11", 1321 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1322 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1323 | "dev": true, 1324 | "requires": { 1325 | "balanced-match": "^1.0.0", 1326 | "concat-map": "0.0.1" 1327 | } 1328 | }, 1329 | "minimatch": { 1330 | "version": "3.1.2", 1331 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1332 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1333 | "dev": true, 1334 | "requires": { 1335 | "brace-expansion": "^1.1.7" 1336 | } 1337 | } 1338 | } 1339 | }, 1340 | "glob-parent": { 1341 | "version": "5.1.2", 1342 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1343 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1344 | "dev": true, 1345 | "requires": { 1346 | "is-glob": "^4.0.1" 1347 | } 1348 | }, 1349 | "has-flag": { 1350 | "version": "4.0.0", 1351 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1352 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1353 | "dev": true 1354 | }, 1355 | "he": { 1356 | "version": "1.2.0", 1357 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1358 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1359 | "dev": true 1360 | }, 1361 | "inflight": { 1362 | "version": "1.0.6", 1363 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1364 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1365 | "dev": true, 1366 | "requires": { 1367 | "once": "^1.3.0", 1368 | "wrappy": "1" 1369 | } 1370 | }, 1371 | "inherits": { 1372 | "version": "2.0.4", 1373 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1374 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1375 | "dev": true 1376 | }, 1377 | "is-binary-path": { 1378 | "version": "2.1.0", 1379 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1380 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1381 | "dev": true, 1382 | "requires": { 1383 | "binary-extensions": "^2.0.0" 1384 | } 1385 | }, 1386 | "is-extglob": { 1387 | "version": "2.1.1", 1388 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1389 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1390 | "dev": true 1391 | }, 1392 | "is-fullwidth-code-point": { 1393 | "version": "3.0.0", 1394 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1395 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1396 | "dev": true 1397 | }, 1398 | "is-glob": { 1399 | "version": "4.0.3", 1400 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1401 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1402 | "dev": true, 1403 | "requires": { 1404 | "is-extglob": "^2.1.1" 1405 | } 1406 | }, 1407 | "is-number": { 1408 | "version": "7.0.0", 1409 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1410 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1411 | "dev": true 1412 | }, 1413 | "is-plain-obj": { 1414 | "version": "2.1.0", 1415 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1416 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1417 | "dev": true 1418 | }, 1419 | "is-unicode-supported": { 1420 | "version": "0.1.0", 1421 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 1422 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 1423 | "dev": true 1424 | }, 1425 | "js-yaml": { 1426 | "version": "4.1.0", 1427 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1428 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1429 | "dev": true, 1430 | "requires": { 1431 | "argparse": "^2.0.1" 1432 | } 1433 | }, 1434 | "locate-path": { 1435 | "version": "6.0.0", 1436 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1437 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1438 | "dev": true, 1439 | "requires": { 1440 | "p-locate": "^5.0.0" 1441 | } 1442 | }, 1443 | "log-symbols": { 1444 | "version": "4.1.0", 1445 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 1446 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 1447 | "dev": true, 1448 | "requires": { 1449 | "chalk": "^4.1.0", 1450 | "is-unicode-supported": "^0.1.0" 1451 | } 1452 | }, 1453 | "loupe": { 1454 | "version": "2.3.6", 1455 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", 1456 | "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", 1457 | "dev": true, 1458 | "requires": { 1459 | "get-func-name": "^2.0.0" 1460 | } 1461 | }, 1462 | "minimatch": { 1463 | "version": "5.0.1", 1464 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 1465 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 1466 | "dev": true, 1467 | "requires": { 1468 | "brace-expansion": "^2.0.1" 1469 | } 1470 | }, 1471 | "mocha": { 1472 | "version": "10.2.0", 1473 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", 1474 | "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", 1475 | "dev": true, 1476 | "requires": { 1477 | "ansi-colors": "4.1.1", 1478 | "browser-stdout": "1.3.1", 1479 | "chokidar": "3.5.3", 1480 | "debug": "4.3.4", 1481 | "diff": "5.0.0", 1482 | "escape-string-regexp": "4.0.0", 1483 | "find-up": "5.0.0", 1484 | "glob": "7.2.0", 1485 | "he": "1.2.0", 1486 | "js-yaml": "4.1.0", 1487 | "log-symbols": "4.1.0", 1488 | "minimatch": "5.0.1", 1489 | "ms": "2.1.3", 1490 | "nanoid": "3.3.3", 1491 | "serialize-javascript": "6.0.0", 1492 | "strip-json-comments": "3.1.1", 1493 | "supports-color": "8.1.1", 1494 | "workerpool": "6.2.1", 1495 | "yargs": "16.2.0", 1496 | "yargs-parser": "20.2.4", 1497 | "yargs-unparser": "2.0.0" 1498 | } 1499 | }, 1500 | "ms": { 1501 | "version": "2.1.3", 1502 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1503 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1504 | "dev": true 1505 | }, 1506 | "nanoid": { 1507 | "version": "3.3.3", 1508 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", 1509 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", 1510 | "dev": true 1511 | }, 1512 | "normalize-path": { 1513 | "version": "3.0.0", 1514 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1515 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1516 | "dev": true 1517 | }, 1518 | "once": { 1519 | "version": "1.4.0", 1520 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1521 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1522 | "dev": true, 1523 | "requires": { 1524 | "wrappy": "1" 1525 | } 1526 | }, 1527 | "p-limit": { 1528 | "version": "3.1.0", 1529 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1530 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1531 | "dev": true, 1532 | "requires": { 1533 | "yocto-queue": "^0.1.0" 1534 | } 1535 | }, 1536 | "p-locate": { 1537 | "version": "5.0.0", 1538 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1539 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1540 | "dev": true, 1541 | "requires": { 1542 | "p-limit": "^3.0.2" 1543 | } 1544 | }, 1545 | "path-exists": { 1546 | "version": "4.0.0", 1547 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1548 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1549 | "dev": true 1550 | }, 1551 | "path-is-absolute": { 1552 | "version": "1.0.1", 1553 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1554 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1555 | "dev": true 1556 | }, 1557 | "pathval": { 1558 | "version": "1.1.1", 1559 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 1560 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 1561 | "dev": true 1562 | }, 1563 | "picomatch": { 1564 | "version": "2.3.1", 1565 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1566 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1567 | "dev": true 1568 | }, 1569 | "quibble": { 1570 | "version": "file:..", 1571 | "requires": { 1572 | "core-assert": "^1.0.0", 1573 | "is-number": "^7.0.0", 1574 | "is-promise": "^4.0.0", 1575 | "lodash": "^4.17.21", 1576 | "resolve": "^1.22.8", 1577 | "standard": "^17.1.0", 1578 | "teenytest": "^6.0.5", 1579 | "teenytest-promise": "^1.0.0" 1580 | } 1581 | }, 1582 | "randombytes": { 1583 | "version": "2.1.0", 1584 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1585 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1586 | "dev": true, 1587 | "requires": { 1588 | "safe-buffer": "^5.1.0" 1589 | } 1590 | }, 1591 | "readdirp": { 1592 | "version": "3.6.0", 1593 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1594 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1595 | "dev": true, 1596 | "requires": { 1597 | "picomatch": "^2.2.1" 1598 | } 1599 | }, 1600 | "require-directory": { 1601 | "version": "2.1.1", 1602 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1603 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1604 | "dev": true 1605 | }, 1606 | "safe-buffer": { 1607 | "version": "5.2.1", 1608 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1609 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1610 | "dev": true 1611 | }, 1612 | "serialize-javascript": { 1613 | "version": "6.0.0", 1614 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 1615 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 1616 | "dev": true, 1617 | "requires": { 1618 | "randombytes": "^2.1.0" 1619 | } 1620 | }, 1621 | "string-width": { 1622 | "version": "4.2.3", 1623 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1624 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1625 | "dev": true, 1626 | "requires": { 1627 | "emoji-regex": "^8.0.0", 1628 | "is-fullwidth-code-point": "^3.0.0", 1629 | "strip-ansi": "^6.0.1" 1630 | } 1631 | }, 1632 | "strip-ansi": { 1633 | "version": "6.0.1", 1634 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1635 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1636 | "dev": true, 1637 | "requires": { 1638 | "ansi-regex": "^5.0.1" 1639 | } 1640 | }, 1641 | "strip-json-comments": { 1642 | "version": "3.1.1", 1643 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1644 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1645 | "dev": true 1646 | }, 1647 | "supports-color": { 1648 | "version": "8.1.1", 1649 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1650 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1651 | "dev": true, 1652 | "requires": { 1653 | "has-flag": "^4.0.0" 1654 | } 1655 | }, 1656 | "to-regex-range": { 1657 | "version": "5.0.1", 1658 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1659 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1660 | "dev": true, 1661 | "requires": { 1662 | "is-number": "^7.0.0" 1663 | } 1664 | }, 1665 | "type-detect": { 1666 | "version": "4.0.8", 1667 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1668 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1669 | "dev": true 1670 | }, 1671 | "workerpool": { 1672 | "version": "6.2.1", 1673 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 1674 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 1675 | "dev": true 1676 | }, 1677 | "wrap-ansi": { 1678 | "version": "7.0.0", 1679 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1680 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1681 | "dev": true, 1682 | "requires": { 1683 | "ansi-styles": "^4.0.0", 1684 | "string-width": "^4.1.0", 1685 | "strip-ansi": "^6.0.0" 1686 | } 1687 | }, 1688 | "wrappy": { 1689 | "version": "1.0.2", 1690 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1691 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1692 | "dev": true 1693 | }, 1694 | "y18n": { 1695 | "version": "5.0.8", 1696 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1697 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1698 | "dev": true 1699 | }, 1700 | "yargs": { 1701 | "version": "16.2.0", 1702 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1703 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1704 | "dev": true, 1705 | "requires": { 1706 | "cliui": "^7.0.2", 1707 | "escalade": "^3.1.1", 1708 | "get-caller-file": "^2.0.5", 1709 | "require-directory": "^2.1.1", 1710 | "string-width": "^4.2.0", 1711 | "y18n": "^5.0.5", 1712 | "yargs-parser": "^20.2.2" 1713 | } 1714 | }, 1715 | "yargs-parser": { 1716 | "version": "20.2.4", 1717 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 1718 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 1719 | "dev": true 1720 | }, 1721 | "yargs-unparser": { 1722 | "version": "2.0.0", 1723 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1724 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1725 | "dev": true, 1726 | "requires": { 1727 | "camelcase": "^6.0.0", 1728 | "decamelize": "^4.0.0", 1729 | "flat": "^5.0.2", 1730 | "is-plain-obj": "^2.1.0" 1731 | } 1732 | }, 1733 | "yocto-queue": { 1734 | "version": "0.1.0", 1735 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1736 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1737 | "dev": true 1738 | } 1739 | } 1740 | } 1741 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quibble-example", 3 | "private": true, 4 | "scripts": { 5 | "test": "mocha -R spec --recursive test/helper.js test/lib/" 6 | }, 7 | "devDependencies": { 8 | "chai": "^4.3.7", 9 | "mocha": "^10.2.0", 10 | "quibble": "file:.." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/test/helper.js: -------------------------------------------------------------------------------- 1 | global.expect = require('chai').expect 2 | global.context = describe 3 | quibble = require('quibble') 4 | 5 | beforeEach(function () { 6 | // Config a default response for quibbles (usually in a spec helper) 7 | quibble.config({ 8 | defaultFakeCreator: function (path) { 9 | return function () { return 'a fake animal' } 10 | } 11 | }) 12 | }) 13 | 14 | afterEach(function () { 15 | quibble.reset() 16 | }) 17 | -------------------------------------------------------------------------------- /example/test/lib/zoo-spec.js: -------------------------------------------------------------------------------- 1 | quibble = require('quibble') 2 | 3 | require('../../lib/zoo') // drop the zoo in the cache 4 | 5 | describe('zoo', function () { 6 | var subject 7 | 8 | beforeEach(function () { 9 | quibble('../../lib/animals/bear') // return ->'a fake animal'; see helper.js 10 | quibble('../../lib/animals/lion', function () { return 'a fake lion' }) 11 | 12 | subject = require('../../lib/zoo') 13 | }) 14 | 15 | it('contains a fake animal', function () { 16 | expect(subject().animals).to.contain('a fake animal') 17 | }) 18 | 19 | it('contains a fake lion', function () { 20 | expect(subject().animals).to.contain('a fake lion') 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export type QuibbleConfig = { 2 | defaultFakeCreator: (request: string) => any; 3 | }; 4 | 5 | declare const quibble: ((request: string, stub?: any) => any) & { 6 | config(userConfig: Partial): QuibbleConfig; 7 | ignoreCallsFromThisFile(file?: string): void; 8 | reset(hard?: boolean): void; 9 | absolutify(relativePath: string, parentFileName?: string): string; 10 | esm( 11 | specifier: string, 12 | namedExportStubs?: Record, 13 | defaultExportStub?: any 14 | ): Promise; 15 | listMockedModules(): string[]; 16 | isLoaderLoaded(): boolean; 17 | esmImportWithPath(specifier: string): Promise<{ 18 | modulePath: string; 19 | moduleUrl: string; 20 | module: any; 21 | }>; 22 | }; 23 | 24 | export default quibble; 25 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/quibble') 2 | -------------------------------------------------------------------------------- /lib/canRegisterLoader.js: -------------------------------------------------------------------------------- 1 | const Module = require('module') 2 | 3 | function canRegisterLoader () { 4 | return !!Module.register 5 | } 6 | 7 | exports.canRegisterLoader = canRegisterLoader 8 | -------------------------------------------------------------------------------- /lib/esm-import-functions.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { pathToFileURL } = require('url') 3 | 4 | exports.dummyImportModuleToGetAtPath = async function dummyImportModuleToGetAtPath (modulePath) { 5 | try { 6 | const moduleUrl = path.isAbsolute(modulePath) ? pathToFileURL(modulePath) : modulePath 7 | 8 | await import(addQueryToUrl(moduleUrl, '__quibbleresolveurl')) 9 | } catch (error) { 10 | if (error.code === 'QUIBBLE_RESOLVED_URL') { 11 | return error.resolvedUrl 12 | } else { 13 | throw error 14 | } 15 | } 16 | 17 | throw new Error( 18 | 'Node.js is not running with the Quibble loader. Run node with "--loader=quibble"' 19 | ) 20 | } 21 | 22 | exports.importOriginalModule = async (fullImportPath) => { 23 | return import(addQueryToUrl(fullImportPath, '__quibbleoriginal')) 24 | } 25 | 26 | function addQueryToUrl (url, query) { 27 | try { 28 | const urlObject = new URL(url) 29 | urlObject.searchParams.set(query, '') 30 | return urlObject.href.replace(`${query}=`, query) 31 | } catch { 32 | return url + '?' + query 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/quibble-registered.mjs: -------------------------------------------------------------------------------- 1 | import { globalPreload } from './quibble.mjs' 2 | export * from './quibble.mjs' 3 | 4 | export function initialize ({ port }) { 5 | globalPreload({ port }) 6 | } 7 | -------------------------------------------------------------------------------- /lib/quibble.js: -------------------------------------------------------------------------------- 1 | const Module = require('module') 2 | const path = require('path') 3 | const util = require('util') 4 | const { URL, pathToFileURL, fileURLToPath } = require('url') 5 | const resolve = require('resolve') 6 | const importFunctions = require('./esm-import-functions') 7 | const isPlainObject = require('lodash/isPlainObject.js') 8 | const _ = { 9 | compact: require('lodash/fp/compact'), 10 | extendAll: require('lodash/fp/extendAll'), 11 | filter: require('lodash/fp/filter'), 12 | find: require('lodash/fp/find'), 13 | ooFind: require('lodash/find'), 14 | flow: require('lodash/fp/flow'), 15 | invokeMap: require('lodash/fp/invokeMap'), 16 | map: require('lodash/fp/map'), 17 | includes: require('lodash/fp/includes'), 18 | reject: require('lodash/fp/reject'), 19 | startsWith: require('lodash/fp/startsWith'), 20 | uniq: require('lodash/uniq'), 21 | tap: require('lodash/tap'), 22 | values: require('lodash/values') 23 | } 24 | const { MessageChannel } = require('node:worker_threads') 25 | const { canRegisterLoader } = require('./canRegisterLoader') 26 | 27 | const originalLoad = Module._load 28 | let config = null 29 | let quibbles = {} 30 | let ignoredCallerFiles = [] 31 | let quibble 32 | 33 | const quibbleUserToLoaderCommunication = () => 34 | globalThis[Symbol.for('__quibbleUserToLoaderCommunication')] 35 | 36 | module.exports = quibble = function (request, stub) { 37 | request = quibble.absolutify(request) 38 | Module._load = fakeLoad 39 | quibbles[request] = { 40 | callerFile: hackErrorStackToGetCallerFile(), 41 | stub: arguments.length < 2 ? config.defaultFakeCreator(request) : stub 42 | } 43 | 44 | return quibbles[request].stub 45 | } 46 | 47 | quibble.config = function (userConfig) { 48 | return (config = _.extendAll({}, { 49 | defaultFakeCreator: function (request) { return {} } 50 | }, userConfig)) 51 | } 52 | 53 | config = quibble.config() 54 | 55 | quibble.ignoreCallsFromThisFile = function (file) { 56 | if (file == null) { 57 | file = hackErrorStackToGetCallerFile(false) 58 | } 59 | ignoredCallerFiles = _.uniq(ignoredCallerFiles.concat(file, pathToFileURL(file).href)) 60 | } 61 | 62 | quibble.reset = function (hard) { 63 | Module._load = originalLoad 64 | quibbles = {} 65 | 66 | quibbleUserToLoaderCommunication()?.reset() 67 | 68 | config = quibble.config() 69 | if (hard) { 70 | ignoredCallerFiles = [] 71 | } 72 | } 73 | 74 | quibble.absolutify = function (relativePath, parentFileName) { 75 | if (parentFileName == null) { 76 | parentFileName = hackErrorStackToGetCallerFile() 77 | } 78 | const absolutePath = absolutePathFor(relativePath, parentFileName) 79 | const resolvedPath = nodeResolve(absolutePath, { basedir: path.dirname(parentFileName) }) 80 | return resolvedPath || absolutePath 81 | } 82 | 83 | quibble.esm = async function (specifier, namedExportStubs, defaultExportStub) { 84 | checkThatLoaderIsLoaded() 85 | if ( 86 | namedExportStubs != null && 87 | !util.types.isProxy(namedExportStubs) && 88 | !isPlainObject(namedExportStubs) 89 | ) { 90 | throw new Error( 91 | 'namedExportsStub argument must be either a plain object or null/undefined' 92 | ) 93 | } 94 | 95 | let finalNamedExportStubs = namedExportStubs 96 | 97 | if (finalNamedExportStubs != null && 'default' in finalNamedExportStubs) { 98 | if (defaultExportStub !== undefined) { 99 | throw new Error( 100 | "conflict between a named export with the name 'default' and the default export stub. You can't have both" 101 | ) 102 | } 103 | finalNamedExportStubs = { ...namedExportStubs } 104 | defaultExportStub = namedExportStubs.default 105 | delete finalNamedExportStubs.default 106 | } 107 | 108 | const importPathIsBareSpecifier = isBareSpecifier(specifier) 109 | const parentUrl = importPathIsBareSpecifier 110 | ? undefined 111 | : hackErrorStackToGetCallerFile(true, true) 112 | const moduleUrl = importPathIsBareSpecifier 113 | ? await importFunctions.dummyImportModuleToGetAtPath(specifier) 114 | : new URL(specifier, parentUrl).href 115 | 116 | await quibbleUserToLoaderCommunication().addMockedModule(moduleUrl, { 117 | namedExportStubs: finalNamedExportStubs, 118 | defaultExportStub 119 | }) 120 | } 121 | 122 | quibble.listMockedModules = function () { 123 | const esmMockedModules = quibbleUserToLoaderCommunication()?.listMockedModules() ?? [] 124 | const cjsMockedModules = Object.keys(quibbles).map((modulePath) => pathToFileURL(modulePath).href) 125 | 126 | return esmMockedModules.concat(cjsMockedModules) 127 | } 128 | 129 | quibble.isLoaderLoaded = function () { 130 | return !!quibbleUserToLoaderCommunication() 131 | } 132 | 133 | quibble.esmImportWithPath = async function esmImportWithPath (specifier) { 134 | checkThatLoaderIsLoaded() 135 | 136 | const importPathIsBareSpecifier = isBareSpecifier(specifier) 137 | const parentUrl = importPathIsBareSpecifier 138 | ? undefined 139 | : hackErrorStackToGetCallerFile(true, true) 140 | const moduleUrl = importPathIsBareSpecifier 141 | ? await importFunctions.dummyImportModuleToGetAtPath(specifier) 142 | : new URL(specifier, parentUrl).href 143 | 144 | return { 145 | // The name of this property _should_ be `moduleUrl`, but it is used in `testdouble` as `modulePath` 146 | // and so can't be changed without breaking `testdouble`. So I add another field with the correct name 147 | // and once testdouble is updated, I can remove the `modulePath` field. 148 | modulePath: moduleUrl, 149 | moduleUrl, 150 | module: await importFunctions.importOriginalModule(moduleUrl) 151 | } 152 | } 153 | 154 | const absolutePathFor = function (relativePath, parentFileName) { 155 | if (_.startsWith(relativePath, '/') || /^(\w|@)/.test(relativePath)) { 156 | return relativePath 157 | } else { 158 | return path.resolve(path.dirname(parentFileName), relativePath) 159 | } 160 | } 161 | 162 | const fakeLoad = function (request, parent, isMain) { 163 | if (parent != null) { 164 | request = quibble.absolutify(request, parent.filename) 165 | } 166 | const stubbing = stubbingThatMatchesRequest(request) 167 | 168 | if (stubbing) { 169 | return stubbing.stub 170 | } else if (requireWasCalledFromAFileThatHasQuibbledStuff()) { 171 | return doWithoutCache(request, parent, function () { 172 | return originalLoad(request, parent, isMain) 173 | }) 174 | } else { 175 | return originalLoad(request, parent, isMain) 176 | } 177 | } 178 | const stubbingThatMatchesRequest = function (request) { 179 | return _.ooFind( 180 | quibbles, 181 | function (stubbing, stubbedPath) { 182 | if (request === stubbedPath) return true 183 | if (nodeResolve(request) === stubbedPath) return true 184 | }, 185 | quibbles 186 | ) 187 | } 188 | 189 | const requireWasCalledFromAFileThatHasQuibbledStuff = function () { 190 | const quibbleValues = _.values(quibbles) 191 | for (let i = 0; i < quibbleValues.length; i++) { 192 | if (quibbleValues[i].callerFile === hackErrorStackToGetCallerFile()) { 193 | return true 194 | } 195 | } 196 | } 197 | 198 | const doWithoutCache = function (request, parent, thingToDo) { 199 | const filename = Module._resolveFilename(request, parent) 200 | if (Object.prototype.hasOwnProperty.call(Module._cache, filename)) { 201 | return doAndRestoreCache(filename, thingToDo) 202 | } else { 203 | return doAndDeleteCache(filename, thingToDo) 204 | } 205 | } 206 | 207 | const doAndRestoreCache = function (filename, thingToDo) { 208 | const cachedThing = Module._cache[filename] 209 | delete Module._cache[filename] 210 | return _.tap(thingToDo(), function () { 211 | Module._cache[filename] = cachedThing 212 | }) 213 | } 214 | 215 | const doAndDeleteCache = function (filename, thingToDo) { 216 | return _.tap(thingToDo(), function () { 217 | delete Module._cache[filename] 218 | }) 219 | } 220 | 221 | const nodeResolve = function (request, options) { 222 | try { 223 | return resolve.sync(request, options) 224 | } catch (e) {} 225 | } 226 | 227 | const hackErrorStackToGetCallerFile = function ( 228 | includeGlobalIgnores = true, 229 | keepUrls = false 230 | ) { 231 | const originalFunc = Error.prepareStackTrace 232 | const originalStackTraceLimit = Error.stackTraceLimit 233 | try { 234 | Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 30) 235 | Error.prepareStackTrace = function (e, stack) { 236 | return stack 237 | } 238 | const conversionFunc = keepUrls 239 | ? convertStackPathToUrl 240 | : convertStackUrlToPath 241 | const e = new Error() 242 | const currentFile = conversionFunc(e.stack[0].getFileName()) 243 | return _.flow([ 244 | _.invokeMap('getFileName'), 245 | _.compact, 246 | _.map(conversionFunc), 247 | _.reject(function (f) { 248 | return includeGlobalIgnores && _.includes(f, ignoredCallerFiles) 249 | }), 250 | _.filter(keepUrls ? _.identity : path.isAbsolute), 251 | _.filter(conversionFunc), 252 | _.find(function (f) { 253 | return f !== currentFile 254 | }) 255 | ])(e.stack) 256 | } finally { 257 | Error.prepareStackTrace = originalFunc 258 | Error.stackTraceLimit = originalStackTraceLimit 259 | } 260 | } 261 | 262 | function checkThatLoaderIsLoaded () { 263 | if (!quibble.isLoaderLoaded()) { 264 | if (canRegisterLoader()) { 265 | registerEsmLoader() 266 | } else { 267 | throw new Error( 268 | 'quibble loader not loaded. You cannot replace ES modules without a loader. Run Node.js with `--loader=quibble` or use Node.js v20.6.0 or higher.' 269 | ) 270 | } 271 | } 272 | } 273 | 274 | function convertStackUrlToPath (fileUrl) { 275 | try { 276 | return fileURLToPath(fileUrl) 277 | } catch (error) { 278 | if (error.code !== 'TYPE_ERROR') { 279 | return fileUrl 280 | } else { 281 | throw error 282 | } 283 | } 284 | } 285 | 286 | function convertStackPathToUrl (filePath) { 287 | if (path.isAbsolute(filePath)) { 288 | return pathToFileURL(filePath).href 289 | } else { 290 | return filePath 291 | } 292 | } 293 | 294 | function isBareSpecifier (modulePath) { 295 | const firstLetter = modulePath[0] 296 | if (firstLetter === '.' || firstLetter === '/') { 297 | return false 298 | } 299 | 300 | if (!modulePath.includes(':')) { 301 | return true 302 | } 303 | 304 | try { 305 | // (yes, we DO use new for side-effects!) 306 | // eslint-disable-next-line 307 | new URL(modulePath); 308 | } catch (error) { 309 | if (error.code === 'ERR_INVALID_URL') { 310 | return false 311 | } else { 312 | throw error 313 | } 314 | } 315 | 316 | return true 317 | } 318 | 319 | function registerEsmLoader () { 320 | const { port1, port2 } = new MessageChannel() 321 | 322 | Module.register( 323 | new URL('./quibble-registered.mjs', pathToFileURL(__filename)), 324 | { data: { port: port2 }, transferList: [port2] } 325 | ) 326 | 327 | require('./thisWillRunInUserThread.js').thisWillRunInUserThread( 328 | globalThis, 329 | port1 330 | ) 331 | } 332 | -------------------------------------------------------------------------------- /lib/quibble.mjs: -------------------------------------------------------------------------------- 1 | import quibble from './quibble.js' 2 | import { thisWillRunInUserThread } from './thisWillRunInUserThread.js' 3 | 4 | export default quibble 5 | export const reset = quibble.reset 6 | export const ignoreCallsFromThisFile = quibble.ignoreCallsFromThisFile 7 | export const config = quibble.config 8 | export const isLoaderLoaded = quibble.isLoaderLoaded 9 | 10 | /** @typedef {{hasDefaultExportStub: boolean, namedExports: [string]}} ModuleLoaderMockInfo */ 11 | /** 12 | * @type {{ 13 | * quibbledModules: Map, 14 | * stubModuleGeneration: number 15 | * }} 16 | * 17 | */ 18 | const quibbleLoaderState = { 19 | quibbledModules: new Map(), 20 | stubModuleGeneration: 0 21 | } 22 | 23 | export async function resolve (specifier, context, nextResolve) { 24 | const resolve = () => 25 | nextResolve( 26 | specifier.includes('__quibble') 27 | ? specifier 28 | .replace(/[?&]__quibbleresolveurl/, '') 29 | .replace(/[?&]__quibbleoriginal/, '') 30 | : specifier, 31 | context 32 | ) 33 | 34 | if (specifier.includes('__quibbleresolveurl')) { 35 | const resolvedUrl = (await resolve()).url 36 | const error = new Error() 37 | error.code = 'QUIBBLE_RESOLVED_URL' 38 | error.resolvedUrl = resolvedUrl 39 | throw error 40 | } 41 | 42 | if (!quibbleLoaderState.quibbledModules) { 43 | return resolve() 44 | } 45 | 46 | if (specifier === 'quibble') { 47 | return resolve() 48 | } 49 | 50 | if (specifier.includes('__quibbleoriginal')) { 51 | return resolve() 52 | } 53 | 54 | const stubModuleGeneration = quibbleLoaderState.stubModuleGeneration 55 | const { parentURL } = context 56 | 57 | try { 58 | const { url, ...ctx } = await resolve() 59 | 60 | const quibbledUrl = addQueryToUrl(url, '__quibble', stubModuleGeneration) 61 | 62 | if (url.startsWith('node:') && !getStubsInfo(quibbledUrl)) { 63 | return { ...ctx, url } // It's allowed to change ctx for a builtin (but unlikely) 64 | } 65 | 66 | return { ...ctx, url: quibbledUrl } 67 | } catch (error) { 68 | if (error.code === 'ERR_MODULE_NOT_FOUND') { 69 | return { 70 | url: parentURL 71 | ? addQueryToUrl( 72 | new URL(specifier, parentURL).href 73 | , '__quibble', stubModuleGeneration) 74 | : new URL(specifier).href 75 | } 76 | } else { 77 | throw error 78 | } 79 | } 80 | } 81 | 82 | /** 83 | * @param {string} moduleUrl 84 | * 85 | * @returns {[string, ModuleLoaderMockInfo] | undefined} 86 | * */ 87 | function getStubsInfo (moduleUrl) { 88 | if (!quibbleLoaderState.quibbledModules) return undefined 89 | if (!moduleUrl.includes('__quibble=')) return undefined 90 | 91 | const moduleKey = moduleUrl.replace(/\?.*/, '').replace(/#.*/, '') 92 | 93 | const moduleMockingInfo = quibbleLoaderState.quibbledModules.get(moduleKey) 94 | 95 | return moduleMockingInfo ? [moduleKey, moduleMockingInfo] : undefined 96 | } 97 | 98 | /** 99 | * 100 | * @param {[string, ModuleLoaderMockInfo]} options 101 | * @returns 102 | */ 103 | function transformModuleSource ([moduleKey, mockingInfo]) { 104 | return ` 105 | ${mockingInfo.namedExports 106 | .map( 107 | (name) => 108 | `export let ${name} = globalThis[Symbol.for('__quibbleUserState')].quibbledModules.get(${JSON.stringify( 109 | moduleKey 110 | )}).namedExportStubs["${name}"]` 111 | ) 112 | .join(';\n')}; 113 | ${ 114 | mockingInfo.hasDefaultExport 115 | ? `export default globalThis[Symbol.for('__quibbleUserState')].quibbledModules.get(${JSON.stringify( 116 | moduleKey 117 | )}).defaultExportStub;` 118 | : '' 119 | } 120 | ` 121 | } 122 | 123 | /** 124 | * @param {string} url 125 | * @param {{ 126 | * format: string, 127 | * }} context 128 | * @param {Function} nextLoad 129 | * @returns {Promise<{ source: !(string | SharedArrayBuffer | Uint8Array), format: string}>} 130 | */ 131 | export async function load (url, context, nextLoad) { 132 | const mockingInfo = getStubsInfo(url) 133 | 134 | return mockingInfo 135 | ? { 136 | source: transformModuleSource(mockingInfo), 137 | format: 'module', 138 | shortCircuit: true 139 | } 140 | : await nextLoad(url.replace(/\?.*/, '').replace(/#.*/, ''), context) 141 | } 142 | 143 | export const globalPreload = ({ port }) => { 144 | globalThis[Symbol.for('__quibbleLoaderState')] = quibbleLoaderState 145 | 146 | port.addEventListener('message', ({ data }) => { 147 | if (data.type === 'reset') { 148 | quibbleLoaderState.quibbledModules = new Map() 149 | quibbleLoaderState.stubModuleGeneration++ 150 | Atomics.store(data.hasResetHappened, 0, 1) 151 | Atomics.notify(data.hasResetHappened, 0) 152 | } else if (data.type === 'addMockedModule') { 153 | quibbleLoaderState.quibbledModules.set(data.moduleUrl, { 154 | namedExports: data.namedExports, 155 | hasDefaultExport: data.hasDefaultExport 156 | }) 157 | ++quibbleLoaderState.stubModuleGeneration 158 | Atomics.store(data.hasAddMockedHappened, 0, 1) 159 | Atomics.notify(data.hasAddMockedHappened, 0) 160 | } else if (data.type === 'listMockedModules') { 161 | const mockedModules = Array.from(quibbleLoaderState.quibbledModules.keys()) 162 | const serializedMockedModules = mockedModules.join(' ') 163 | const encodedMockedModules = new TextEncoder().encode(serializedMockedModules) 164 | 165 | data.mockedModulesListLength[0] = encodedMockedModules.length 166 | if (encodedMockedModules.length <= data.mockedModulesList.length) { 167 | for (let i = 0; i < encodedMockedModules.length; ++i) { 168 | data.mockedModulesList[i] = encodedMockedModules[i] 169 | } 170 | } 171 | Atomics.store(data.hasListMockedModulesHappened, 0, 1) 172 | Atomics.notify(data.hasListMockedModulesHappened, 0) 173 | } 174 | }) 175 | port.unref() 176 | 177 | return `(${thisWillRunInUserThread})(globalThis, port)` 178 | } 179 | 180 | function addQueryToUrl (url, query, value) { 181 | const urlObject = new URL(url) 182 | urlObject.searchParams.set(query, value) 183 | return urlObject.href 184 | } 185 | -------------------------------------------------------------------------------- /lib/thisWillRunInUserThread.js: -------------------------------------------------------------------------------- 1 | exports.thisWillRunInUserThread = (globalThis, port) => { 2 | globalThis[Symbol.for('__quibbleUserState')] = { quibbledModules: new Map() } 3 | 4 | globalThis[Symbol.for('__quibbleUserToLoaderCommunication')] = { 5 | reset () { 6 | globalThis[Symbol.for('__quibbleUserState')].quibbledModules = new Map() 7 | 8 | if (!loaderAndUserRunInSameThread(globalThis)) { 9 | const hasResetHappened = new Int32Array(new SharedArrayBuffer(4)) 10 | port.postMessage({ type: 'reset', hasResetHappened }) 11 | Atomics.wait(hasResetHappened, 0, 0) 12 | } else { 13 | const quibbleLoaderState = globalThis[Symbol.for('__quibbleLoaderState')] 14 | 15 | quibbleLoaderState.quibbledModules = new Map() 16 | quibbleLoaderState.stubModuleGeneration++ 17 | } 18 | }, 19 | addMockedModule ( 20 | moduleUrl, 21 | { namedExportStubs, defaultExportStub } 22 | ) { 23 | globalThis[Symbol.for('__quibbleUserState')].quibbledModules.set(moduleUrl, { 24 | defaultExportStub, 25 | namedExportStubs 26 | }) 27 | 28 | if (!loaderAndUserRunInSameThread(globalThis)) { 29 | const hasAddMockedHappened = new Int32Array(new SharedArrayBuffer(4)) 30 | 31 | port.postMessage({ 32 | type: 'addMockedModule', 33 | moduleUrl, 34 | namedExports: Object.keys(namedExportStubs || []), 35 | hasDefaultExport: defaultExportStub != null, 36 | hasAddMockedHappened 37 | }) 38 | Atomics.wait(hasAddMockedHappened, 0, 0) 39 | } else { 40 | const quibbleLoaderState = globalThis[Symbol.for('__quibbleLoaderState')] 41 | 42 | quibbleLoaderState.quibbledModules.set(moduleUrl, { 43 | hasDefaultExport: defaultExportStub != null, 44 | namedExports: Object.keys(namedExportStubs || []) 45 | }) 46 | ++quibbleLoaderState.stubModuleGeneration 47 | } 48 | }, 49 | listMockedModules () { 50 | if (!loaderAndUserRunInSameThread(globalThis)) { 51 | const hasListMockedModulesHappened = new Int32Array(new SharedArrayBuffer(4)) 52 | const mockedModulesListLength = new Int32Array(new SharedArrayBuffer(4)) 53 | const mockedModulesList = new Uint8Array(new SharedArrayBuffer(20 * 1024 * 1024)) // 20MB should be sufficient 54 | port.postMessage({ 55 | type: 'listMockedModules', 56 | hasListMockedModulesHappened, 57 | mockedModulesListLength, 58 | mockedModulesList 59 | }) 60 | Atomics.wait(hasListMockedModulesHappened, 0, 0) 61 | if (mockedModulesListLength[0] > mockedModulesList.length) { 62 | throw new Error('Not enough buffer allocated for result') 63 | } 64 | const serializedMockedModules = new TextDecoder().decode(mockedModulesList.slice(0, mockedModulesListLength[0])) 65 | return serializedMockedModules ? serializedMockedModules.split(' ') : [] 66 | } else { 67 | const quibbleLoaderState = globalThis[Symbol.for('__quibbleLoaderState')] 68 | 69 | return Array.from(quibbleLoaderState.quibbledModules.keys()) 70 | } 71 | } 72 | } 73 | 74 | function loaderAndUserRunInSameThread (globalThis) { 75 | return !!globalThis[Symbol.for('__quibbleLoaderState')] 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quibble", 3 | "version": "0.9.2", 4 | "description": "Makes it easy to replace require'd dependencies.", 5 | "homepage": "https://github.com/testdouble/quibble", 6 | "main": "./index.js", 7 | "types": "./index.d.ts", 8 | "exports": { 9 | ".": { 10 | "require": "./lib/quibble.js", 11 | "import": "./lib/quibble.mjs", 12 | "types": "./index.d.ts" 13 | }, 14 | "./package.json": "./package.json" 15 | }, 16 | "scripts": { 17 | "test": "teenytest", 18 | "style": "standard --fix", 19 | "test:esm": "node --loader=quibble ./test/esm-lib/teenytest-proxy.js \"./test/esm-lib/*.test.{mjs,js}\"", 20 | "test:esm-auto-loader": "node test/esm-lib/supports-auto-load.js not || node ./test/esm-lib/teenytest-proxy.js \"./test/esm-lib/*.test.{mjs,js}\"", 21 | "test:no-loader-esm": "node test/esm-lib/supports-auto-load.js || teenytest \"./test/esm-lib/*.no-loader-test.js\" && teenytest \"./test/esm-lib/*.no-loader-test.mjs\"", 22 | "test:example": "cd example && npm it", 23 | "test:example-esm": "cd example-esm && npm it", 24 | "test:example-esm-auto-loader": "node test/esm-lib/supports-auto-load.js not || (cd example-esm && npm i && npm run test-auto-loader)", 25 | "test:smells": "bash ./test/require-smell-test.sh", 26 | "test:ci": "npm test && npm run test:esm && npm run test:no-loader-esm && npm run test:esm-auto-loader && npm run style && npm run test:example && npm run test:example-esm && npm run test:example-esm-auto-loader && npm run test:smells", 27 | "preversion": "git pull --rebase && npm run test:ci", 28 | "postversion": "git push && git push --tags && npm publish" 29 | }, 30 | "author": { 31 | "name": "Justin Searls", 32 | "email": "justin@testdouble.com", 33 | "url": "http://testdouble.com" 34 | }, 35 | "dependencies": { 36 | "lodash": "^4.17.21", 37 | "resolve": "^1.22.8" 38 | }, 39 | "devDependencies": { 40 | "core-assert": "^1.0.0", 41 | "is-number": "^7.0.0", 42 | "is-promise": "^4.0.0", 43 | "standard": "^17.1.0", 44 | "teenytest": "^6.0.5", 45 | "teenytest-promise": "^1.0.0" 46 | }, 47 | "standard": { 48 | "globals": [ 49 | "assert" 50 | ], 51 | "ignore": [ 52 | "example", 53 | "example-esm" 54 | ] 55 | }, 56 | "teenytest": { 57 | "plugins": [ 58 | "teenytest-promise" 59 | ] 60 | }, 61 | "bugs": { 62 | "url": "https://github.com/testdouble/quibble/issues" 63 | }, 64 | "repository": { 65 | "type": "git", 66 | "url": "https://github.com/testdouble/quibble.git" 67 | }, 68 | "engines": { 69 | "node": ">= 0.14.0" 70 | }, 71 | "license": "MIT" 72 | } 73 | -------------------------------------------------------------------------------- /test/esm-fixtures/a-module-ignored.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = async function () { 4 | return import('./a-module-ignored.mjs') 5 | } 6 | -------------------------------------------------------------------------------- /test/esm-fixtures/a-module-ignored.mjs: -------------------------------------------------------------------------------- 1 | import { ignoreCallsFromThisFile } from '../../lib/quibble.mjs' 2 | export const life = 42 3 | export const namedExport = 'named-export' 4 | 5 | ignoreCallsFromThisFile() 6 | 7 | export default 'default-export' 8 | -------------------------------------------------------------------------------- /test/esm-fixtures/a-module-with-function.mjs: -------------------------------------------------------------------------------- 1 | export const life = 42 2 | export const namedExport = 'named-export' 3 | export const namedFunctionExport = () => 'named-function-export' 4 | 5 | export default 'default-export' 6 | -------------------------------------------------------------------------------- /test/esm-fixtures/a-module.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = async function () { 4 | return import('./a-module.mjs') 5 | } 6 | -------------------------------------------------------------------------------- /test/esm-fixtures/a-module.mjs: -------------------------------------------------------------------------------- 1 | export const life = 42 2 | export const namedExport = 'named-export' 3 | 4 | export default 'default-export' 5 | -------------------------------------------------------------------------------- /test/esm-fixtures/b-module.mjs: -------------------------------------------------------------------------------- 1 | export const life = 43 2 | export const namedExport = 'named-export-b' 3 | 4 | export default 'default-export-b' 5 | -------------------------------------------------------------------------------- /test/esm-lib/quibble-cjs-esmImportWithPath.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { pathToFileURL } = require('url') 3 | const quibble = require('quibble') 4 | 5 | module.exports = { 6 | afterEach: function () { quibble.reset() }, 7 | 'support importing esm and returning the path for a relative url': async function () { 8 | const { modulePath, moduleUrl, module } = await quibble.esmImportWithPath('../esm-fixtures/a-module.mjs') 9 | 10 | assert.deepEqual(modulePath, pathToFileURL(path.resolve(__dirname, '../esm-fixtures/a-module.mjs')).href) 11 | assert.deepEqual(moduleUrl, pathToFileURL(path.resolve(__dirname, '../esm-fixtures/a-module.mjs')).href) 12 | assert.deepEqual({ ...module }, { 13 | default: 'default-export', 14 | namedExport: 'named-export', 15 | life: 42 16 | }) 17 | }, 18 | 'support importing esm and returning the path for a bare specifier': async function () { 19 | // This test that `is-promise` is a dual-mode module where 20 | // the entry points are index.js and index.mjs. If this changes in the future, you 21 | // can always create a module of your own and put it in node_modules. 22 | const { modulePath, module } = await quibble.esmImportWithPath('is-promise') 23 | 24 | assert.deepEqual(modulePath, pathToFileURL(require.resolve('is-promise')).href.replace('.js', '.mjs')) 25 | const { default: isPromise, ...rest } = module 26 | assert.deepEqual(rest, {}) 27 | assert.deepEqual(isPromise(Promise.resolve()), true) 28 | assert.deepEqual(isPromise(42), false) 29 | }, 30 | 'support importing esm and returning the path even when relative path quibbled': async function () { 31 | await quibble.esm('./a-module.mjs', { 32 | namedExport: 'replacement', 33 | life: 41, 34 | namedFunctionExport: () => 'export replacement' 35 | }, 'default-export-replacement') 36 | const { modulePath, module } = await quibble.esmImportWithPath('../esm-fixtures/a-module.mjs') 37 | 38 | assert.deepEqual(modulePath, pathToFileURL(path.resolve(__dirname, '../esm-fixtures/a-module.mjs')).href) 39 | assert.deepEqual({ ...module }, { 40 | default: 'default-export', 41 | namedExport: 'named-export', 42 | life: 42 43 | }) 44 | }, 45 | 'support importing esm and returning the path even when bare-specifier quibbled': async function () { 46 | // This test that `is-promise` is a dual-mode module where 47 | // the entry points are index.js and index.mjs. If thie changes in the future, you 48 | // can always create a module of your own and put it in node_modules. 49 | await quibble.esm('is-promise', undefined, 42) 50 | const { modulePath, module } = await quibble.esmImportWithPath('is-promise') 51 | 52 | assert.deepEqual(modulePath, pathToFileURL(require.resolve('is-promise')).href.replace('.js', '.mjs')) 53 | const { default: isPromise, ...rest } = module 54 | assert.deepEqual(rest, {}) 55 | assert.deepEqual(isPromise(Promise.resolve()), true) 56 | assert.deepEqual(isPromise(42), false) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/esm-lib/quibble-cjs.test.js: -------------------------------------------------------------------------------- 1 | const quibble = require('quibble') 2 | 3 | module.exports = { 4 | afterEach: function () { quibble.reset() }, 5 | 'used from cjs': async function () { 6 | const cjsImporingMjs = require('../esm-fixtures/a-module') 7 | const result1 = await cjsImporingMjs() 8 | assert.deepEqual({ ...result1 }, { 9 | default: 'default-export', 10 | namedExport: 'named-export', 11 | life: 42 12 | }) 13 | 14 | await quibble.esm('../esm-fixtures/a-module.mjs', { 15 | namedExport: 'replacement', 16 | life: 41 17 | }, 'default-export-replacement') 18 | 19 | const result2 = await cjsImporingMjs() 20 | assert.deepEqual({ ...result2 }, { 21 | default: 'default-export-replacement', 22 | namedExport: 'replacement', 23 | life: 41 24 | }) 25 | 26 | quibble.reset() 27 | const result3 = await cjsImporingMjs() 28 | assert.deepEqual({ ...result3 }, { 29 | default: 'default-export', 30 | namedExport: 'named-export', 31 | life: 42 32 | }) 33 | 34 | await quibble.esm('../esm-fixtures/a-module.mjs', { 35 | namedExport: 'replacement 2', 36 | life: 40 37 | }, 'default-export-replacement 2') 38 | const result4 = await cjsImporingMjs() 39 | 40 | assert.deepEqual({ ...result4 }, { 41 | default: 'default-export-replacement 2', 42 | namedExport: 'replacement 2', 43 | life: 40 44 | }) 45 | }, 46 | 'works for modules that dont exist': async function () { 47 | await quibble.esm('../esm-fixtures/this-module-does-not-exist.mjs', { named: 'named!' }, 'def-export') 48 | const result = await import('../esm-fixtures/this-module-does-not-exist.mjs') 49 | 50 | assert.deepEqual({ ...result }, { 51 | default: 'def-export', 52 | named: 'named!' 53 | }) 54 | }, 55 | 'ignoreCallsFromThisFile works with ESM': async function () { 56 | const cjsImporingMjs = require('../esm-fixtures/a-module-ignored') 57 | const result1 = await cjsImporingMjs() 58 | assert.deepEqual({ ...result1 }, { 59 | default: 'default-export', 60 | namedExport: 'named-export', 61 | life: 42 62 | }) 63 | 64 | await quibble.esm('../esm-fixtures/a-module.mjs', { 65 | namedExport: 'replacement', 66 | life: 41 67 | }, 'default-export-replacement') 68 | 69 | const result2 = await cjsImporingMjs() 70 | assert.deepEqual({ ...result2 }, { 71 | default: 'default-export', 72 | namedExport: 'named-export', 73 | life: 42 74 | }) 75 | 76 | quibble.reset() 77 | const result3 = await cjsImporingMjs() 78 | assert.deepEqual({ ...result3 }, { 79 | default: 'default-export', 80 | namedExport: 'named-export', 81 | life: 42 82 | }) 83 | 84 | await quibble.esm('../esm-fixtures/a-module.mjs', { 85 | namedExport: 'replacement 2', 86 | life: 40 87 | }, 'default-export-replacement 2') 88 | const result4 = await cjsImporingMjs() 89 | assert.deepEqual({ ...result4 }, { 90 | default: 'default-export', 91 | namedExport: 'named-export', 92 | life: 42 93 | }) 94 | }, 95 | 'isLoaderLoader returns true if loader as loaded': async function () { 96 | assert.equal(quibble.isLoaderLoaded(), true) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/esm-lib/quibble-esm.test.mjs: -------------------------------------------------------------------------------- 1 | // This import is important and part of the test, 2 | // as it checks how quibble interacts with internal modules 3 | import 'fs' 4 | import quibble from 'quibble' 5 | import { fileURLToPath, pathToFileURL } from 'url' 6 | 7 | const __filename = fileURLToPath(import.meta.url) 8 | 9 | export default { 10 | afterEach: function () { quibble.reset() }, 11 | 'mock a module': async function () { 12 | await quibble.esm('../esm-fixtures/a-module-with-function.mjs', { 13 | namedExport: 'replacement', 14 | life: 41, 15 | namedFunctionExport: () => 'export replacement' 16 | }, 'default-export-replacement') 17 | 18 | // This import is important, as it checks how quibble interacts with internal modules 19 | await import('util') 20 | 21 | const result = await import('../esm-fixtures/a-module-with-function.mjs') 22 | assert.equal(result.default, 'default-export-replacement') 23 | assert.equal(result.namedExport, 'replacement') 24 | assert.equal(result.life, 41) 25 | assert.equal(result.namedFunctionExport(), 'export replacement') 26 | }, 27 | 'mock a module with no named exports': async function () { 28 | await quibble.esm('../esm-fixtures/a-module.mjs', undefined, 'default-export-replacement') 29 | 30 | const result = await import('../esm-fixtures/a-module.mjs') 31 | assert.equal(result.default, 'default-export-replacement') 32 | }, 33 | 'mock a module after it is used unmocked': async function () { 34 | const result1 = await import('../esm-fixtures/a-module.mjs') 35 | assert.deepEqual({ ...result1 }, { 36 | default: 'default-export', 37 | namedExport: 'named-export', 38 | life: 42 39 | }) 40 | 41 | await quibble.esm('../esm-fixtures/a-module.mjs', { 42 | namedExport: 'replacement', 43 | life: 41 44 | }, 'default-export-replacement') 45 | 46 | const result2 = await import('../esm-fixtures/a-module.mjs') 47 | assert.deepEqual({ ...result2 }, { 48 | default: 'default-export-replacement', 49 | namedExport: 'replacement', 50 | life: 41 51 | }) 52 | }, 53 | reset: async function () { 54 | await quibble.esm('../esm-fixtures/a-module.mjs', { 55 | namedExport: 'replacement', 56 | life: 41 57 | }, 'default-export-replacement') 58 | await import('../esm-fixtures/a-module.mjs') 59 | 60 | quibble.reset() 61 | 62 | const result = await import('../esm-fixtures/a-module.mjs') 63 | assert.deepEqual({ ...result }, { 64 | default: 'default-export', 65 | namedExport: 'named-export', 66 | life: 42 67 | }) 68 | }, 69 | 'remock a module after reset': async function () { 70 | await quibble.esm('../esm-fixtures/a-module.mjs', { 71 | namedExport: 'replacement', 72 | life: 41, 73 | namedFunctionExport: () => 'export replacement' 74 | }, 'default-export-replacement') 75 | 76 | await import('../esm-fixtures/a-module.mjs') 77 | quibble.reset() 78 | 79 | await quibble.esm('../esm-fixtures/a-module.mjs', { 80 | namedExport: 'replacement 2', 81 | life: 40 82 | }, 'default-export-replacement 2') 83 | const result = await import('../esm-fixtures/a-module.mjs') 84 | 85 | assert.deepEqual({ ...result }, { 86 | default: 'default-export-replacement 2', 87 | namedExport: 'replacement 2', 88 | life: 40 89 | }) 90 | }, 91 | 'mock two modules': async function () { 92 | await quibble.esm('../esm-fixtures/a-module.mjs', { a: 4 }, 'a-mock') 93 | 94 | await import('../esm-fixtures/b-module.mjs') 95 | 96 | await quibble.esm('../esm-fixtures/b-module.mjs', { a: 4 }, 'b-mock') 97 | 98 | assert.deepEqual((await import('../esm-fixtures/a-module.mjs')).default, 'a-mock') 99 | assert.deepEqual((await import('../esm-fixtures/b-module.mjs')).default, 'b-mock') 100 | }, 101 | 'mock a 3rd party lib': async function () { 102 | await quibble.esm('is-promise', undefined, () => 42) 103 | 104 | const { default: result } = await import('is-promise') 105 | assert.equal(result(), 42) 106 | }, 107 | 'isLoaderLoader returns true if loader as loaded': async function () { 108 | assert.equal(quibble.isLoaderLoaded(), true) 109 | }, 110 | 'mock a native module': async function () { 111 | await quibble.esm('fs', { 112 | async readFileSync () { 113 | return 42 114 | } 115 | }) 116 | 117 | const fs = await import('fs') 118 | 119 | assert.equal(await fs.readFileSync(), 42) 120 | }, 121 | 'quibble is never mocked': async function () { 122 | await quibble.esm('fs', { 123 | async readFileSync () { 124 | return 42 125 | } 126 | }) 127 | 128 | await import('quibble') 129 | 130 | const fs = await import('fs') 131 | 132 | assert.equal(await fs.readFileSync(), 42) 133 | }, 134 | 'namedExport will implicitly be converted to the "default" export': async function () { 135 | await quibble.esm('../esm-fixtures/a-module-with-function.mjs', { 136 | default: 'default-export-replacement', 137 | namedExport: 'replacement', 138 | life: 41, 139 | namedFunctionExport: () => 'export replacement' 140 | }) 141 | 142 | // This import is important, as it checks how quibble interacts with internal modules 143 | await import('util') 144 | 145 | const result = await import('../esm-fixtures/a-module-with-function.mjs') 146 | assert.equal(result.default, 'default-export-replacement') 147 | assert.equal(result.namedExport, 'replacement') 148 | assert.equal(result.life, 41) 149 | assert.equal(result.namedFunctionExport(), 'export replacement') 150 | }, 151 | 'a "default" named export stub along with a "default" export is a conflict and thus an error': 152 | async function () { 153 | await assertThrows(() => quibble.esm('../esm-fixtures/a-module-with-function.mjs', { 154 | default: 'default-export-replacement', 155 | namedExport: 'replacement', 156 | life: 41, 157 | namedFunctionExport: () => 'export replacement' 158 | }, 'conflict with the above named export') 159 | , "conflict between a named export with the name 'default'") 160 | }, 161 | 'ensure named exports is an object': async function () { 162 | await assertThrows(() => quibble.esm('../esm-fixtures/a-module.mjs', 163 | 'this should be an object') 164 | , 'namedExportsStub argument must be either a plain object') 165 | 166 | await assertThrows(() => quibble.esm('../esm-fixtures/a-module.mjs', 167 | ['this should be an object']) 168 | , 'namedExportsStub argument must be either a plain object') 169 | 170 | await assertThrows(() => quibble.esm('../esm-fixtures/a-module.mjs', 171 | function () { 'this should be an object' }) 172 | , 'namedExportsStub argument must be either a plain object') 173 | 174 | // Should still allow Proxy. 175 | await quibble.esm('../esm-fixtures/a-module.mjs', new Proxy({}, {})) 176 | }, 177 | 'list mocked modules': async function () { 178 | await quibble.esm('../esm-fixtures/a-module-with-function.mjs', { 179 | namedExport: 'replacement', 180 | life: 41, 181 | namedFunctionExport: () => 'export replacement' 182 | }, 'default-export-replacement') 183 | 184 | assert.deepEqual(quibble.listMockedModules(), [ 185 | pathToFileURL(quibble.absolutify('../esm-fixtures/a-module-with-function.mjs', __filename)).href 186 | ]) 187 | await quibble.esm('../esm-fixtures/a-module.mjs', { 188 | namedExport: 'replacement', 189 | life: 41, 190 | namedFunctionExport: () => 'export replacement' 191 | }, 'default-export-replacement') 192 | 193 | assert.deepEqual(quibble.listMockedModules(), [ 194 | pathToFileURL(quibble.absolutify('../esm-fixtures/a-module-with-function.mjs', __filename)).href, 195 | pathToFileURL(quibble.absolutify('../esm-fixtures/a-module.mjs', __filename)).href 196 | ]) 197 | 198 | quibble.reset() 199 | 200 | assert.deepEqual(quibble.listMockedModules(), []) 201 | } 202 | } 203 | 204 | async function assertThrows (asyncFunc, messageContained) { 205 | try { 206 | await asyncFunc() 207 | assert.fail(`function did not throw exception with ${messageContained}`) 208 | } catch (err) { 209 | assert.equal(err.message.includes(messageContained), true) 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /test/esm-lib/quibble.no-loader-test.js: -------------------------------------------------------------------------------- 1 | const quibble = require('quibble') 2 | 3 | module.exports = { 4 | 'throw exception on quibble.esm with no loader': async function () { 5 | await assertThrows(() => quibble.esm('../esm-fixtures/a-module.mjs'), 6 | 'quibble loader not loaded') 7 | }, 8 | 'throw exception on quibble.esmImportWithPath with no loader': async function () { 9 | await assertThrows(() => quibble.esmImportWithPath('../esm-fixtures/a-module.mjs'), 10 | 'quibble loader not loaded') 11 | }, 12 | 'isLoaderLoader returns false if no loader': async function () { 13 | assert.equal(quibble.isLoaderLoaded(), false) 14 | } 15 | } 16 | 17 | async function assertThrows (asyncFunc, messageContained) { 18 | try { 19 | asyncFunc() 20 | assert.fail(`function did not throw exception with ${messageContained}`) 21 | } catch (err) { 22 | assert.equal(err.message.includes(messageContained), true) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/esm-lib/quibble.no-loader-test.mjs: -------------------------------------------------------------------------------- 1 | import quibble from 'quibble' 2 | 3 | export default { 4 | 'isLoaderLoader returns false if no loader': async function () { 5 | assert.equal(quibble.isLoaderLoaded(), false) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/esm-lib/supports-auto-load.js: -------------------------------------------------------------------------------- 1 | const { canRegisterLoader } = require('../../lib/canRegisterLoader.js') 2 | 3 | if (process.argv[2] === 'not') { 4 | process.exit(!canRegisterLoader() ? 0 : 1) 5 | } 6 | process.exit(canRegisterLoader() ? 0 : 1) 7 | -------------------------------------------------------------------------------- /test/esm-lib/teenytest-proxy.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // This file is needed because of bugs in ESM in Node.js (around loaders): 4 | // https://github.com/nodejs/node/issues/33226 5 | // https://github.com/nodejs/node/issues/33303 6 | // 7 | // Once these bugs are solved, we can go back to running teenytest regularly for ESM tests 8 | 9 | require('../../node_modules/teenytest/bin/teenytest') 10 | -------------------------------------------------------------------------------- /test/fixtures/a-function.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return 'the real function' 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/a-function.json: -------------------------------------------------------------------------------- 1 | { 2 | "wups" : "lol" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/a-quibble-wrapper.js: -------------------------------------------------------------------------------- 1 | const quibble = require('../../lib/quibble') 2 | 3 | quibble.ignoreCallsFromThisFile() 4 | 5 | module.exports = function () { 6 | quibble.apply(this, arguments) 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/a-symlinked-function.js: -------------------------------------------------------------------------------- 1 | a-function.js -------------------------------------------------------------------------------- /test/fixtures/b-function.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return 'b function' 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/bomb.js: -------------------------------------------------------------------------------- 1 | throw new Error('a bomb') 2 | -------------------------------------------------------------------------------- /test/fixtures/expects-a-quibbling.js: -------------------------------------------------------------------------------- 1 | if (require('./requires-a-function')() !== 'loaded lol') { 2 | console.log('X - Fails to quibble with -r option') 3 | process.exit(1) 4 | } else { 5 | console.log('✔️ - Able to use quibble with -r option') 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/is-number/index.js: -------------------------------------------------------------------------------- 1 | // Fake dependency to test importing node_modules 2 | module.exports = function () { 3 | return false 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/is-number/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "is-number", 3 | "description": "Fake dependency to test importing node_modules", 4 | "version": "100.0.0", 5 | "files": [ 6 | "index.js" 7 | ], 8 | "main": "index.js" 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/quibbles-requires-a-function.js: -------------------------------------------------------------------------------- 1 | const quibble = require('../../lib/quibble') 2 | quibble('./a-function', function () { return 'lol' }) 3 | -------------------------------------------------------------------------------- /test/fixtures/requires-a-function.js: -------------------------------------------------------------------------------- 1 | const aFunction = require('./a-function') 2 | 3 | module.exports = function () { 4 | return 'loaded ' + aFunction() 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/requires-a-node-module.js: -------------------------------------------------------------------------------- 1 | // This should import the fake dependency in './node_modules/is-number' 2 | // not the real dependency in '../../node_modules/is-number' 3 | const isNumber = require('is-number') 4 | 5 | module.exports = function () { 6 | return isNumber(1) 7 | } 8 | -------------------------------------------------------------------------------- /test/helper.js: -------------------------------------------------------------------------------- 1 | global.assert = require('core-assert') 2 | 3 | // Just in case we lose track of it somewhere 4 | global.ORIGINAL_MODULE_LOAD = require('module')._load 5 | -------------------------------------------------------------------------------- /test/lib/a-module-spec.js: -------------------------------------------------------------------------------- 1 | const quibble = require('../../lib/quibble') 2 | const _ = require('lodash') 3 | 4 | module.exports = { 5 | 'un-quibbled': function () { 6 | const isNumber = require('is-number') 7 | 8 | assert.equal(isNumber(5), true) 9 | assert.equal(isNumber('pants'), false) 10 | }, 11 | 'quibbled to be opposite day': function () { 12 | const isNumberQuibbleReturn = quibble('is-number', function () { 13 | return !_.isNumber.apply(this, arguments) 14 | }) 15 | const isNumber = require('is-number') 16 | 17 | assert.equal(isNumber(5), false) 18 | assert.equal(isNumber('pants'), true) 19 | assert.equal(isNumberQuibbleReturn(5), false) 20 | assert.equal(isNumberQuibbleReturn('pants'), true) 21 | }, 22 | 'reset restores things': function () { 23 | quibble.reset() 24 | 25 | const isNumber = require('is-number') 26 | assert.equal(isNumber(5), true) 27 | assert.equal(isNumber('pants'), false) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/lib/a-quibble-wrapper-spec.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'something that wraps quibble': function () { 3 | const subject = require('../fixtures/a-quibble-wrapper') 4 | subject('./should-be-relative-to-test-slash-lib', 'neat') 5 | 6 | const result = require('./should-be-relative-to-test-slash-lib') 7 | 8 | assert.equal(result, 'neat') 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/lib/quibble.test.js: -------------------------------------------------------------------------------- 1 | const quibble = require('../../lib/quibble') 2 | const { pathToFileURL } = require('url') 3 | 4 | module.exports = { 5 | 'basic behavior': function () { 6 | const stubbing = quibble('../fixtures/a-function', function () { return 'kek' }) 7 | 8 | assert.equal(stubbing(), 'kek') 9 | assert.equal(require('../fixtures/a-function')(), 'kek') 10 | assert.equal(require('../fixtures/a-function')(), 'kek') 11 | assert.equal(require('../../test/fixtures/a-function')(), 'kek') 12 | assert.equal(require('../fixtures/b-function')(), 'b function') 13 | }, 14 | 'mismatched extensions': { 15 | 'resolves specific quibbling with resolve-compatible require': function () { 16 | quibble('../fixtures/a-function.js', function () { return 'woo' }) 17 | 18 | const result = require('../fixtures/a-function')() 19 | 20 | assert.equal(result, 'woo') 21 | }, 22 | 'resolves extensionless quibbling just as node itself would': function () { 23 | quibble('../fixtures/a-function', function () { return '!' }) 24 | 25 | assert.equal(require('../fixtures/a-function')(), '!') 26 | assert.equal(require('../fixtures/a-function.js')(), '!') 27 | assert.deepEqual(require('../fixtures/a-function.json'), { wups: 'lol' }) 28 | }, 29 | 'general->specific stubbing matches specific': function () { 30 | quibble('../fixtures/a-function', function () { return 'A' }) 31 | quibble('../fixtures/a-function.js', function () { return 'B' }) 32 | quibble('../fixtures/a-function.json', { C: true }) 33 | 34 | assert.equal(require('../fixtures/a-function')(), 'B') 35 | assert.equal(require('../fixtures/a-function.js')(), 'B') 36 | assert.deepEqual(require('../fixtures/a-function.json'), { C: true }) 37 | }, 38 | 'specific->general stubbing matches when node resolve does': function () { 39 | quibble('../fixtures/a-function.js', function () { return 'B' }) 40 | quibble('../fixtures/a-function.json', { C: true }) 41 | quibble('../fixtures/a-function', function () { return 'A' }) 42 | 43 | assert.equal(require('../fixtures/a-function')(), 'A') 44 | assert.equal(require('../fixtures/a-function.js')(), 'A') 45 | assert.deepEqual(require('../fixtures/a-function.json'), { C: true }) 46 | }, 47 | 'non-existant files need to be exact since resolve will ¯\\_(ツ)_/¯ ': function () { 48 | quibble('../fixtures/fake-file.js', function () { return 'B' }) 49 | quibble('../fixtures/fake-file.json', { C: true }) 50 | quibble('../fixtures/fake-file', function () { return 'A' }) 51 | 52 | assert.equal(require('../fixtures/fake-file')(), 'A') 53 | assert.equal(require('../fixtures/fake-file.js')(), 'B') 54 | assert.deepEqual(require('../fixtures/fake-file.json'), { C: true }) 55 | } 56 | }, 57 | 'last-in wins': function () { 58 | quibble('../fixtures/a-function', function () { return 'loser' }) 59 | quibble('../fixtures/a-function', function () { return 'loser!' }) 60 | quibble('../fixtures/a-function', function () { return 'winner' }) 61 | 62 | assert.equal(require('../fixtures/a-function')(), 'winner') 63 | }, 64 | 'works when file is not resolvable': function () { 65 | quibble('../fixtures/not-a-real-file', function () { return 'hi' }) 66 | 67 | assert.equal(require('../fixtures/not-a-real-file')(), 'hi') 68 | }, 69 | 'does not screw up symlinks': function () { 70 | quibble('../fixtures/a-symlinked-function', function () { return 'A' }) 71 | 72 | assert.equal(require('../fixtures/a-symlinked-function')(), 'A') 73 | assert.equal(require('../fixtures/a-function')(), 'the real function') 74 | }, 75 | '.config': { 76 | defaultFakeCreator: function () { 77 | quibble.config({ defaultFakeCreator: function () { return 'lol' } }) 78 | 79 | const stubbing = quibble('./lol') 80 | 81 | assert.equal(stubbing, 'lol') 82 | assert.equal(require('./lol'), 'lol') 83 | } 84 | }, 85 | '.reset': { 86 | 'ensure it clears its internal data structure of quibbles': function () { 87 | quibble('../fixtures/a-function', function () { return 'ha' }) 88 | assert.equal(require('../fixtures/requires-a-function')(), 'loaded ha') 89 | 90 | quibble.reset() 91 | 92 | assert.equal(require('../fixtures/a-function')(), 'the real function') 93 | assert.equal(require('../fixtures/requires-a-function')(), 'loaded the real function') 94 | }, 95 | 'can quibble again after reset': function () { 96 | quibble('../fixtures/a-function', function () { return 'ha' }) 97 | assert.equal(require('../fixtures/a-function')(), 'ha') 98 | assert.equal(require('../fixtures/requires-a-function')(), 'loaded ha') 99 | 100 | quibble.reset() 101 | 102 | quibble('./some-other-thing') 103 | assert.equal(require('../fixtures/a-function')(), 'the real function') 104 | quibble('../fixtures/a-function', function () { return 'ha2' }) 105 | assert.equal(require('../fixtures/requires-a-function')(), 'loaded ha2') 106 | }, 107 | 'without a reset': function () { 108 | quibble('../fixtures/a-function', function () { return 'ha' }) 109 | quibble('./some-other-thing') 110 | 111 | assert.equal(require('../fixtures/a-function')(), 'ha') 112 | } 113 | }, 114 | 'blowing the require cache': { 115 | 'requiring-an-already-cached-thing and then quibbling it': function () { 116 | require('../fixtures/requires-a-function') 117 | quibble('../fixtures/a-function', function () { return 'a fake function' }) 118 | const quibbledRequiresAFunction = require('../fixtures/requires-a-function') 119 | 120 | const result = quibbledRequiresAFunction() 121 | 122 | assert.equal(result, 'loaded a fake function') 123 | } 124 | }, 125 | 'requiring-a-node-module': function () { 126 | quibble('./some-other-thing') 127 | const quibbledRequiresANodeModule = require('../fixtures/requires-a-node-module') 128 | 129 | assert.equal(quibbledRequiresANodeModule(), false) 130 | }, 131 | 'list mocked modules': async function () { 132 | quibble('../fixtures/a-function', function () { return 'kek' }) 133 | 134 | assert.deepEqual(quibble.listMockedModules(), [ 135 | pathToFileURL(quibble.absolutify('../fixtures/a-function', __filename)).href 136 | ]) 137 | 138 | quibble('../fixtures/b-function', function () { return 'kek' }) 139 | 140 | assert.deepEqual(quibble.listMockedModules(), [ 141 | pathToFileURL(quibble.absolutify('../fixtures/a-function', __filename)).href, 142 | pathToFileURL(quibble.absolutify('../fixtures/b-function', __filename)).href 143 | ]) 144 | 145 | quibble.reset() 146 | 147 | assert.deepEqual(await quibble.listMockedModules(), []) 148 | }, 149 | afterEach: function () { 150 | quibble.reset() 151 | }, 152 | afterAll: function () { 153 | // Ensure we didn't just screw up the module._load function somehow 154 | assert.equal(require('module')._load, global.ORIGINAL_MODULE_LOAD) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /test/require-smell-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "test/fixtures" 6 | node -r "./quibbles-requires-a-function.js" "expects-a-quibbling.js" 7 | --------------------------------------------------------------------------------